diff --git a/DEPS b/DEPS
index b51d1c38..0f4f590 100644
--- a/DEPS
+++ b/DEPS
@@ -162,11 +162,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '6abaff3041a3eb140b82d091ef2aa35063b5c69c',
+  'skia_revision': 'c712e962b64742f18fc69620678297bee144ea9b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '87177fcba6dd1ac403023f850431fe8bdedba7d3',
+  'v8_revision': '121f6b791c3b0a6c6f6ae4c98b45746451320168',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -178,7 +178,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': 'cc3f098616852eb7520fc4fd695f6b7db8aa9b3a',
+  'swiftshader_revision': '2eae4389fbdf1914385106513973a00960b0e6e2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -225,7 +225,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '6730faf618f825994304332395b41c934d9de512',
+  'catapult_revision': 'e00ffeb79abcfd6cf7219358f556111b4e0f56a3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -233,7 +233,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-node-modules
   # and whatever else without interference from each other.
-  'devtools_node_modules_revision': '56245d8ba398ac98d39974c3552b25e30a60a1b9',
+  'devtools_node_modules_revision': '42d0028a8621347b04fa31462b33a32cd105d715',
   # 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.
@@ -297,7 +297,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '05be0ff348150eceafcdc89bed8526de60839414',
+  'dawn_revision': 'cf0e9d93f1775e75f17ad045c1e28d118f9fad1b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -1257,7 +1257,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '0c127f488fdbbbbf9190cad96c837d5f6a41717c',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '8adff0796b3103f21db1032b6a9eea9abcfea3ed',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1425,7 +1425,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '7c4e67ff117d6c640e6dd17989afe2fb7da7eecb',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '90d6efbd4eb4b3a0a6fc26da0bc2f04843865b3e',
+    Var('webrtc_git') + '/src.git' + '@' + 'd63f8f88a1b0bc5129f111b440ee294947ba98b1',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1487,7 +1487,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@f2723363e181b4c93f71ec246a448b72b1b5ce20',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@09aa96cf69bd07fa860f63717bf8706344cbe0c8',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/WATCHLISTS b/WATCHLISTS
index 5094afbf..c55f9e3 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -2322,7 +2322,7 @@
     'feature_policy': ['loonybear@chromium.org',
                        'iclelland+watch@chromium.org',
                        'jmedley+watch@chromium.org'],
-    'feedback': ['jkardatzke+watch@chromium.org'],
+    'feedback': ['cros-monitoring-forensics+feedback@google.com'],
     'fileapi': ['kinuko+fileapi@chromium.org',
                 'nhiroki@chromium.org'],
     'filebrowse': ['rginda+watch@chromium.org'],
@@ -2351,7 +2351,7 @@
     'guest_view': ['ekaramad@chromium.org',
                    'mcnee@chromium.org',
                    'wjmaclean@chromium.org'],
-    'hats': ['jkardatzke+watch@chromium.org'],
+    'hats': ['cros-monitoring-forensics+hats@google.com'],
     'headless': ['headless-reviews@chromium.org'],
     'history_ui': ['dbeam+watch-history-ui@chromium.org'],
     'i18n': ['jshin+watch@chromium.org'],
diff --git a/android_webview/java/src/org/chromium/android_webview/AwAutofillProvider.java b/android_webview/java/src/org/chromium/android_webview/AwAutofillProvider.java
index 4120745..1510c44 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwAutofillProvider.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwAutofillProvider.java
@@ -331,10 +331,12 @@
             // the position could be changed.
             int virtualId = mRequest.getVirtualId(sIndex);
             Rect absBound = transformToWindowBounds(new RectF(x, y, x + width, y + height));
-            mAutofillManager.notifyVirtualViewExited(mContainerView, virtualId);
-            mAutofillManager.notifyVirtualViewEntered(mContainerView, virtualId, absBound);
-            // Update focus field position.
-            mRequest.setFocusField(new FocusField(focusField.fieldIndex, absBound));
+            if (!focusField.absBound.equals(absBound)) {
+                mAutofillManager.notifyVirtualViewExited(mContainerView, virtualId);
+                mAutofillManager.notifyVirtualViewEntered(mContainerView, virtualId, absBound);
+                // Update focus field position.
+                mRequest.setFocusField(new FocusField(focusField.fieldIndex, absBound));
+            }
         }
         notifyVirtualValueChanged(index);
         mAutofillUMA.onUserChangeFieldValue(mRequest.getField(sIndex).hasPreviouslyAutofilled());
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 7fcba5e..5398f39 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
@@ -557,8 +557,7 @@
             mTest.dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_A);
             // Note that we currently call ENTER/EXIT one more time.
             mCnt += mTest.waitForCallbackAndVerifyTypes(mCnt,
-                    new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_VIEW_EXITED,
-                            AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
+                    new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
         }
 
         public void simulateUserSelectSuggestion() throws Throwable {
@@ -582,9 +581,8 @@
         public void simulateUserChangeAutofilledField() throws Throwable {
             mTest.executeJavaScriptAndWaitForResult("document.getElementById('text1').select();");
             mTest.dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_B);
-            mCnt += mTest.waitForCallbackAndVerifyTypes(mCnt,
-                    new Integer[] {
-                            AUTOFILL_VIEW_EXITED, AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
+            mCnt += mTest.waitForCallbackAndVerifyTypes(
+                    mCnt, new Integer[] {AUTOFILL_VALUE_CHANGED});
         }
 
         public void submitForm() throws Throwable {
@@ -606,9 +604,8 @@
         public void simulateUserChangeField() throws Throwable {
             mTest.executeJavaScriptAndWaitForResult("document.getElementById('text1').select();");
             mTest.dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_B);
-            mCnt += mTest.waitForCallbackAndVerifyTypes(mCnt,
-                    new Integer[] {
-                            AUTOFILL_VIEW_EXITED, AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
+            mCnt += mTest.waitForCallbackAndVerifyTypes(
+                    mCnt, new Integer[] {AUTOFILL_VALUE_CHANGED});
         }
 
         private void initDeltaSamples() {
@@ -780,10 +777,7 @@
             cnt += waitForCallbackAndVerifyTypes(
                     cnt, new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED});
             dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_A);
-            // Note that we currently call ENTER/EXIT one more time.
-            waitForCallbackAndVerifyTypes(cnt,
-                    new Integer[] {
-                            AUTOFILL_VIEW_EXITED, AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
+            waitForCallbackAndVerifyTypes(cnt, new Integer[] {AUTOFILL_VALUE_CHANGED});
 
             executeJavaScriptAndWaitForResult("document.getElementById('text1').blur();");
             waitForCallbackAndVerifyTypes(cnt, new Integer[] {AUTOFILL_VIEW_EXITED});
@@ -819,10 +813,8 @@
             loadUrlSync(url);
             executeJavaScriptAndWaitForResult("document.getElementById('text1').select();");
             dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_A);
-            // Note that we currently call ENTER/EXIT one more time.
             cnt += waitForCallbackAndVerifyTypes(cnt,
-                    new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_VIEW_EXITED,
-                            AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
+                    new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
             invokeOnProvideAutoFillVirtualStructure();
             TestViewStructure viewStructure = mTestValues.testViewStructure;
             assertNotNull(viewStructure);
@@ -938,10 +930,8 @@
             executeJavaScriptAndWaitForResult("document.getElementById('text1').select();");
             dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_A);
 
-            // Note that we currently call ENTER/EXIT one more time.
             cnt += waitForCallbackAndVerifyTypes(cnt,
-                    new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_VIEW_EXITED,
-                            AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
+                    new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
             ArrayList<Pair<Integer, AutofillValue>> values = getChangedValues();
             // Check if NotifyVirtualValueChanged() called and value is 'a'.
             assertEquals(1, values.size());
@@ -951,9 +941,7 @@
 
             // Check if NotifyVirtualValueChanged() called again, first value is 'a',
             // second value is 'ab', and both time has the same id.
-            waitForCallbackAndVerifyTypes(cnt,
-                    new Integer[] {
-                            AUTOFILL_VIEW_EXITED, AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
+            waitForCallbackAndVerifyTypes(cnt, new Integer[] {AUTOFILL_VALUE_CHANGED});
             values = getChangedValues();
             assertEquals(2, values.size());
             assertEquals("a", values.get(0).second.getTextValue());
@@ -979,10 +967,8 @@
             int cnt = 0;
             executeJavaScriptAndWaitForResult("document.getElementById('text1').select();");
             dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_A);
-            // Note that we currently call ENTER/EXIT one more time.
             cnt += waitForCallbackAndVerifyTypes(cnt,
-                    new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_VIEW_EXITED,
-                            AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
+                    new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
             ArrayList<Pair<Integer, AutofillValue>> values = getChangedValues();
             // Check if NotifyVirtualValueChanged() called and value is 'a'.
             assertEquals(1, values.size());
@@ -990,16 +976,14 @@
             executeJavaScriptAndWaitForResult("document.getElementById('text1').value='c';");
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                 // There is no AUTOFILL_CANCEL from Android P.
-                assertEquals(4, getCallbackCount());
+                assertEquals(2, getCallbackCount());
             } else {
-                assertEquals(5, getCallbackCount());
+                assertEquals(3, getCallbackCount());
             }
             dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_B);
             // Check if NotifyVirtualValueChanged() called one more time and value is 'cb', this
             // means javascript change didn't trigger the NotifyVirtualValueChanged().
-            waitForCallbackAndVerifyTypes(cnt,
-                    new Integer[] {
-                            AUTOFILL_VIEW_EXITED, AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
+            waitForCallbackAndVerifyTypes(cnt, new Integer[] {AUTOFILL_VALUE_CHANGED});
             values = getChangedValues();
             assertEquals(2, values.size());
             assertEquals("a", values.get(0).second.getTextValue());
@@ -1028,10 +1012,8 @@
             int cnt = 0;
             executeJavaScriptAndWaitForResult("document.getElementById('text1').select();");
             dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_A);
-            // Note that we currently call ENTER/EXIT one more time.
             cnt += waitForCallbackAndVerifyTypes(cnt,
-                    new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_VIEW_EXITED,
-                            AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
+                    new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
             invokeOnProvideAutoFillVirtualStructure();
             // Fill the password.
             executeJavaScriptAndWaitForResult("document.getElementById('passwordid').select();");
@@ -1039,9 +1021,7 @@
                     new Integer[] {
                             AUTOFILL_VIEW_EXITED, AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
             dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_B);
-            cnt += waitForCallbackAndVerifyTypes(cnt,
-                    new Integer[] {
-                            AUTOFILL_VIEW_EXITED, AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
+            cnt += waitForCallbackAndVerifyTypes(cnt, new Integer[] {AUTOFILL_VALUE_CHANGED});
             clearChangedValues();
             // Submit form.
             executeJavaScriptAndWaitForResult("document.getElementById('formid').submit();");
@@ -1067,10 +1047,8 @@
         executeJavaScriptAndWaitForResult("document.getElementById('text1').select();");
         dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_A);
         // Cancel called for the first query.
-        // Note that we currently call ENTER/EXIT one more time.
         waitForCallbackAndVerifyTypes(cnt,
-                new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_VIEW_EXITED,
-                        AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
+                new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
     }
 
     @Test
@@ -1094,10 +1072,8 @@
             loadUrlSync(url);
             executeJavaScriptAndWaitForResult("document.getElementById('text1').select();");
             dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_A);
-            // Note that we currently call ENTER/EXIT one more time.
             cnt += waitForCallbackAndVerifyTypes(cnt,
-                    new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_VIEW_EXITED,
-                            AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
+                    new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
             // Move to form2, cancel() should be called again.
             executeJavaScriptAndWaitForResult("document.getElementById('text2').select();");
             dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_A);
@@ -1164,8 +1140,7 @@
             dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_A);
             // Verify autofill session triggered.
             count += waitForCallbackAndVerifyTypes(count,
-                    new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_VIEW_EXITED,
-                            AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
+                    new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
             // Verify focus is in iframe.
             assertEquals("true",
                     executeJavaScriptAndWaitForResult(
@@ -1177,7 +1152,7 @@
             // The new session starts because cancel() has been called.
             waitForCallbackAndVerifyTypes(count,
                     new Integer[] {AUTOFILL_VIEW_EXITED, AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED,
-                            AUTOFILL_VIEW_EXITED, AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
+                            AUTOFILL_VALUE_CHANGED});
             ArrayList<Pair<Integer, AutofillValue>> values = getChangedValues();
             assertEquals(1, values.size());
             assertEquals("a", values.get(0).second.getTextValue());
@@ -1249,10 +1224,8 @@
             loadUrlSync(url);
             executeJavaScriptAndWaitForResult("document.getElementById('text1').select();");
             dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_A);
-            // Note that we currently call ENTER/EXIT one more time.
             cnt += waitForCallbackAndVerifyTypes(cnt,
-                    new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_VIEW_EXITED,
-                            AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
+                    new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
             executeJavaScriptAndWaitForResult("window.location.href = 'success.html'; ");
             waitForCallbackAndVerifyTypes(cnt,
                     new Integer[] {
@@ -1322,8 +1295,7 @@
             executeJavaScriptAndWaitForResult("document.getElementById('text1').select();");
             dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_A);
             cnt += waitForCallbackAndVerifyTypes(cnt,
-                    new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_VIEW_EXITED,
-                            AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
+                    new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
             clearChangedValues();
             executeJavaScriptAndWaitForResult("document.getElementById('color').focus();");
             dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_CENTER);
@@ -1365,8 +1337,7 @@
             // Use key B to select 'blue'.
             dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_B);
             cnt += waitForCallbackAndVerifyTypes(cnt,
-                    new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_VIEW_EXITED,
-                            AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
+                    new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
             ArrayList<Pair<Integer, AutofillValue>> values = getChangedValues();
             assertEquals(1, values.size());
             assertTrue(values.get(0).second.isList());
@@ -1402,8 +1373,7 @@
             // Change select control first shall start autofill session.
             dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_CENTER);
             cnt += waitForCallbackAndVerifyTypes(cnt,
-                    new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_VIEW_EXITED,
-                            AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
+                    new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
             ArrayList<Pair<Integer, AutofillValue>> values = getChangedValues();
             assertEquals(1, values.size());
             assertTrue(values.get(0).second.isList());
@@ -1444,8 +1414,7 @@
             // work.
             dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_CENTER);
             cnt += waitForCallbackAndVerifyTypes(cnt,
-                    new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_VIEW_EXITED,
-                            AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
+                    new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
             ArrayList<Pair<Integer, AutofillValue>> values = getChangedValues();
             assertEquals(1, values.size());
             assertTrue(values.get(0).second.isList());
@@ -1481,10 +1450,8 @@
             loadUrlSync(url);
             executeJavaScriptAndWaitForResult("document.getElementById('frmAddressB').select();");
             dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_A);
-            // Note that we currently call ENTER/EXIT one more time.
             cnt += waitForCallbackAndVerifyTypes(cnt,
-                    new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_VIEW_EXITED,
-                            AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
+                    new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
             invokeOnProvideAutoFillVirtualStructure();
             TestViewStructure viewStructure = mTestValues.testViewStructure;
             assertNotNull(viewStructure);
@@ -1839,6 +1806,45 @@
         mUMATestHelper.verifyWebViewCreatedByActivityContext();
     }
 
+    @Test
+    @SmallTest
+    @Feature({"AndroidWebView"})
+    public void testPageScrollTriggerViewExitAndEnter() throws Throwable {
+        TestWebServer webServer = TestWebServer.start();
+        final String data = "<html><head></head><body><form action='a.html' name='formname'>"
+                + "<input type='text' id='text1' name='username'"
+                + " placeholder='placeholder@placeholder.com' autocomplete='username name'>"
+                + "</form><p style='height: 100vh'>Hello</p></body></html>";
+        try {
+            final String url = webServer.setResponse(FILE, data, null);
+            loadUrlSync(url);
+            int cnt = 0;
+            executeJavaScriptAndWaitForResult("document.getElementById('text1').select();");
+            dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_A);
+
+            cnt += waitForCallbackAndVerifyTypes(cnt,
+                    new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
+
+            // Moved view, the position change trigger additional AUTOFILL_VIEW_EXITED and
+            // AUTOFILL_VIEW_ENTERED.
+            scrollToBottom();
+            dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_B);
+
+            // Check if NotifyVirtualValueChanged() called again and with extra AUTOFILL_VIEW_EXITED
+            // and AUTOFILL_VIEW_ENTERED
+            waitForCallbackAndVerifyTypes(cnt,
+                    new Integer[] {
+                            AUTOFILL_VIEW_EXITED, AUTOFILL_VIEW_ENTERED, AUTOFILL_VALUE_CHANGED});
+        } finally {
+            webServer.shutdown();
+        }
+    }
+
+    private void scrollToBottom() {
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> { mTestContainerView.scrollTo(0, mTestContainerView.getHeight()); });
+    }
+
     private void loadUrlSync(String url) throws Exception {
         mRule.loadUrlSync(
                 mTestContainerView.getAwContents(), mContentsClient.getOnPageFinishedHelper(), url);
diff --git a/ash/accessibility/accessibility_controller_impl.cc b/ash/accessibility/accessibility_controller_impl.cc
index b46853a..ca5b347 100644
--- a/ash/accessibility/accessibility_controller_impl.cc
+++ b/ash/accessibility/accessibility_controller_impl.cc
@@ -882,6 +882,7 @@
   base::RecordAction(base::UserMetricsAction("Accel_Toggle_Dictation"));
   UserMetricsRecorder::RecordUserToggleDictation(source);
 
+  SetDictationEnabled(true);
   ToggleDictation();
 }
 
diff --git a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
index bbec2518..e1a6717ae 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
+++ b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
@@ -1677,7 +1677,8 @@
 
 // Regression test for screenshot staying visible when entering tablet mode when
 // already in overview mode. See https://crbug.com/1002735.
-TEST_F(TabletModeControllerScreenshotTest, FromOverviewNoScreenshot) {
+// Flaky in remote builds, see: crbug.com/1007961
+TEST_F(TabletModeControllerScreenshotTest, DISABLED_FromOverviewNoScreenshot) {
   // Create two maximized windows.
   auto window = CreateTestWindow(gfx::Rect(200, 200));
   auto window2 = CreateTestWindow(gfx::Rect(200, 200));
diff --git a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
index abef77b..9d75b06 100644
--- a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
+++ b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
@@ -51,6 +51,7 @@
 import androidx.annotation.Nullable;
 
 import org.chromium.base.annotations.VerifiesOnLollipop;
+import org.chromium.base.annotations.VerifiesOnN;
 
 import java.io.UnsupportedEncodingException;
 
@@ -136,7 +137,7 @@
      * @see android.text.Html#toHtml(Spanned, int)
      * @param option is ignored on below N
      */
-    @SuppressWarnings("deprecation")
+    @VerifiesOnN
     public static String toHtml(Spanned spanned, int option) {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
             return Html.toHtml(spanned, option);
diff --git a/base/android/java/src/org/chromium/base/compat/ApiHelperForO.java b/base/android/java/src/org/chromium/base/compat/ApiHelperForO.java
index f97dded..769a8ee 100644
--- a/base/android/java/src/org/chromium/base/compat/ApiHelperForO.java
+++ b/base/android/java/src/org/chromium/base/compat/ApiHelperForO.java
@@ -5,6 +5,7 @@
 package org.chromium.base.compat;
 
 import android.annotation.TargetApi;
+import android.content.ClipDescription;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.os.Build;
@@ -42,4 +43,9 @@
     public static void setDefaultFocusHighlightEnabled(View view, boolean enabled) {
         view.setDefaultFocusHighlightEnabled(enabled);
     }
+
+    /** See {@link ClipDescription#getTimestamp()}. */
+    public static long getTimestamp(ClipDescription clipDescription) {
+        return clipDescription.getTimestamp();
+    }
 }
diff --git a/base/task/task_executor.cc b/base/task/task_executor.cc
index 8b527b0..0bb8651 100644
--- a/base/task/task_executor.cc
+++ b/base/task/task_executor.cc
@@ -6,8 +6,10 @@
 
 #include <type_traits>
 
+#include "base/no_destructor.h"
 #include "base/task/task_traits.h"
 #include "base/task/task_traits_extension.h"
+#include "base/threading/thread_local.h"
 
 namespace base {
 
@@ -30,6 +32,21 @@
 
 }  // namespace
 
+ThreadLocalPointer<TaskExecutor>* GetTLSForCurrentTaskExecutor() {
+  static NoDestructor<ThreadLocalPointer<TaskExecutor>> instance;
+  return instance.get();
+}
+
+void SetTaskExecutorForCurrentThread(TaskExecutor* task_executor) {
+  DCHECK(!task_executor || !GetTLSForCurrentTaskExecutor()->Get() ||
+         GetTLSForCurrentTaskExecutor()->Get() == task_executor);
+  GetTLSForCurrentTaskExecutor()->Set(task_executor);
+}
+
+TaskExecutor* GetTaskExecutorForCurrentThread() {
+  return GetTLSForCurrentTaskExecutor()->Get();
+}
+
 void RegisterTaskExecutor(uint8_t extension_id, TaskExecutor* task_executor) {
   DCHECK_NE(extension_id, TaskTraitsExtensionStorage::kInvalidExtensionId);
   DCHECK_LE(extension_id, TaskTraitsExtensionStorage::kMaxExtensionId);
diff --git a/base/task/task_executor.h b/base/task/task_executor.h
index b4e79e14..a062fdc 100644
--- a/base/task/task_executor.h
+++ b/base/task/task_executor.h
@@ -74,6 +74,13 @@
                                       TaskExecutor* task_executor);
 void BASE_EXPORT UnregisterTaskExecutorForTesting(uint8_t extension_id);
 
+// Stores the provided TaskExecutor in TLS for the current thread, to be used by
+// tasks with the CurrentThread() trait.
+void BASE_EXPORT SetTaskExecutorForCurrentThread(TaskExecutor* task_executor);
+
+// Returns the task executor registered for the current thread.
+BASE_EXPORT TaskExecutor* GetTaskExecutorForCurrentThread();
+
 // Determines whether a registered TaskExecutor will handle tasks with the given
 // |traits| and, if so, returns a pointer to it. Otherwise, returns |nullptr|.
 TaskExecutor* GetRegisteredTaskExecutorForTraits(const TaskTraits& traits);
diff --git a/cc/input/input_handler.h b/cc/input/input_handler.h
index e7794a5b..f39e006 100644
--- a/cc/input/input_handler.h
+++ b/cc/input/input_handler.h
@@ -198,8 +198,8 @@
 
   virtual InputHandlerPointerResult MouseMoveAt(
       const gfx::Point& mouse_position) = 0;
-  virtual InputHandlerPointerResult MouseDown(
-      const gfx::PointF& mouse_position) = 0;
+  virtual InputHandlerPointerResult MouseDown(const gfx::PointF& mouse_position,
+                                              bool shift_modifier) = 0;
   virtual InputHandlerPointerResult MouseUp(
       const gfx::PointF& mouse_position) = 0;
   virtual void MouseLeave() = 0;
diff --git a/cc/input/scrollbar_controller.cc b/cc/input/scrollbar_controller.cc
index 517c493..9231182 100644
--- a/cc/input/scrollbar_controller.cc
+++ b/cc/input/scrollbar_controller.cc
@@ -53,7 +53,8 @@
 // Performs hit test and prepares scroll deltas that will be used by GSB and
 // GSU.
 InputHandlerPointerResult ScrollbarController::HandlePointerDown(
-    const gfx::PointF position_in_widget) {
+    const gfx::PointF position_in_widget,
+    bool shift_modifier) {
   LayerImpl* layer_impl = GetLayerHitByPoint(position_in_widget);
 
   // If a non-custom scrollbar layer was not found, we return early as there is
@@ -73,19 +74,13 @@
   const ScrollbarPart scrollbar_part =
       GetScrollbarPartFromPointerDown(position_in_widget);
   scroll_result.scroll_offset = GetScrollOffsetForScrollbarPart(
-      scrollbar_part, currently_captured_scrollbar_->orientation());
+      scrollbar_part, currently_captured_scrollbar_->orientation(),
+      shift_modifier);
   last_known_pointer_position_ = position_in_widget;
   scrollbar_scroll_is_active_ = true;
-  if (scrollbar_part == ScrollbarPart::THUMB) {
-    scroll_result.scroll_units =
-        ui::input_types::ScrollGranularity::kScrollByPrecisePixel;
+  if (scrollbar_part == ScrollbarPart::THUMB)
     drag_anchor_relative_to_thumb_ = GetThumbRelativePoint(position_in_widget);
-  } else {
-    // TODO(arakeri): This needs to be updated to kLine once cc implements
-    // handling it. crbug.com/959441
-    scroll_result.scroll_units =
-        ui::input_types::ScrollGranularity::kScrollByPixel;
-  }
+  scroll_result.scroll_units = Granularity(scrollbar_part, shift_modifier);
 
   if (!scroll_result.scroll_offset.IsZero()) {
     // Thumb drag is the only scrollbar manipulation that cannot produce an
@@ -108,6 +103,54 @@
   return scroll_result;
 }
 
+ui::input_types::ScrollGranularity ScrollbarController::Granularity(
+    const ScrollbarPart scrollbar_part,
+    const bool shift_modifier) {
+  const bool shift_click_on_scrollbar_track =
+      shift_modifier && (scrollbar_part == ScrollbarPart::FORWARD_TRACK ||
+                         scrollbar_part == ScrollbarPart::BACK_TRACK);
+  if (shift_click_on_scrollbar_track || scrollbar_part == ScrollbarPart::THUMB)
+    return ui::input_types::ScrollGranularity::kScrollByPrecisePixel;
+
+  // TODO(arakeri): This needs to be updated to kLine once cc implements
+  // handling it. crbug.com/959441
+  return ui::input_types::ScrollGranularity::kScrollByPixel;
+}
+
+float ScrollbarController::GetScrollDeltaForShiftClick() {
+  layer_tree_host_impl_->active_tree()->UpdateScrollbarGeometries();
+
+  bool clipped = false;
+  const gfx::PointF pointer_position_in_layer =
+      GetScrollbarRelativePosition(last_known_pointer_position_, &clipped);
+
+  if (clipped)
+    return 0;
+
+  const ScrollbarOrientation orientation =
+      currently_captured_scrollbar_->orientation();
+  const float pointer_location = orientation == ScrollbarOrientation::VERTICAL
+                                     ? pointer_position_in_layer.y()
+                                     : pointer_position_in_layer.x();
+
+  // During a shift + click, the pointers current location (on the track) needs
+  // to be considered as the center of the thumb and the thumb origin needs to
+  // be calculated based on that. This will ensure that when shift + click is
+  // processed, the thumb will be centered on the pointer.
+  const int thumb_length = currently_captured_scrollbar_->ThumbLength();
+  const float desired_thumb_origin = pointer_location - thumb_length / 2.f;
+
+  const gfx::Rect thumb_rect(
+      currently_captured_scrollbar_->ComputeThumbQuadRect());
+  const float current_thumb_origin =
+      orientation == ScrollbarOrientation::VERTICAL ? thumb_rect.y()
+                                                    : thumb_rect.x();
+
+  const float delta =
+      round(std::abs(desired_thumb_origin - current_thumb_origin));
+  return delta * GetScrollerToScrollbarRatio();
+}
+
 gfx::ScrollOffset ScrollbarController::GetScrollOffsetForDragPosition(
     const gfx::PointF pointer_position_in_widget) {
   layer_tree_host_impl_->active_tree()->UpdateScrollbarGeometries();
@@ -141,7 +184,7 @@
 }
 
 // Performs hit test and prepares scroll deltas that will be used by GSU.
-InputHandlerPointerResult ScrollbarController::HandleMouseMove(
+InputHandlerPointerResult ScrollbarController::HandlePointerMove(
     const gfx::PointF position_in_widget) {
   last_known_pointer_position_ = position_in_widget;
   RecomputeAutoscrollStateIfNeeded();
@@ -437,7 +480,8 @@
 }
 
 int ScrollbarController::GetScrollDeltaForScrollbarPart(
-    ScrollbarPart scrollbar_part) {
+    const ScrollbarPart scrollbar_part,
+    const bool shift_modifier) {
   int scroll_delta = 0;
   int viewport_length = 0;
   LayerImpl* owner_scroll_layer = nullptr;
@@ -449,6 +493,10 @@
       break;
     case ScrollbarPart::BACK_TRACK:
     case ScrollbarPart::FORWARD_TRACK:
+      if (shift_modifier) {
+        scroll_delta = GetScrollDeltaForShiftClick();
+        break;
+      }
       owner_scroll_layer =
           layer_tree_host_impl_->active_tree()->ScrollableLayerByElementId(
               currently_captured_scrollbar_->scroll_element_id());
@@ -514,8 +562,10 @@
 // orientation.
 gfx::ScrollOffset ScrollbarController::GetScrollOffsetForScrollbarPart(
     const ScrollbarPart scrollbar_part,
-    const ScrollbarOrientation orientation) {
-  float scroll_delta = GetScrollDeltaForScrollbarPart(scrollbar_part);
+    const ScrollbarOrientation orientation,
+    const bool shift_modifier) {
+  float scroll_delta =
+      GetScrollDeltaForScrollbarPart(scrollbar_part, shift_modifier);
 
   // See CreateScrollStateForGesture for more information on how these values
   // will be interpreted.
diff --git a/cc/input/scrollbar_controller.h b/cc/input/scrollbar_controller.h
index eb7c43b..365e924 100644
--- a/cc/input/scrollbar_controller.h
+++ b/cc/input/scrollbar_controller.h
@@ -20,8 +20,9 @@
   virtual ~ScrollbarController();
 
   InputHandlerPointerResult HandlePointerDown(
-      const gfx::PointF position_in_widget);
-  InputHandlerPointerResult HandleMouseMove(
+      const gfx::PointF position_in_widget,
+      const bool shift_modifier);
+  InputHandlerPointerResult HandlePointerMove(
       const gfx::PointF position_in_widget);
   InputHandlerPointerResult HandlePointerUp(
       const gfx::PointF position_in_widget);
@@ -73,13 +74,15 @@
   // Returns scroll offsets based on which ScrollbarPart was hit tested.
   gfx::ScrollOffset GetScrollOffsetForScrollbarPart(
       const ScrollbarPart scrollbar_part,
-      const ScrollbarOrientation orientation);
+      const ScrollbarOrientation orientation,
+      const bool shift_modifier);
 
   // Returns the rect for the ScrollbarPart.
   gfx::Rect GetRectForScrollbarPart(const ScrollbarPart scrollbar_part);
 
   LayerImpl* GetLayerHitByPoint(const gfx::PointF position_in_widget);
-  int GetScrollDeltaForScrollbarPart(ScrollbarPart scrollbar_part);
+  int GetScrollDeltaForScrollbarPart(const ScrollbarPart scrollbar_part,
+                                     const bool shift_modifier);
 
   // Makes position_in_widget relative to the scrollbar.
   gfx::PointF GetScrollbarRelativePosition(const gfx::PointF position_in_widget,
@@ -90,6 +93,14 @@
   // bounds.
   void RecomputeAutoscrollStateIfNeeded();
 
+  // Shift + click is expected to do a non-animated jump to a certain offset.
+  float GetScrollDeltaForShiftClick();
+
+  // Determines if the delta needs to be animated.
+  ui::input_types::ScrollGranularity Granularity(
+      const ScrollbarPart scrollbar_part,
+      bool shift_modifier);
+
   // Calculates the scroll_offset based on position_in_widget and
   // drag_anchor_relative_to_thumb_.
   gfx::ScrollOffset GetScrollOffsetForDragPosition(
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 0fa59ab..8e90324b 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -4946,7 +4946,8 @@
 }
 
 InputHandlerPointerResult LayerTreeHostImpl::MouseDown(
-    const gfx::PointF& viewport_point) {
+    const gfx::PointF& viewport_point,
+    bool shift_modifier) {
   ScrollbarAnimationController* animation_controller =
       ScrollbarAnimationControllerForElementId(
           scroll_element_id_mouse_currently_over_);
@@ -4957,8 +4958,10 @@
   }
 
   InputHandlerPointerResult result;
-  if (settings().compositor_threaded_scrollbar_scrolling)
-    result = scrollbar_controller_->HandlePointerDown(viewport_point);
+  if (settings().compositor_threaded_scrollbar_scrolling) {
+    result = scrollbar_controller_->HandlePointerDown(viewport_point,
+                                                      shift_modifier);
+  }
 
   return result;
 }
@@ -4986,9 +4989,10 @@
 InputHandlerPointerResult LayerTreeHostImpl::MouseMoveAt(
     const gfx::Point& viewport_point) {
   InputHandlerPointerResult result;
-  if (settings().compositor_threaded_scrollbar_scrolling)
+  if (settings().compositor_threaded_scrollbar_scrolling) {
     result =
-        scrollbar_controller_->HandleMouseMove(gfx::PointF(viewport_point));
+        scrollbar_controller_->HandlePointerMove(gfx::PointF(viewport_point));
+  }
 
   // Early out if there are no animation controllers and avoid the hit test.
   // This happens on platforms without animated scrollbars.
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 514f6a7..e2935b0 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -278,8 +278,8 @@
       const gfx::ScrollOffset& root_content_offset) override;
   void ScrollEnd(ScrollState* scroll_state, bool should_snap = false) override;
 
-  InputHandlerPointerResult MouseDown(
-      const gfx::PointF& viewport_point) override;
+  InputHandlerPointerResult MouseDown(const gfx::PointF& viewport_point,
+                                      bool shift_modifier) override;
   InputHandlerPointerResult MouseUp(const gfx::PointF& viewport_point) override;
   InputHandlerPointerResult MouseMoveAt(
       const gfx::Point& viewport_point) override;
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index fe090fca..d9537f1b 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -10964,7 +10964,7 @@
 
   // MouseDown on the thumb should not produce a scroll.
   InputHandlerPointerResult result =
-      host_impl_->MouseDown(gfx::PointF(350, 18));
+      host_impl_->MouseDown(gfx::PointF(350, 18), /*shift_modifier*/ false);
   EXPECT_EQ(result.scroll_offset.y(), 0u);
 
   // The first request for a GSU should be processed as expected.
@@ -12450,7 +12450,7 @@
   animation_task_.Reset();
 
   // Only the MouseMove's location will affect the overlay scrollbar.
-  host_impl_->MouseDown(gfx::PointF(60, 50));
+  host_impl_->MouseDown(gfx::PointF(60, 50), /*shift_modifier*/ false);
   host_impl_->MouseMoveAt(gfx::Point(60, 50));
   host_impl_->MouseUp(gfx::PointF(60, 50));
 
@@ -12461,14 +12461,14 @@
   host_impl_->MouseMoveAt(gfx::Point(40, 150));
   animation_task_.Reset();
 
-  host_impl_->MouseDown(gfx::PointF(40, 150));
+  host_impl_->MouseDown(gfx::PointF(40, 150), /*shift_modifier*/ false);
   host_impl_->MouseUp(gfx::PointF(40, 150));
   EXPECT_TRUE(animation_task_.is_null());
 
   // Near scrollbar_1, then mouse down and unregister
   // scrollbar_2_animation_controller, then mouse up should not cause crash.
   host_impl_->MouseMoveAt(gfx::Point(40, 150));
-  host_impl_->MouseDown(gfx::PointF(40, 150));
+  host_impl_->MouseDown(gfx::PointF(40, 150), /*shift_modifier*/ false);
   host_impl_->UnregisterScrollbarAnimationController(root_scroll->element_id());
   host_impl_->MouseUp(gfx::PointF(40, 150));
 }
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 31340e35..f502bdc 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -282,7 +282,6 @@
     "//chrome/browser/ui/android/widget:java",
     "//chrome/browser/util/android:java",
     "//chrome/lib/lifecycle/public/android:java",
-    "//chrome/lib/util/public/android:java",
     "//components/autofill/android:autofill_java",
     "//components/autofill_assistant/browser:proto_java",
     "//components/background_task_scheduler:background_task_scheduler_java",
@@ -537,7 +536,7 @@
     "//chrome/android/public/profiles:jni_headers",
     "//chrome/browser/image_fetcher:jni_headers",
     "//chrome/browser/touch_to_fill/android:jni_headers",
-    "//chrome/lib/util/public/android:jni_headers",
+    "//chrome/browser/util/android:jni_headers",
   ]
 }
 
@@ -817,7 +816,6 @@
     "//chrome/browser/android/metrics:ukm_utils_java",
     "//chrome/browser/ui/android/widget:java",
     "//chrome/browser/util/android:java",
-    "//chrome/lib/util/public/android:java",
     "//chrome/test/android:chrome_java_test_support",
     "//chrome/test/android/test_trusted_web_activity:test_trusted_web_activity_java",
     "//components/autofill/android:autofill_java",
@@ -973,7 +971,6 @@
     "//chrome/android:chrome_java",
     "//chrome/android/features/vr:java",
     "//chrome/browser/util/android:java",
-    "//chrome/lib/util/public/android:java",
     "//chrome/test/android:chrome_java_test_support",
     "//components/policy/android:policy_java",
     "//content/public/android:content_java",
diff --git a/chrome/android/features/keyboard_accessory/internal/BUILD.gn b/chrome/android/features/keyboard_accessory/internal/BUILD.gn
index e21c53c..07f5d1c 100644
--- a/chrome/android/features/keyboard_accessory/internal/BUILD.gn
+++ b/chrome/android/features/keyboard_accessory/internal/BUILD.gn
@@ -16,7 +16,7 @@
     "//chrome/android:chrome_public_java",
     "//chrome/android/features/keyboard_accessory/public:public_java",
     "//chrome/android/public/profiles:java",
-    "//chrome/lib/util/public/android:java",
+    "//chrome/browser/util/android:java",
     "//components/autofill/android:autofill_java",
     "//components/feature_engagement/public:public_java",
     "//content/public/android:content_java",
diff --git a/chrome/android/features/tab_ui/BUILD.gn b/chrome/android/features/tab_ui/BUILD.gn
index 4a3b277..5e96fb6f 100644
--- a/chrome/android/features/tab_ui/BUILD.gn
+++ b/chrome/android/features/tab_ui/BUILD.gn
@@ -150,8 +150,8 @@
     "//chrome/android/public/profiles:java",
     "//chrome/app:java_strings_grd",
     "//chrome/browser/ui/android/widget:java",
+    "//chrome/browser/util/android:java",
     "//chrome/lib/lifecycle/public/android:java",
-    "//chrome/lib/util/public/android:java",
     "//components/embedder_support/android:web_contents_delegate_java",
     "//components/feature_engagement:feature_engagement_java",
     "//components/policy/android:policy_java",
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUi.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUi.java
index 2004074..c74d329 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUi.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUi.java
@@ -12,6 +12,12 @@
  * BottomControlsCoordinator.BottomControlsVisibilityController}.
  */
 public interface TabGroupUi {
+    /**
+     * Called by the ToolbarManager when the system back button is pressed.
+     * @return Whether or not the TabGroupUi consumed the event.
+     */
+    boolean onBackPressed();
+
     void initializeWithNative(ChromeActivity activity,
             BottomControlsCoordinator.BottomControlsVisibilityController visibilityController);
     void destroy();
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiCoordinator.java
index f40ea1d..c3ceef34 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiCoordinator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiCoordinator.java
@@ -36,7 +36,7 @@
  */
 public class TabGroupUiCoordinator
         implements TabGroupUiMediator.ResetHandler, TabGroupUi, PauseResumeWithNativeObserver {
-    final static String COMPONENT_NAME = "TabStrip";
+    static final String COMPONENT_NAME = "TabStrip";
     private final Context mContext;
     private final PropertyModel mTabStripToolbarModel;
     private final ThemeColorProvider mThemeColorProvider;
@@ -81,9 +81,11 @@
                 TabProperties.UiType.STRIP, null,
                 mTabStripToolbarCoordinator.getTabListContainerView(), null, true, COMPONENT_NAME);
 
-        if (FeatureUtilities.isTabGroupsAndroidUiImprovementsEnabled()) {
-            // TODO(yuezhanggg): find a way to enable interactions between grid tab switcher and the
-            // dialog here.
+        boolean isTabGroupsUiImprovementsEnabled =
+                FeatureUtilities.isTabGroupsAndroidUiImprovementsEnabled();
+        if (isTabGroupsUiImprovementsEnabled) {
+            // TODO(crbug.com/972217): find a way to enable interactions between grid tab switcher
+            // and the dialog here.
             mTabGridSheetCoordinator = null;
 
             mTabGridDialogCoordinator =
@@ -99,7 +101,10 @@
 
         mMediator = new TabGroupUiMediator(visibilityController, this, mTabStripToolbarModel,
                 tabModelSelector, activity,
-                ((ChromeTabbedActivity) activity).getOverviewModeBehavior(), mThemeColorProvider);
+                ((ChromeTabbedActivity) activity).getOverviewModeBehavior(), mThemeColorProvider,
+                isTabGroupsUiImprovementsEnabled ? mTabGridDialogCoordinator.getDialogController()
+                                                 : null);
+
         mActivityLifecycleDispatcher = activity.getLifecycleDispatcher();
         mActivityLifecycleDispatcher.register(this);
 
@@ -133,6 +138,14 @@
     }
 
     /**
+     * TabGroupUi implementation.
+     */
+    @Override
+    public boolean onBackPressed() {
+        return mMediator.onBackPressed();
+    }
+
+    /**
      * Destroy any members that needs clean up.
      */
     @Override
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediator.java
index 343fb6d..7289b5e 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediator.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.tasks.tab_management;
 
+import androidx.annotation.Nullable;
+
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
@@ -68,19 +70,21 @@
     private final BottomControlsCoordinator
             .BottomControlsVisibilityController mVisibilityController;
     private final ThemeColorProvider mThemeColorProvider;
+    private final TabGridDialogMediator.DialogController mTabGridDialogController;
     private final ThemeColorProvider.ThemeColorObserver mThemeColorObserver;
     private final ThemeColorProvider.TintObserver mTintObserver;
     private final TabModelSelectorTabObserver mTabModelSelectorTabObserver;
     private final TabModelSelectorObserver mTabModelSelectorObserver;
+    private final TabGroupModelFilter.Observer mTabGroupModelFilterObserver;
     private boolean mIsTabGroupUiVisible;
     private boolean mIsShowingOverViewMode;
-    private final TabGroupModelFilter.Observer mTabGroupModelFilterObserver;
 
     TabGroupUiMediator(
             BottomControlsCoordinator.BottomControlsVisibilityController visibilityController,
             ResetHandler resetHandler, PropertyModel toolbarPropertyModel,
             TabModelSelector tabModelSelector, TabCreatorManager tabCreatorManager,
-            OverviewModeBehavior overviewModeBehavior, ThemeColorProvider themeColorProvider) {
+            OverviewModeBehavior overviewModeBehavior, ThemeColorProvider themeColorProvider,
+            @Nullable TabGridDialogMediator.DialogController dialogController) {
         mResetHandler = resetHandler;
         mToolbarPropertyModel = toolbarPropertyModel;
         mTabModelSelector = tabModelSelector;
@@ -88,6 +92,7 @@
         mOverviewModeBehavior = overviewModeBehavior;
         mVisibilityController = visibilityController;
         mThemeColorProvider = themeColorProvider;
+        mTabGridDialogController = dialogController;
 
         // register for tab model
         mTabModelObserver = new EmptyTabModelObserver() {
@@ -256,6 +261,12 @@
                 .getRelatedTabList(id);
     }
 
+    public boolean onBackPressed() {
+        // TODO(crbug.com/1006421): add a regression test to make sure that the back button closes
+        // the dialog when the dialog is showing.
+        return mTabGridDialogController != null && mTabGridDialogController.handleBackPressed();
+    }
+
     public void destroy() {
         if (mTabModelSelector != null) {
             mTabModelSelector.getTabModelFilterProvider().removeTabModelFilterObserver(
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediatorUnitTest.java
index b4448e9..b2b3af3 100644
--- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediatorUnitTest.java
+++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediatorUnitTest.java
@@ -105,6 +105,8 @@
     TabModelFilterProvider mTabModelFilterProvider;
     @Mock
     TabGroupModelFilter mTabGroupModelFilter;
+    @Mock
+    TabGridDialogMediator.DialogController mTabGridDialogController;
     @Captor
     ArgumentCaptor<TabModelObserver> mTabModelObserverArgumentCaptor;
     @Captor
@@ -170,7 +172,8 @@
         }
 
         mTabGroupUiMediator = new TabGroupUiMediator(mVisibilityController, mResetHandler, mModel,
-                mTabModelSelector, mTabCreatorManager, mOverviewModeBehavior, mThemeColorProvider);
+                mTabModelSelector, mTabCreatorManager, mOverviewModeBehavior, mThemeColorProvider,
+                mTabGridDialogController);
 
         if (currentTab == null) {
             verifyNeverReset();
@@ -299,10 +302,11 @@
     }
 
     @Test
+    // clang-format off
     @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID,
             ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID})
-    public void
-    onClickExpand() {
+    public void onClickExpand() {
+        // clang-format on
         initAndAssertProperties(mTab2);
 
         View.OnClickListener listener =
@@ -642,6 +646,24 @@
     }
 
     @Test
+    public void backButtonPress_ShouldHandle() {
+        initAndAssertProperties(mTab1);
+        doReturn(true).when(mTabGridDialogController).handleBackPressed();
+
+        assertThat(mTabGroupUiMediator.onBackPressed(), equalTo(true));
+        verify(mTabGridDialogController).handleBackPressed();
+    }
+
+    @Test
+    public void backButtonPress_ShouldNotHandle() {
+        initAndAssertProperties(mTab1);
+        doReturn(false).when(mTabGridDialogController).handleBackPressed();
+
+        assertThat(mTabGroupUiMediator.onBackPressed(), equalTo(false));
+        verify(mTabGridDialogController).handleBackPressed();
+    }
+
+    @Test
     public void destroy() {
         initAndAssertProperties(mTab1);
 
diff --git a/chrome/android/features/test_dummy/internal/BUILD.gn b/chrome/android/features/test_dummy/internal/BUILD.gn
index 88df7f8e..6482e89 100644
--- a/chrome/android/features/test_dummy/internal/BUILD.gn
+++ b/chrome/android/features/test_dummy/internal/BUILD.gn
@@ -6,9 +6,15 @@
 import("//build/config/android/rules.gni")
 import("//chrome/android/modules/buildflags.gni")
 
+android_resources("java_resources") {
+  resource_dirs = [ "java/res" ]
+  custom_package = "org.chromium.chrome.features.test_dummy"
+}
+
 android_library("java") {
   deps = [
     ":base_module_java",
+    ":java_resources",
     "//base:base_java",
     "//chrome/android/features/test_dummy/public:java",
     "//third_party/android_deps:android_support_v7_appcompat_java",
diff --git a/chrome/android/features/test_dummy/internal/java/res/raw/dummy_resource b/chrome/android/features/test_dummy/internal/java/res/raw/dummy_resource
new file mode 100644
index 0000000..95d09f2b
--- /dev/null
+++ b/chrome/android/features/test_dummy/internal/java/res/raw/dummy_resource
@@ -0,0 +1 @@
+hello world
\ No newline at end of file
diff --git a/chrome/android/features/test_dummy/internal/java/src/org/chromium/chrome/features/test_dummy/TestDummyImpl.java b/chrome/android/features/test_dummy/internal/java/src/org/chromium/chrome/features/test_dummy/TestDummyImpl.java
index a41fcac..8216c6d 100644
--- a/chrome/android/features/test_dummy/internal/java/src/org/chromium/chrome/features/test_dummy/TestDummyImpl.java
+++ b/chrome/android/features/test_dummy/internal/java/src/org/chromium/chrome/features/test_dummy/TestDummyImpl.java
@@ -10,17 +10,24 @@
 
 import androidx.annotation.IntDef;
 
+import org.chromium.base.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Locale;
 
 /** Test dummy implementation. */
 public class TestDummyImpl implements TestDummy {
+    private static final String TAG = "TestDummyImpl";
+
     @IntDef({TestCase.EXECUTE_JAVA, TestCase.EXECUTE_NATIVE})
     @Retention(RetentionPolicy.SOURCE)
     private @interface TestCase {
         int EXECUTE_JAVA = 0;
         int EXECUTE_NATIVE = 1;
+        int LOAD_JAVA_RESOURCE = 2;
     }
 
     @Override
@@ -34,6 +41,9 @@
             case TestCase.EXECUTE_NATIVE:
                 executeNative(activity);
                 break;
+            case TestCase.LOAD_JAVA_RESOURCE:
+                loadJavaResource(activity);
+                break;
             default:
                 throw new RuntimeException("Unknown test case " + testCase);
         }
@@ -56,4 +66,23 @@
         boolean result = TestDummySupport.openAndVerifyNativeLibrary();
         showDoneDialog(activity, TestCase.EXECUTE_NATIVE, result);
     }
+
+    private void loadJavaResource(Activity activity) {
+        InputStream stream = activity.getResources().openRawResource(R.raw.dummy_resource);
+        StringBuilder stringBuilder = new StringBuilder();
+        boolean result;
+        // Note: Not using BufferedReader(-).readLine() in order to capture the content of the
+        // entire resource file.
+        try {
+            int character;
+            while ((character = stream.read()) != -1) {
+                stringBuilder.append((char) character);
+            }
+            result = stringBuilder.toString().equals("hello world");
+        } catch (IOException e) {
+            Log.e(TAG, "Failed to load resource: %s", e);
+            result = false;
+        }
+        showDoneDialog(activity, TestCase.LOAD_JAVA_RESOURCE, result);
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 058c0bb..ccc7e0a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -180,13 +180,16 @@
  * are accessible via a chrome specific tab switching UI.
  */
 public class ChromeTabbedActivity extends ChromeActivity implements ScreenshotMonitorDelegate {
+    /**
+     * The results of a system back press action.
+     */
     @IntDef({BackPressedResult.NOTHING_HAPPENED, BackPressedResult.HELP_URL_CLOSED,
             BackPressedResult.MINIMIZED_NO_TAB_CLOSED, BackPressedResult.MINIMIZED_TAB_CLOSED,
             BackPressedResult.TAB_CLOSED, BackPressedResult.TAB_IS_NULL,
             BackPressedResult.EXITED_TAB_SWITCHER, BackPressedResult.EXITED_FULLSCREEN,
-            BackPressedResult.NAVIGATED_BACK})
+            BackPressedResult.NAVIGATED_BACK, BackPressedResult.EXITED_TAB_GROUP_DIALOG})
     @Retention(RetentionPolicy.SOURCE)
-    private @interface BackPressedResult {
+    public @interface BackPressedResult {
         int NOTHING_HAPPENED = 0;
         int HELP_URL_CLOSED = 1;
         int MINIMIZED_NO_TAB_CLOSED = 2;
@@ -196,8 +199,9 @@
         int EXITED_TAB_SWITCHER = 6;
         int EXITED_FULLSCREEN = 7;
         int NAVIGATED_BACK = 8;
+        int EXITED_TAB_GROUP_DIALOG = 9;
 
-        int NUM_ENTRIES = 9;
+        int NUM_ENTRIES = 10;
     }
 
     private static final String TAG = "ChromeTabbedActivity";
@@ -1896,13 +1900,25 @@
 
         // If we are in overview mode and not a tablet, then leave overview mode on back.
         if (mOverviewModeController.overviewVisible() && !isTablet()) {
-            recordBackPressedUma("Hid overview", BackPressedResult.EXITED_TAB_SWITCHER);
+            recordBackPressedUma("Hide overview", BackPressedResult.EXITED_TAB_SWITCHER);
             mOverviewModeController.hideOverview(true);
             return true;
         }
 
-        if (getToolbarManager().back()) {
-            recordBackPressedUma("Navigating backward", BackPressedResult.NAVIGATED_BACK);
+        Integer toolbarManagerBackPressResult = getToolbarManager().back();
+        if (toolbarManagerBackPressResult != null) {
+            String logMessage = "";
+            switch (toolbarManagerBackPressResult) {
+                case BackPressedResult.NAVIGATED_BACK:
+                    logMessage = "Navigating backward";
+                    break;
+                case BackPressedResult.EXITED_TAB_GROUP_DIALOG:
+                    logMessage = "Exiting tab group dialog";
+                    break;
+                default:
+                    assert false;
+            }
+            recordBackPressedUma(logMessage, toolbarManagerBackPressResult);
             return true;
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabSheetContent.java
index 463485c..294b5f29 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabSheetContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabSheetContent.java
@@ -26,7 +26,7 @@
 import org.chromium.components.embedder_support.view.ContentView;
 import org.chromium.content_public.browser.RenderCoordinates;
 import org.chromium.content_public.browser.WebContents;
-import org.chromium.ui.base.WindowAndroid;
+import org.chromium.ui.base.ActivityWindowAndroid;
 
 /**
  * Represents ephemeral tab content and the toolbar, which can be included inside the bottom sheet.
@@ -81,7 +81,7 @@
      * bottom sheet.
      */
     private void createThinWebView() {
-        mThinWebView = ThinWebViewFactory.create(mContext, new WindowAndroid(mContext));
+        mThinWebView = ThinWebViewFactory.create(mContext, new ActivityWindowAndroid(mContext));
 
         mSheetContentView = new FrameLayout(mContext);
         mSheetContentView.addView(mThinWebView.getView());
@@ -192,6 +192,11 @@
         return true;
     }
 
+    @Override
+    public float getCustomFullRatio() {
+        return 0.9f;
+    }
+
     // TODO(shaktisahu): Provide correct strings for the following methods.
     @Override
     public int getSheetContentDescriptionStringId() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationController.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationController.java
index 393eb4d8..b5b4b372 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationController.java
@@ -202,7 +202,7 @@
     }
 
     private void executeDefaultBackHandling() {
-        if (mToolbarManager.get().back()) return;
+        if (mToolbarManager.get().back() != null) return;
 
         // mTabController.closeTab may result in either closing the only tab (through the back
         // button or the close button), or swapping to the previous tab. In the first case we need
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
index 45191d76..f25cfd2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
@@ -268,8 +268,6 @@
         return false;
     }
 
-    // http://crbug.com/169549 : If you type in a URL that then redirects in server side to a link
-    // that cannot be rendered by the browser, we want to show the intent picker.
     private boolean isTypedRedirectToExternalProtocol(
             ExternalNavigationParams params, int pageTransitionCore, boolean isExternalProtocol) {
         boolean isTyped = (pageTransitionCore == PageTransition.TYPED)
@@ -307,6 +305,45 @@
         return false;
     }
 
+    private boolean preferToShowIntentPicker(ExternalNavigationParams params,
+            int pageTransitionCore, boolean isExternalProtocol, boolean isFormSubmit,
+            boolean linkNotFromIntent, boolean incomingIntentRedirect) {
+        // http://crbug.com/169549 : If you type in a URL that then redirects in server side to a
+        // link that cannot be rendered by the browser, we want to show the intent picker.
+        if (isTypedRedirectToExternalProtocol(params, pageTransitionCore, isExternalProtocol)) {
+            return true;
+        }
+        // http://crbug.com/181186: We need to show the intent picker when we receive a redirect
+        // following a form submit.
+        boolean isRedirectFromFormSubmit = isFormSubmit && params.isRedirect();
+
+        if (!linkNotFromIntent && !incomingIntentRedirect && !isRedirectFromFormSubmit) {
+            if (DEBUG) Log.i(TAG, "NO_OVERRIDE: Incoming intent (not a redirect)");
+            return false;
+        }
+        // http://crbug.com/839751: Require user gestures for form submits to external
+        //                          protocols.
+        // TODO(tedchoc): Remove the ChromeFeatureList check once we verify this change does
+        //                not break the world.
+        if (isRedirectFromFormSubmit && !incomingIntentRedirect && !params.hasUserGesture()
+                && ChromeFeatureList.isEnabled(
+                        ChromeFeatureList.INTENT_BLOCK_EXTERNAL_FORM_REDIRECT_NO_GESTURE)) {
+            if (DEBUG) {
+                Log.i(TAG,
+                        "NO_OVERRIDE: Incoming form intent attempting to redirect without "
+                                + "user gesture");
+            }
+            return false;
+        }
+        // http://crbug/331571 : Do not override a navigation started from user typing.
+        if (params.getRedirectHandler() != null
+                && params.getRedirectHandler().isNavigationFromUserTyping()) {
+            if (DEBUG) Log.i(TAG, "NO_OVERRIDE: Navigation from user typing");
+            return false;
+        }
+        return true;
+    }
+
     private @OverrideUrlLoadingResult int shouldOverrideUrlLoadingInternal(
             ExternalNavigationParams params, Intent intent, boolean hasBrowserFallbackUrl,
             String browserFallbackUrl) {
@@ -331,15 +368,6 @@
             return OverrideUrlLoadingResult.OVERRIDE_WITH_ASYNC_ACTION;
         }
 
-        // We do not want to show the intent picker for core types typed, bookmarks, auto toplevel,
-        // generated, keyword, keyword generated. See below for exception to typed URL and
-        // redirects:
-        // - http://crbug.com/143118 : URL intercepting should not be invoked on navigations
-        //   initiated by the user in the omnibox / NTP.
-        // - http://crbug.com/159153 : Don't override http or https URLs from the NTP or bookmarks.
-        // - http://crbug.com/162106: Intent picker should not be presented on returning to a page.
-        //   This should be covered by not showing the picker if the core type is reload.
-
         // http://crbug.com/149218: We want to show the intent picker for ordinary links, providing
         // the link is not an incoming intent from another application, unless it's a redirect (see
         // below).
@@ -360,40 +388,14 @@
             return OverrideUrlLoadingResult.NO_OVERRIDE;
         }
 
-        if (!isTypedRedirectToExternalProtocol(params, pageTransitionCore, isExternalProtocol)) {
-            // http://crbug.com/181186: We need to show the intent picker when we receive a redirect
-            // following a form submit.
-            boolean isRedirectFromFormSubmit = isFormSubmit && params.isRedirect();
-
-            if (!linkNotFromIntent && !incomingIntentRedirect && !isRedirectFromFormSubmit) {
-                if (DEBUG) Log.i(TAG, "NO_OVERRIDE: Incoming intent (not a redirect)");
-                return OverrideUrlLoadingResult.NO_OVERRIDE;
-            }
-            // http://crbug.com/839751: Require user gestures for form submits to external
-            //                          protocols.
-            // TODO(tedchoc): Remove the ChromeFeatureList check once we verify this change does
-            //                not break the world.
-            if (isRedirectFromFormSubmit && !incomingIntentRedirect && !params.hasUserGesture()
-                    && ChromeFeatureList.isEnabled(
-                            ChromeFeatureList.INTENT_BLOCK_EXTERNAL_FORM_REDIRECT_NO_GESTURE)) {
-                if (DEBUG) {
-                    Log.i(TAG,
-                            "NO_OVERRIDE: Incoming form intent attempting to redirect without "
-                                    + "user gesture");
-                }
-                return OverrideUrlLoadingResult.NO_OVERRIDE;
-            }
-            // http://crbug/331571 : Do not override a navigation started from user typing.
-            if (params.getRedirectHandler() != null
-                    && params.getRedirectHandler().isNavigationFromUserTyping()) {
-                if (DEBUG) Log.i(TAG, "NO_OVERRIDE: Navigation from user typing");
-                return OverrideUrlLoadingResult.NO_OVERRIDE;
-            }
+        if (!preferToShowIntentPicker(params, pageTransitionCore, isExternalProtocol, isFormSubmit,
+                    linkNotFromIntent, incomingIntentRedirect)) {
+            return OverrideUrlLoadingResult.NO_OVERRIDE;
         }
 
-        // Don't override navigation from a chrome:* url to http or https. For example,
-        // when clicking a link in bookmarks or most visited. When navigating from such a
-        // page, there is clear intent to complete the navigation in Chrome.
+        // http://crbug.com/159153: Don't override navigation from a chrome:* url to http or https.
+        // For example when clicking a link in bookmarks or most visited. When navigating from such
+        // a page, there is clear intent to complete the navigation in Chrome.
         if (params.getReferrerUrl() != null
                 && params.getReferrerUrl().startsWith(UrlConstants.CHROME_URL_PREFIX)
                 && (params.getUrl().startsWith(UrlConstants.HTTP_URL_PREFIX)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/sync/AccountManagementFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/sync/AccountManagementFragment.java
index dbc720f3..c997754b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/sync/AccountManagementFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/sync/AccountManagementFragment.java
@@ -310,6 +310,8 @@
             SigninUtils.logEvent(ProfileAccountManagementMetrics.ADD_ACCOUNT, mGaiaServiceType);
 
             AccountManagerFacade.get().createAddAccountIntent((@Nullable Intent intent) -> {
+                if (!isVisible() || !isResumed()) return;
+
                 if (intent != null) {
                     startActivity(intent);
                     return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabRedirectHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabRedirectHandler.java
index 5634fa3..9eec537 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabRedirectHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabRedirectHandler.java
@@ -278,7 +278,7 @@
     }
 
     private boolean shouldNavigationTypeStayInChrome(boolean isForTrustedCallingApp) {
-        // Never leave Chrome from a refresh.
+        // http://crbug.com/162106: Never leave Chrome from a refresh.
         if (mInitialNavigationType == NAVIGATION_TYPE_FROM_RELOAD) return true;
 
         // If the app we would navigate to is trusted and what launched Chrome, allow the
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
index 5d9243d..3ced0cd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -1451,14 +1451,18 @@
     }
 
     @Override
-    public boolean back() {
+    public @ChromeTabbedActivity.BackPressedResult Integer back() {
+        if (mBottomControlsCoordinator != null && mBottomControlsCoordinator.onBackPressed()) {
+            return ChromeTabbedActivity.BackPressedResult.EXITED_TAB_GROUP_DIALOG;
+        }
+
         Tab tab = mLocationBarModel.getTab();
         if (tab != null && tab.canGoBack()) {
             tab.goBack();
             updateButtonStatus();
-            return true;
+            return ChromeTabbedActivity.BackPressedResult.NAVIGATED_BACK;
         }
-        return false;
+        return null;
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarTabController.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarTabController.java
index 54a58a6..20f4854b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarTabController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarTabController.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.toolbar;
 
+import org.chromium.chrome.browser.ChromeTabbedActivity;
+
 /**
  * Handles toolbar triggered actions on the specific tab.
  */
@@ -17,10 +19,12 @@
     void stopOrReloadCurrentTab();
 
     /**
-     * Navigates the current Tab back.
-     * @return Whether or not the current Tab did go back.
+     * Handles a back press action in tab page.
+     * @return A {@link ChromeTabbedActivity.BackPressedResult} indicating the result of this back
+     *         press. If returning null, the back press event is not consumed here.
      */
-    boolean back();
+    @ChromeTabbedActivity.BackPressedResult
+    Integer back();
 
     /**
      * Navigates the current Tab forward.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomControlsCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomControlsCoordinator.java
index e2ff209..0d3bc64 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomControlsCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomControlsCoordinator.java
@@ -207,6 +207,14 @@
     }
 
     /**
+     * Handles system back press action if needed.
+     * @return Whether or not the back press event is consumed here.
+     */
+    public boolean onBackPressed() {
+        return mTabGroupUi != null && mTabGroupUi.onBackPressed();
+    }
+
+    /**
      * @param layout The {@link ToolbarSwipeLayout} that the bottom controls will hook into. This
      *               allows the bottom controls to provide the layout with scene layers with the
      *               bottom controls' texture.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
index 6ce467e0..1a1838c8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
@@ -798,7 +798,7 @@
      */
     boolean back() {
         if (getLocationBar() != null) getLocationBar().setUrlBarFocus(false);
-        return mToolbarTabController != null ? mToolbarTabController.back() : false;
+        return mToolbarTabController != null && mToolbarTabController.back() != null;
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
index 279c59e5..85ea40b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
@@ -1213,8 +1213,8 @@
      * @return The height of the sheet at the provided state.
      */
     private float getSheetHeightForState(@SheetState int state) {
-        if (mSheetContent != null && mSheetContent.wrapContentEnabled()
-                && state == SheetState.FULL) {
+        if (mSheetContent != null && mSheetContent.wrapContentEnabled() && state == SheetState.FULL
+                && mSheetContent.getCustomFullRatio() == INVALID_HEIGHT_RATIO) {
             ensureContentDesiredHeightIsComputed();
             return mContentDesiredHeight + mToolbarShadowHeight;
         }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActivityTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActivityTestRule.java
index 9747507..bcc8a2e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActivityTestRule.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActivityTestRule.java
@@ -159,7 +159,7 @@
      * Executing window.open() through a click on a link, as it needs user gesture to avoid Chrome
      * blocking it as a popup.
      */
-    static public void jsWindowOpen(ChromeActivity activity, String url) throws Exception {
+    public static void jsWindowOpen(ChromeActivity activity, String url) throws Exception {
         String injectedHtml = String.format("var aTag = document.createElement('testId');"
                         + "aTag.id = 'testId';"
                         + "aTag.innerHTML = 'Click Me!';"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/test/smoke/ChromeBundleSmokeTest.java b/chrome/android/javatests/src/org/chromium/chrome/test/smoke/ChromeBundleSmokeTest.java
index fc0b09c..589042f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/test/smoke/ChromeBundleSmokeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/test/smoke/ChromeBundleSmokeTest.java
@@ -78,4 +78,9 @@
     public void testModuleNativeCodeExecution() {
         runTestActivity(1); // Test case EXECUTE_NATIVE.
     }
+
+    @Test
+    public void testModuleJavaResourceLoading() {
+        runTestActivity(2); // Test case LOAD_JAVA_RESOURCE.
+    }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityContentTestEnvironment.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityContentTestEnvironment.java
index 4b3f827..c32bc11 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityContentTestEnvironment.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityContentTestEnvironment.java
@@ -113,6 +113,8 @@
         when(tabModelSelector.getModel(anyBoolean())).thenReturn(tabModel);
         when(connection.getSpeculatedUrl(any())).thenReturn(SPECULATED_URL);
         when(browserInitializer.hasNativeInitializationCompleted()).thenReturn(true);
+        // Default setup is toolbarManager doesn't consume back press event.
+        when(toolbarManager.back()).thenReturn(null);
 
         doNothing().when(activityTabProvider).addObserverAndTrigger(
                 activityTabObserverCaptor.capture());
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 313ae00f..ca50175c 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -4348,6 +4348,9 @@
     <message name="IDS_SETTINGS_USERS_ADD_USERS_EMAIL" desc="Label for the email input field for adding users.">
       Email address
     </message>
+    <message name="IDS_SETTINGS_USER_EXISTS_ERROR" desc="Error message for attempting to add a user that already exists">
+      This user already exists
+    </message>
   </if>
 
   <!-- Parental Controls -->
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 7432902..39538309 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1136,6 +1136,10 @@
     {"predictor", ui::input_prediction::kScrollPredictorNameLsq}};
 const FeatureEntry::FeatureParam kResamplingInputEventsKalmanEnabled[] = {
     {"predictor", ui::input_prediction::kScrollPredictorNameKalman}};
+const FeatureEntry::FeatureParam
+    kResamplingInputEventsKalmanHeuristicEnabled[] = {
+        {"predictor",
+         ui::input_prediction::kScrollPredictorNameKalmanHeuristic}};
 const FeatureEntry::FeatureParam kResamplingInputEventsLinearFirstEnabled[] = {
     {"predictor", ui::input_prediction::kScrollPredictorNameLinearFirst}};
 const FeatureEntry::FeatureParam kResamplingInputEventsLinearSecondEnabled[] = {
@@ -1152,6 +1156,9 @@
      {ui::input_prediction::kScrollPredictorNameKalman,
       kResamplingInputEventsKalmanEnabled,
       base::size(kResamplingInputEventsKalmanEnabled), nullptr},
+     {ui::input_prediction::kScrollPredictorNameKalmanHeuristic,
+      kResamplingInputEventsKalmanHeuristicEnabled,
+      base::size(kResamplingInputEventsKalmanHeuristicEnabled), nullptr},
      {ui::input_prediction::kScrollPredictorNameLinearFirst,
       kResamplingInputEventsLinearFirstEnabled,
       base::size(kResamplingInputEventsLinearFirstEnabled), nullptr},
diff --git a/chrome/browser/android/util/url_utilities.cc b/chrome/browser/android/util/url_utilities.cc
index 337c229e..5de57b4a 100644
--- a/chrome/browser/android/util/url_utilities.cc
+++ b/chrome/browser/android/util/url_utilities.cc
@@ -7,7 +7,7 @@
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
 #include "base/strings/string_util.h"
-#include "chrome/lib/util/public/android/jni_headers/UrlUtilities_jni.h"
+#include "chrome/browser/util/android/jni_headers/UrlUtilities_jni.h"
 #include "components/google/core/common/google_util.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "url/gurl.h"
diff --git a/chrome/browser/autofill/autofill_keyboard_accessory_adapter_unittest.cc b/chrome/browser/autofill/autofill_keyboard_accessory_adapter_unittest.cc
index a901596..b7abc23 100644
--- a/chrome/browser/autofill/autofill_keyboard_accessory_adapter_unittest.cc
+++ b/chrome/browser/autofill/autofill_keyboard_accessory_adapter_unittest.cc
@@ -44,7 +44,6 @@
                void(const base::string16&,
                     const base::string16&,
                     base::OnceClosure));
-  MOCK_METHOD1(SetTypesetter, void(gfx::Typesetter));
   MOCK_METHOD1(GetElidedValueWidthForRow, int(int));
   MOCK_METHOD1(GetElidedLabelWidthForRow, int(int));
 
diff --git a/chrome/browser/autofill/mock_autofill_popup_controller.h b/chrome/browser/autofill/mock_autofill_popup_controller.h
index 164523e..1fca0d9 100644
--- a/chrome/browser/autofill/mock_autofill_popup_controller.h
+++ b/chrome/browser/autofill/mock_autofill_popup_controller.h
@@ -44,7 +44,6 @@
     return suggestions_;
   }
 #if !defined(OS_ANDROID)
-  MOCK_METHOD1(SetTypesetter, void(gfx::Typesetter typesetter));
   MOCK_METHOD1(GetElidedValueWidthForRow, int(int row));
   MOCK_METHOD1(GetElidedLabelWidthForRow, int(int row));
 #endif
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index ff2b87b7f..47968ee 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -2357,11 +2357,13 @@
 
 bool ChromeContentBrowserClient::AllowServiceWorkerOnIO(
     const GURL& scope,
-    const GURL& first_party_url,
+    const GURL& site_for_cookies,
+    const base::Optional<url::Origin>& top_frame_origin,
     const GURL& script_url,
     content::ResourceContext* context,
     base::RepeatingCallback<content::WebContents*()> wc_getter) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  GURL first_party_url = top_frame_origin ? top_frame_origin->GetURL() : GURL();
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   // Check if this is an extension-related service worker, and, if so, if it's
@@ -2388,9 +2390,8 @@
   bool allow_javascript = (setting == CONTENT_SETTING_ALLOW);
 
   // Check if cookies are allowed.
-  bool allow_serviceworker =
-      io_data->GetCookieSettings()->IsCookieAccessAllowed(scope,
-                                                          first_party_url);
+  bool allow_cookies = io_data->GetCookieSettings()->IsCookieAccessAllowed(
+      scope, site_for_cookies, top_frame_origin);
   // Record access to database for potential display in UI.
   // Only post the task if this is for a specific tab.
   if (!wc_getter.is_null()) {
@@ -2398,18 +2399,20 @@
         FROM_HERE, {BrowserThread::UI},
         base::BindOnce(&TabSpecificContentSettings::ServiceWorkerAccessed,
                        std::move(wc_getter), scope, !allow_javascript,
-                       !allow_serviceworker));
+                       !allow_cookies));
   }
-  return allow_javascript && allow_serviceworker;
+  return allow_javascript && allow_cookies;
 }
 
 bool ChromeContentBrowserClient::AllowServiceWorkerOnUI(
     const GURL& scope,
-    const GURL& first_party_url,
+    const GURL& site_for_cookies,
+    const base::Optional<url::Origin>& top_frame_origin,
     const GURL& script_url,
     content::BrowserContext* context,
     base::RepeatingCallback<content::WebContents*()> wc_getter) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  GURL first_party_url = top_frame_origin ? top_frame_origin->GetURL() : GURL();
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   // Check if this is an extension-related service worker, and, if so, if it's
@@ -2438,7 +2441,7 @@
   // Check if cookies are allowed.
   bool allow_cookies =
       CookieSettingsFactory::GetForProfile(profile)->IsCookieAccessAllowed(
-          scope, first_party_url);
+          scope, site_for_cookies, top_frame_origin);
 
   // Record access to database for potential display in UI.
   // Only post the task if this is for a specific tab.
@@ -2451,7 +2454,8 @@
 
 bool ChromeContentBrowserClient::AllowSharedWorker(
     const GURL& worker_url,
-    const GURL& main_frame_url,
+    const GURL& site_for_cookies,
+    const base::Optional<url::Origin>& top_frame_origin,
     const std::string& name,
     const url::Origin& constructor_origin,
     content::BrowserContext* context,
@@ -2462,7 +2466,8 @@
   // Check if cookies are allowed.
   bool allow =
       CookieSettingsFactory::GetForProfile(Profile::FromBrowserContext(context))
-          ->IsCookieAccessAllowed(worker_url, main_frame_url);
+          ->IsCookieAccessAllowed(worker_url, site_for_cookies,
+                                  top_frame_origin);
 
   TabSpecificContentSettings::SharedWorkerAccessed(
       render_process_id, render_frame_id, worker_url, name, constructor_origin,
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index 4b251ce..d0671e23 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -221,18 +221,21 @@
                      content::BrowserContext* context) override;
   bool AllowServiceWorkerOnIO(
       const GURL& scope,
-      const GURL& first_party,
+      const GURL& site_for_cookies,
+      const base::Optional<url::Origin>& top_frame_origin,
       const GURL& script_url,
       content::ResourceContext* context,
       base::RepeatingCallback<content::WebContents*()> wc_getter) override;
   bool AllowServiceWorkerOnUI(
       const GURL& scope,
-      const GURL& first_party,
+      const GURL& site_for_cookies,
+      const base::Optional<url::Origin>& top_frame_origin,
       const GURL& script_url,
       content::BrowserContext* context,
       base::RepeatingCallback<content::WebContents*()> wc_getter) override;
   bool AllowSharedWorker(const GURL& worker_url,
-                         const GURL& main_frame_url,
+                         const GURL& site_for_cookies,
+                         const base::Optional<url::Origin>& top_frame_origin,
                          const std::string& name,
                          const url::Origin& constructor_origin,
                          content::BrowserContext* context,
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 7ef3ebaf..8dc435f 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -2219,6 +2219,12 @@
     "extensions/login_screen/login_state/session_state_changed_event_dispatcher.h",
     "extensions/media_player_api.cc",
     "extensions/media_player_api.h",
+    "extensions/printing_metrics/print_job_finished_event_dispatcher.cc",
+    "extensions/printing_metrics/print_job_finished_event_dispatcher.h",
+    "extensions/printing_metrics/print_job_info_idl_conversions.cc",
+    "extensions/printing_metrics/print_job_info_idl_conversions.h",
+    "extensions/printing_metrics/printing_metrics_api.cc",
+    "extensions/printing_metrics/printing_metrics_api.h",
     "extensions/quick_unlock_private/quick_unlock_private_api.cc",
     "extensions/quick_unlock_private/quick_unlock_private_api.h",
     "extensions/users_private/users_private_api.cc",
@@ -2528,6 +2534,7 @@
     "extensions/login_screen/login_state/login_state_api_unittest.cc",
     "extensions/login_screen/login_state/session_state_changed_event_dispatcher_unittest.cc",
     "extensions/permissions_updater_delegate_chromeos_unittest.cc",
+    "extensions/printing_metrics/print_job_info_idl_conversions_unittest.cc",
     "extensions/public_session_permission_helper_unittest.cc",
     "extensions/quick_unlock_private/quick_unlock_private_api_unittest.cc",
     "extensions/signin_screen_policy_provider_unittest.cc",
diff --git a/chrome/browser/chromeos/extensions/printing_metrics/print_job_finished_event_dispatcher.cc b/chrome/browser/chromeos/extensions/printing_metrics/print_job_finished_event_dispatcher.cc
new file mode 100644
index 0000000..3c2283b
--- /dev/null
+++ b/chrome/browser/chromeos/extensions/printing_metrics/print_job_finished_event_dispatcher.cc
@@ -0,0 +1,52 @@
+// 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 "chrome/browser/chromeos/extensions/printing_metrics/print_job_finished_event_dispatcher.h"
+
+#include "base/no_destructor.h"
+#include "chrome/browser/chromeos/extensions/printing_metrics/print_job_info_idl_conversions.h"
+#include "chrome/common/extensions/api/printing_metrics.h"
+#include "content/public/browser/browser_context.h"
+#include "extensions/browser/event_router.h"
+#include "extensions/browser/extension_event_histogram_value.h"
+
+namespace extensions {
+
+BrowserContextKeyedAPIFactory<PrintJobFinishedEventDispatcher>*
+PrintJobFinishedEventDispatcher::GetFactoryInstance() {
+  static base::NoDestructor<
+      BrowserContextKeyedAPIFactory<PrintJobFinishedEventDispatcher>>
+      instance;
+  return instance.get();
+}
+
+PrintJobFinishedEventDispatcher::PrintJobFinishedEventDispatcher(
+    content::BrowserContext* browser_context)
+    : browser_context_(browser_context),
+      event_router_(EventRouter::Get(browser_context)),
+      print_job_history_service_observer_(this) {
+  print_job_history_service_observer_.Add(
+      chromeos::PrintJobHistoryServiceFactory::GetForBrowserContext(
+          browser_context));
+}
+
+PrintJobFinishedEventDispatcher::~PrintJobFinishedEventDispatcher() {}
+
+void PrintJobFinishedEventDispatcher::OnPrintJobFinished(
+    const chromeos::printing::proto::PrintJobInfo& print_job_info) {
+  auto event = std::make_unique<Event>(
+      events::PRINTING_METRICS_ON_PRINT_JOB_FINISHED,
+      api::printing_metrics::OnPrintJobFinished::kEventName,
+      api::printing_metrics::OnPrintJobFinished::Create(
+          PrintJobInfoProtoToIdl(print_job_info)));
+
+  event_router_->BroadcastEvent(std::move(event));
+}
+
+void PrintJobFinishedEventDispatcher::SetEventRouterForTesting(
+    EventRouter* event_router) {
+  event_router_ = event_router;
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/chromeos/extensions/printing_metrics/print_job_finished_event_dispatcher.h b/chrome/browser/chromeos/extensions/printing_metrics/print_job_finished_event_dispatcher.h
new file mode 100644
index 0000000..c2d5d8ed
--- /dev/null
+++ b/chrome/browser/chromeos/extensions/printing_metrics/print_job_finished_event_dispatcher.h
@@ -0,0 +1,74 @@
+// 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 CHROME_BROWSER_CHROMEOS_EXTENSIONS_PRINTING_METRICS_PRINT_JOB_FINISHED_EVENT_DISPATCHER_H_
+#define CHROME_BROWSER_CHROMEOS_EXTENSIONS_PRINTING_METRICS_PRINT_JOB_FINISHED_EVENT_DISPATCHER_H_
+
+#include "base/macros.h"
+#include "base/scoped_observer.h"
+#include "chrome/browser/chromeos/printing/history/print_job_history_service.h"
+#include "chrome/browser/chromeos/printing/history/print_job_history_service_factory.h"
+#include "extensions/browser/browser_context_keyed_api_factory.h"
+#include "extensions/browser/event_router_factory.h"
+
+namespace content {
+class BrowserContext;
+}  // namespace content
+
+namespace extensions {
+
+class EventRouter;
+
+// PrintJobFinishedEventDispatcher observes changes in the print job history
+// service and dispatches them to extensions listening on the
+// printingMetrics.onPrintJobFinished() event.
+class PrintJobFinishedEventDispatcher
+    : public BrowserContextKeyedAPI,
+      public chromeos::PrintJobHistoryService::Observer {
+ public:
+  explicit PrintJobFinishedEventDispatcher(
+      content::BrowserContext* browser_context);
+  ~PrintJobFinishedEventDispatcher() override;
+
+  // BrowserContextKeyedAPI:
+  static BrowserContextKeyedAPIFactory<PrintJobFinishedEventDispatcher>*
+  GetFactoryInstance();
+
+  // PrintJobHistoryService::Observer:
+  void OnPrintJobFinished(
+      const chromeos::printing::proto::PrintJobInfo& print_job_info) override;
+
+  void SetEventRouterForTesting(EventRouter* event_router);
+
+ private:
+  // Needed for BrowserContextKeyedAPI implementation.
+  friend class BrowserContextKeyedAPIFactory<PrintJobFinishedEventDispatcher>;
+
+  // BrowserContextKeyedAPI implementation.
+  static const bool kServiceIsNULLWhileTesting = true;
+  static const char* service_name() {
+    return "PrintJobFinishedEventDispatcher";
+  }
+
+  content::BrowserContext* browser_context_;
+  EventRouter* event_router_;
+  ScopedObserver<chromeos::PrintJobHistoryService,
+                 chromeos::PrintJobHistoryService::Observer>
+      print_job_history_service_observer_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrintJobFinishedEventDispatcher);
+};
+
+template <>
+struct BrowserContextFactoryDependencies<PrintJobFinishedEventDispatcher> {
+  static void DeclareFactoryDependencies(
+      BrowserContextKeyedAPIFactory<PrintJobFinishedEventDispatcher>* factory) {
+    factory->DependsOn(EventRouterFactory::GetInstance());
+    factory->DependsOn(chromeos::PrintJobHistoryServiceFactory::GetInstance());
+  }
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_CHROMEOS_EXTENSIONS_PRINTING_METRICS_PRINT_JOB_FINISHED_EVENT_DISPATCHER_H_
diff --git a/chrome/browser/chromeos/extensions/printing_metrics/print_job_info_idl_conversions.cc b/chrome/browser/chromeos/extensions/printing_metrics/print_job_info_idl_conversions.cc
new file mode 100644
index 0000000..f314d1d
--- /dev/null
+++ b/chrome/browser/chromeos/extensions/printing_metrics/print_job_info_idl_conversions.cc
@@ -0,0 +1,134 @@
+// 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 "chrome/browser/chromeos/extensions/printing_metrics/print_job_info_idl_conversions.h"
+
+#include "base/numerics/safe_conversions.h"
+
+namespace proto = chromeos::printing::proto;
+
+namespace extensions {
+
+namespace idl = api::printing_metrics;
+
+namespace {
+
+idl::ColorMode ColorModeProtoToIdl(proto::PrintSettings_ColorMode color_proto) {
+  switch (color_proto) {
+    case proto::PrintSettings_ColorMode_BLACK_AND_WHITE:
+      return idl::COLOR_MODE_BLACK_AND_WHITE;
+    case proto::PrintSettings_ColorMode_COLOR:
+      return idl::COLOR_MODE_COLOR;
+    default:
+      NOTREACHED();
+  }
+  return idl::COLOR_MODE_BLACK_AND_WHITE;
+}
+
+idl::DuplexMode DuplexModeProtoToIdl(
+    proto::PrintSettings_DuplexMode duplex_proto) {
+  switch (duplex_proto) {
+    case proto::PrintSettings_DuplexMode_ONE_SIDED:
+      return idl::DUPLEX_MODE_ONE_SIDED;
+    case proto::PrintSettings_DuplexMode_TWO_SIDED_LONG_EDGE:
+      return idl::DUPLEX_MODE_TWO_SIDED_LONG_EDGE;
+    case proto::PrintSettings_DuplexMode_TWO_SIDED_SHORT_EDGE:
+      return idl::DUPLEX_MODE_TWO_SIDED_SHORT_EDGE;
+    default:
+      NOTREACHED();
+  }
+  return idl::DUPLEX_MODE_ONE_SIDED;
+}
+
+idl::MediaSize MediaSizeProtoToIdl(const proto::MediaSize& media_size_proto) {
+  idl::MediaSize media_size;
+  media_size.width = media_size_proto.width();
+  media_size.height = media_size_proto.height();
+  media_size.vendor_id = media_size_proto.vendor_id();
+  return media_size;
+}
+
+idl::PrintSettings PrintSettingsProtoToIdl(
+    const proto::PrintSettings& settings_proto) {
+  idl::PrintSettings settings;
+  settings.color = ColorModeProtoToIdl(settings_proto.color());
+  settings.duplex = DuplexModeProtoToIdl(settings_proto.duplex());
+  settings.media_size = MediaSizeProtoToIdl(settings_proto.media_size());
+  settings.copies = settings_proto.copies();
+  return settings;
+}
+
+idl::PrintJobSource PrintJobSourceProtoToIdl(
+    proto::PrintJobInfo_PrintJobSource print_job_source_proto) {
+  switch (print_job_source_proto) {
+    case proto::PrintJobInfo_PrintJobSource_PRINT_PREVIEW:
+      return idl::PRINT_JOB_SOURCE_PRINT_PREVIEW;
+    case proto::PrintJobInfo_PrintJobSource_ARC:
+      return idl::PRINT_JOB_SOURCE_ANDROID_APP;
+    default:
+      NOTREACHED();
+  }
+  return idl::PRINT_JOB_SOURCE_PRINT_PREVIEW;
+}
+
+idl::PrintJobStatus PrintJobStatusProtoToIdl(
+    proto::PrintJobInfo_PrintJobStatus print_job_status_proto) {
+  switch (print_job_status_proto) {
+    case proto::PrintJobInfo_PrintJobStatus_FAILED:
+      return idl::PRINT_JOB_STATUS_FAILED;
+    case proto::PrintJobInfo_PrintJobStatus_CANCELED:
+      return idl::PRINT_JOB_STATUS_CANCELED;
+    case proto::PrintJobInfo_PrintJobStatus_PRINTED:
+      return idl::PRINT_JOB_STATUS_PRINTED;
+    default:
+      NOTREACHED();
+  }
+  return idl::PRINT_JOB_STATUS_FAILED;
+}
+
+idl::PrinterSource PrinterSourceProtoToIdl(
+    proto::Printer_PrinterSource printer_source_proto) {
+  switch (printer_source_proto) {
+    case proto::Printer_PrinterSource_USER:
+      return idl::PRINTER_SOURCE_USER;
+    case proto::Printer_PrinterSource_POLICY:
+      return idl::PRINTER_SOURCE_POLICY;
+    default:
+      NOTREACHED();
+  }
+  return idl::PRINTER_SOURCE_USER;
+}
+
+idl::Printer PrinterProtoToIdl(const proto::Printer& printer_proto) {
+  idl::Printer printer;
+  printer.name = printer_proto.name();
+  printer.uri = printer_proto.uri();
+  printer.source = PrinterSourceProtoToIdl(printer_proto.source());
+  return printer;
+}
+
+}  // namespace
+
+idl::PrintJobInfo PrintJobInfoProtoToIdl(
+    const proto::PrintJobInfo& print_job_info_proto) {
+  idl::PrintJobInfo print_job_info;
+  print_job_info.id = print_job_info_proto.id();
+  print_job_info.title = print_job_info_proto.title();
+  print_job_info.source =
+      PrintJobSourceProtoToIdl(print_job_info_proto.source());
+  print_job_info.source_id = nullptr;
+  print_job_info.status =
+      PrintJobStatusProtoToIdl(print_job_info_proto.status());
+  print_job_info.creation_time =
+      base::checked_cast<double>(print_job_info_proto.creation_time());
+  print_job_info.completion_time =
+      base::checked_cast<double>(print_job_info_proto.completion_time());
+  print_job_info.printer = PrinterProtoToIdl(print_job_info_proto.printer());
+  print_job_info.settings =
+      PrintSettingsProtoToIdl(print_job_info_proto.settings());
+  print_job_info.number_of_pages = print_job_info_proto.number_of_pages();
+  return print_job_info;
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/chromeos/extensions/printing_metrics/print_job_info_idl_conversions.h b/chrome/browser/chromeos/extensions/printing_metrics/print_job_info_idl_conversions.h
new file mode 100644
index 0000000..1cbde72
--- /dev/null
+++ b/chrome/browser/chromeos/extensions/printing_metrics/print_job_info_idl_conversions.h
@@ -0,0 +1,18 @@
+// 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 CHROME_BROWSER_CHROMEOS_EXTENSIONS_PRINTING_METRICS_PRINT_JOB_INFO_IDL_CONVERSIONS_H_
+#define CHROME_BROWSER_CHROMEOS_EXTENSIONS_PRINTING_METRICS_PRINT_JOB_INFO_IDL_CONVERSIONS_H_
+
+#include "chrome/browser/chromeos/printing/history/print_job_info.pb.h"
+#include "chrome/common/extensions/api/printing_metrics.h"
+
+namespace extensions {
+
+api::printing_metrics::PrintJobInfo PrintJobInfoProtoToIdl(
+    const chromeos::printing::proto::PrintJobInfo& print_job_info_proto);
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_CHROMEOS_EXTENSIONS_PRINTING_METRICS_PRINT_JOB_INFO_IDL_CONVERSIONS_H_
diff --git a/chrome/browser/chromeos/extensions/printing_metrics/print_job_info_idl_conversions_unittest.cc b/chrome/browser/chromeos/extensions/printing_metrics/print_job_info_idl_conversions_unittest.cc
new file mode 100644
index 0000000..dbcbdc6
--- /dev/null
+++ b/chrome/browser/chromeos/extensions/printing_metrics/print_job_info_idl_conversions_unittest.cc
@@ -0,0 +1,90 @@
+// 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 "chrome/browser/chromeos/extensions/printing_metrics/print_job_info_idl_conversions.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace proto = chromeos::printing::proto;
+
+namespace extensions {
+
+namespace idl = api::printing_metrics;
+
+namespace {
+
+constexpr int kWidth = 297000;
+constexpr int kHeight = 420000;
+constexpr char kVendorId[] = "iso_a3_297x420mm";
+constexpr int kCopies = 2;
+
+constexpr char kName[] = "name";
+constexpr char kUri[] = "ipp://192.168.1.5";
+
+constexpr char kTitle[] = "title";
+constexpr char kId[] = "id";
+constexpr int64_t kJobCreationTime = 1000;
+constexpr int64_t kJobCompletionTime = 11 * 1000;
+constexpr int kPagesNumber = 3;
+
+}  // namespace
+
+TEST(PrintJobInfoIdlConversionsTest, PrintJobInfoProtoToIdl) {
+  proto::PrintJobInfo print_job_info_proto;
+  print_job_info_proto.set_id(kId);
+  print_job_info_proto.set_title(kTitle);
+  print_job_info_proto.set_source(
+      proto::PrintJobInfo_PrintJobSource_PRINT_PREVIEW);
+  print_job_info_proto.set_source_id("");
+  print_job_info_proto.set_status(proto::PrintJobInfo_PrintJobStatus_FAILED);
+  print_job_info_proto.set_creation_time(kJobCreationTime);
+  print_job_info_proto.set_completion_time(kJobCompletionTime);
+
+  proto::Printer printer_proto;
+  printer_proto.set_name(kName);
+  printer_proto.set_uri(kUri);
+  printer_proto.set_source(proto::Printer_PrinterSource_POLICY);
+  *print_job_info_proto.mutable_printer() = printer_proto;
+
+  proto::MediaSize media_size_proto;
+  media_size_proto.set_width(kWidth);
+  media_size_proto.set_height(kHeight);
+  media_size_proto.set_vendor_id(kVendorId);
+  proto::PrintSettings settings_proto;
+  settings_proto.set_color(proto::PrintSettings_ColorMode_COLOR);
+  settings_proto.set_duplex(proto::PrintSettings_DuplexMode_ONE_SIDED);
+  *settings_proto.mutable_media_size() = media_size_proto;
+  settings_proto.set_copies(kCopies);
+  *print_job_info_proto.mutable_settings() = settings_proto;
+
+  print_job_info_proto.set_number_of_pages(kPagesNumber);
+
+  idl::PrintJobInfo print_job_info =
+      PrintJobInfoProtoToIdl(print_job_info_proto);
+  const idl::Printer& printer = print_job_info.printer;
+  const idl::PrintSettings& settings = print_job_info.settings;
+  const idl::MediaSize& media_size = settings.media_size;
+
+  EXPECT_EQ(kId, print_job_info.id);
+  EXPECT_EQ(kTitle, print_job_info.title);
+  EXPECT_EQ(idl::PRINT_JOB_SOURCE_PRINT_PREVIEW, print_job_info.source);
+  EXPECT_EQ(nullptr, print_job_info.source_id);
+  EXPECT_EQ(idl::PRINT_JOB_STATUS_FAILED, print_job_info.status);
+  EXPECT_DOUBLE_EQ(static_cast<double>(kJobCreationTime),
+                   print_job_info.creation_time);
+  EXPECT_DOUBLE_EQ(static_cast<double>(kJobCompletionTime),
+                   print_job_info.completion_time);
+  EXPECT_EQ(kName, printer.name);
+  EXPECT_EQ(kUri, printer.uri);
+  EXPECT_EQ(idl::PRINTER_SOURCE_POLICY, printer.source);
+  EXPECT_EQ(idl::COLOR_MODE_COLOR, settings.color);
+  EXPECT_EQ(idl::DUPLEX_MODE_ONE_SIDED, settings.duplex);
+  EXPECT_EQ(kCopies, settings.copies);
+  EXPECT_EQ(kWidth, media_size.width);
+  EXPECT_EQ(kHeight, media_size.height);
+  EXPECT_EQ(kVendorId, media_size.vendor_id);
+  EXPECT_EQ(kPagesNumber, print_job_info.number_of_pages);
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/chromeos/extensions/printing_metrics/printing_metrics_api.cc b/chrome/browser/chromeos/extensions/printing_metrics/printing_metrics_api.cc
new file mode 100644
index 0000000..935a999
--- /dev/null
+++ b/chrome/browser/chromeos/extensions/printing_metrics/printing_metrics_api.cc
@@ -0,0 +1,42 @@
+// 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 "chrome/browser/chromeos/extensions/printing_metrics/printing_metrics_api.h"
+
+#include "chrome/browser/chromeos/extensions/printing_metrics/print_job_info_idl_conversions.h"
+#include "chrome/browser/chromeos/printing/history/print_job_history_service.h"
+#include "chrome/browser/chromeos/printing/history/print_job_history_service_factory.h"
+#include "chrome/common/extensions/api/printing_metrics.h"
+#include "content/public/browser/browser_context.h"
+
+namespace extensions {
+
+PrintingMetricsGetPrintJobsFunction::~PrintingMetricsGetPrintJobsFunction() =
+    default;
+
+ExtensionFunction::ResponseAction PrintingMetricsGetPrintJobsFunction::Run() {
+  chromeos::PrintJobHistoryService* print_job_history_service =
+      chromeos::PrintJobHistoryServiceFactory::GetForBrowserContext(
+          browser_context());
+  print_job_history_service->GetPrintJobs(base::BindOnce(
+      &PrintingMetricsGetPrintJobsFunction::OnPrintJobsRetrieved, this));
+
+  // GetPrintJobs might have already responded.
+  return did_respond() ? AlreadyResponded() : RespondLater();
+}
+
+void PrintingMetricsGetPrintJobsFunction::OnPrintJobsRetrieved(
+    bool success,
+    std::unique_ptr<std::vector<chromeos::printing::proto::PrintJobInfo>>
+        print_job_info_protos) {
+  std::vector<api::printing_metrics::PrintJobInfo> print_job_infos;
+  if (success && print_job_info_protos) {
+    for (const auto& print_job_info_proto : *print_job_info_protos)
+      print_job_infos.push_back(PrintJobInfoProtoToIdl(print_job_info_proto));
+  }
+  Respond(ArgumentList(
+      api::printing_metrics::GetPrintJobs::Results::Create(print_job_infos)));
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/chromeos/extensions/printing_metrics/printing_metrics_api.h b/chrome/browser/chromeos/extensions/printing_metrics/printing_metrics_api.h
new file mode 100644
index 0000000..6db6ffe
--- /dev/null
+++ b/chrome/browser/chromeos/extensions/printing_metrics/printing_metrics_api.h
@@ -0,0 +1,35 @@
+// 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 CHROME_BROWSER_CHROMEOS_EXTENSIONS_PRINTING_METRICS_PRINTING_METRICS_API_H_
+#define CHROME_BROWSER_CHROMEOS_EXTENSIONS_PRINTING_METRICS_PRINTING_METRICS_API_H_
+
+#include <memory>
+#include <vector>
+
+#include "chrome/browser/chromeos/printing/history/print_job_info.pb.h"
+#include "extensions/browser/extension_function.h"
+#include "extensions/browser/extension_function_histogram_value.h"
+
+namespace extensions {
+
+class PrintingMetricsGetPrintJobsFunction : public ExtensionFunction {
+ protected:
+  ~PrintingMetricsGetPrintJobsFunction() override;
+
+  // ExtensionFunction:
+  ResponseAction Run() override;
+
+ private:
+  void OnPrintJobsRetrieved(
+      bool success,
+      std::unique_ptr<std::vector<chromeos::printing::proto::PrintJobInfo>>
+          print_job_info_protos);
+  DECLARE_EXTENSION_FUNCTION("printingMetrics.getPrintJobs",
+                             PRINTINGMETRICS_GETPRINTJOBS)
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_CHROMEOS_EXTENSIONS_PRINTING_METRICS_PRINTING_METRICS_API_H_
diff --git a/chrome/browser/extensions/component_loader.cc b/chrome/browser/extensions/component_loader.cc
index a8d0ed0..8ca1a527 100644
--- a/chrome/browser/extensions/component_loader.cc
+++ b/chrome/browser/extensions/component_loader.cc
@@ -49,6 +49,7 @@
 
 #if defined(OS_CHROMEOS)
 #include "ash/keyboard/ui/grit/keyboard_resources.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "components/user_manager/user_manager.h"
 #include "content/public/browser/site_instance.h"
@@ -541,7 +542,7 @@
 
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
     if (base::FeatureList::IsEnabled(
-            features::kDisableOfficeEditingComponentApp)) {
+            chromeos::features::kDisableOfficeEditingComponentApp)) {
       Add(IDR_QUICKOFFICE_MANIFEST,
           base::FilePath(
               FILE_PATH_LITERAL("/usr/share/chromeos-assets/quickoffice")));
diff --git a/chrome/browser/image_fetcher/BUILD.gn b/chrome/browser/image_fetcher/BUILD.gn
index 0bfd696..9aabc0f 100644
--- a/chrome/browser/image_fetcher/BUILD.gn
+++ b/chrome/browser/image_fetcher/BUILD.gn
@@ -9,7 +9,7 @@
     "//base:base_java",
     "//base:jni_java",
     "//chrome/android/public/profiles:java",
-    "//chrome/lib/util/public/android:java",
+    "//chrome/browser/util/android:java",
     "//content/public/android:content_java",
     "//third_party/gif_player:gif_player_java",
   ]
diff --git a/chrome/browser/image_fetcher/DEPS b/chrome/browser/image_fetcher/DEPS
index 2febd10..f62cb86 100644
--- a/chrome/browser/image_fetcher/DEPS
+++ b/chrome/browser/image_fetcher/DEPS
@@ -2,6 +2,6 @@
   # TODO(crbug/973821): Temporary until profiles is moved to chrome/lib.
   "+chrome/android/public/profiles",
 
-  "+chrome/lib/util/public",
+  "+chrome/browser/util",
   "+content/public/android/java/src/org/chromium/content_public",
 ]
diff --git a/chrome/browser/lookalikes/lookalike_url_interstitial_page.cc b/chrome/browser/lookalikes/lookalike_url_interstitial_page.cc
index bf4cad2..f9efcdca 100644
--- a/chrome/browser/lookalikes/lookalike_url_interstitial_page.cc
+++ b/chrome/browser/lookalikes/lookalike_url_interstitial_page.cc
@@ -87,18 +87,14 @@
   security_interstitials::common_string_util::PopulateDarkModeDisplaySetting(
       load_time_data);
 
-  load_time_data->SetString(
-      "tabTitle",
-      l10n_util::GetStringFUTF16(
-          IDS_LOOKALIKE_URL_TITLE,
-          security_interstitials::common_string_util::GetFormattedHostName(
-              request_url())));
+  const base::string16 hostname =
+      security_interstitials::common_string_util::GetFormattedHostName(
+          request_url());
+  load_time_data->SetString("tabTitle", l10n_util::GetStringFUTF16(
+                                            IDS_LOOKALIKE_URL_TITLE, hostname));
   load_time_data->SetString(
       "heading",
-      l10n_util::GetStringFUTF16(
-          IDS_LOOKALIKE_URL_HEADING,
-          security_interstitials::common_string_util::GetFormattedHostName(
-              request_url())));
+      l10n_util::GetStringFUTF16(IDS_LOOKALIKE_URL_HEADING, hostname));
   load_time_data->SetString(
       "primaryParagraph",
       l10n_util::GetStringUTF16(IDS_LOOKALIKE_URL_PRIMARY_PARAGRAPH));
@@ -106,7 +102,7 @@
       "proceedButtonText", l10n_util::GetStringUTF16(IDS_LOOKALIKE_URL_IGNORE));
   load_time_data->SetString(
       "primaryButtonText",
-      l10n_util::GetStringUTF16(IDS_LOOKALIKE_URL_CONTINUE));
+      l10n_util::GetStringFUTF16(IDS_LOOKALIKE_URL_CONTINUE, hostname));
 }
 
 void LookalikeUrlInterstitialPage::OnInterstitialClosing() {
diff --git a/chrome/browser/net/cookie_policy_browsertest.cc b/chrome/browser/net/cookie_policy_browsertest.cc
index 58a92d8..a647134 100644
--- a/chrome/browser/net/cookie_policy_browsertest.cc
+++ b/chrome/browser/net/cookie_policy_browsertest.cc
@@ -30,11 +30,9 @@
 
 namespace {
 
-// "ServiceWorker" is not handled correctly by content settings with secondary
-// pattern yet.
 const std::vector<std::string> kStorageTypes{
     "Cookie",    "LocalStorage", "FileSystem",   "SessionStorage",
-    "IndexedDb", "WebSql",       "CacheStorage",
+    "IndexedDb", "WebSql",       "CacheStorage", "ServiceWorker",
 };
 
 class CookiePolicyBrowserTest : public InProcessBrowserTest {
diff --git a/chrome/browser/notifications/win/notification_template_builder.cc b/chrome/browser/notifications/win/notification_template_builder.cc
index 043a127..30f5155 100644
--- a/chrome/browser/notifications/win/notification_template_builder.cc
+++ b/chrome/browser/notifications/win/notification_template_builder.cc
@@ -19,6 +19,7 @@
 #include "base/time/time.h"
 #include "chrome/browser/notifications/win/notification_image_retainer.h"
 #include "chrome/browser/notifications/win/notification_launch_id.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/url_formatter/elide_url.h"
@@ -48,6 +49,8 @@
 const char kBindingElementTemplateAttribute[] = "template";
 const char kContent[] = "content";
 const char kContextMenu[] = "contextMenu";
+const char kDuration[] = "duration";
+const char kDurationLong[] = "long";
 const char kForeground[] = "foreground";
 const char kHero[] = "hero";
 const char kHintCrop[] = "hint-crop";
@@ -98,10 +101,16 @@
   xml_writer->StartElement(kNotificationToastElement);
   xml_writer->AddAttribute(kNotificationLaunchAttribute, launch_id.Serialize());
 
-  // Note: If the notification doesn't include a button, then Windows will
-  // ignore the Reminder flag.
-  if (notification.never_timeout())
-    xml_writer->AddAttribute(kScenario, kReminder);
+  if (notification.never_timeout()) {
+    if (base::FeatureList::IsEnabled(
+            features::kNotificationDurationLongForRequireInteraction)) {
+      xml_writer->AddAttribute(kDuration, kDurationLong);
+    } else {
+      // Note: If the notification doesn't include a button, then Windows will
+      // ignore the Reminder flag. See EnsureReminderHasButton below.
+      xml_writer->AddAttribute(kScenario, kReminder);
+    }
+  }
 
   if (notification.timestamp().is_null())
     return;
@@ -315,8 +324,11 @@
 void EnsureReminderHasButton(XmlWriter* xml_writer,
                              const message_center::Notification& notification,
                              NotificationLaunchId copied_launch_id) {
-  if (!notification.never_timeout() || !notification.buttons().empty())
+  if (!notification.never_timeout() || !notification.buttons().empty() ||
+      base::FeatureList::IsEnabled(
+          features::kNotificationDurationLongForRequireInteraction)) {
     return;
+  }
 
   xml_writer->StartElement(kActionElement);
   xml_writer->AddAttribute(kActivationType, kBackground);
diff --git a/chrome/browser/notifications/win/notification_template_builder_unittest.cc b/chrome/browser/notifications/win/notification_template_builder_unittest.cc
index e29c84c..f39fc8a 100644
--- a/chrome/browser/notifications/win/notification_template_builder_unittest.cc
+++ b/chrome/browser/notifications/win/notification_template_builder_unittest.cc
@@ -13,9 +13,11 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "chrome/browser/notifications/win/fake_notification_image_retainer.h"
 #include "chrome/browser/notifications/win/notification_launch_id.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/grit/chromium_strings.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -286,6 +288,32 @@
   ASSERT_NO_FATAL_FAILURE(VerifyXml(notification, kExpectedXml));
 }
 
+TEST_F(NotificationTemplateBuilderTest, RequireInteractionSuppressed) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(
+      features::kNotificationDurationLongForRequireInteraction);
+
+  message_center::Notification notification = BuildNotification();
+  notification.set_never_timeout(true);
+
+  const wchar_t kExpectedXml[] =
+      LR"(<toast launch="0|0|Default|0|https://example.com/|notification_id" duration="long" displayTimestamp="1998-09-04T01:02:03Z">
+ <visual>
+  <binding template="ToastGeneric">
+   <text>My Title</text>
+   <text>My Message</text>
+   <text placement="attribution">example.com</text>
+  </binding>
+ </visual>
+ <actions>
+  <action content="settings" placement="contextMenu" activationType="foreground" arguments="2|0|Default|0|https://example.com/|notification_id"/>
+ </actions>
+</toast>
+)";
+
+  ASSERT_NO_FATAL_FAILURE(VerifyXml(notification, kExpectedXml));
+}
+
 TEST_F(NotificationTemplateBuilderTest, NullTimestamp) {
   message_center::Notification notification = BuildNotification();
   notification.set_timestamp(base::Time());
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index e1ad4504..fffe15dc 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -391,6 +391,9 @@
   { key::kSpellcheckEnabled,
     spellcheck::prefs::kSpellCheckEnable,
     base::Value::Type::BOOLEAN },
+  { key::kSharedClipboardEnabled,
+    prefs::kSharedClipboardEnabled,
+    base::Value::Type::BOOLEAN },
 
   // First run import.
   { key::kImportBookmarks,
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index 24eaf8f..63420e8 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -5799,4 +5799,22 @@
   EXPECT_EQ("true", message);
 }
 
+class SharedClipboardPolicyTest : public PolicyTest {
+  void SetUpInProcessBrowserTestFixture() override {
+    PolicyTest::SetUpInProcessBrowserTestFixture();
+    PolicyMap policies;
+    policies.Set(policy::key::kSharedClipboardEnabled,
+                 policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
+                 policy::POLICY_SOURCE_CLOUD,
+                 std::make_unique<base::Value>(true), nullptr);
+    provider_.UpdateChromePolicy(policies);
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(SharedClipboardPolicyTest, SharedClipboardEnabled) {
+  PrefService* prefs = browser()->profile()->GetPrefs();
+  EXPECT_TRUE(prefs->IsManagedPreference(prefs::kSharedClipboardEnabled));
+  EXPECT_TRUE(prefs->GetBoolean(prefs::kSharedClipboardEnabled));
+}
+
 }  // namespace policy
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
index 9ee30cf..0b06d08 100644
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -111,6 +111,7 @@
 #include "chrome/browser/chromeos/android_sms/android_sms_service_factory.h"
 #include "chrome/browser/chromeos/crostini/crostini_registry_service_factory.h"
 #include "chrome/browser/chromeos/extensions/login_screen/login_state/session_state_changed_event_dispatcher.h"
+#include "chrome/browser/chromeos/extensions/printing_metrics/print_job_finished_event_dispatcher.h"
 #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.h"
 #include "chrome/browser/chromeos/plugin_vm/plugin_vm_engagement_metrics_service.h"
 #include "chrome/browser/chromeos/policy/policy_cert_service_factory.h"
@@ -279,6 +280,7 @@
   chromeos::smb_client::SmbServiceFactory::GetInstance();
   crostini::CrostiniRegistryServiceFactory::GetInstance();
   extensions::SessionStateChangedEventDispatcher::GetFactoryInstance();
+  extensions::PrintJobFinishedEventDispatcher::GetFactoryInstance();
   extensions::VerifyTrustAPI::GetFactoryInstance();
   TetherServiceFactory::GetInstance();
 #if defined(USE_CUPS)
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/shared_style.html b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/shared_style.html
index 2c4276f..72cf396a 100644
--- a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/shared_style.html
+++ b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/shared_style.html
@@ -80,9 +80,14 @@
       }
 
       .subpermission-row {
+        border-top: var(--card-separator);
         height: 48px;
       }
 
+      .subpermission-row:first-of-type {
+        border-top: none;
+      }
+
       .secondary-text {
         color: var(--secondary-text-color);
         font-weight: var(--secondary-font-weight);
diff --git a/chrome/browser/resources/settings/people_page/users_add_user_dialog.html b/chrome/browser/resources/settings/people_page/users_add_user_dialog.html
index 1fea196..cbcbc0b2 100644
--- a/chrome/browser/resources/settings/people_page/users_add_user_dialog.html
+++ b/chrome/browser/resources/settings/people_page/users_add_user_dialog.html
@@ -13,17 +13,14 @@
       cr-dialog::part(dialog) {
         width: 320px;
       }
-
-      cr-input {
-        --cr-input-error-display: none;
-      }
     </style>
     <cr-dialog id="dialog" close-text="$i18n{close}">
       <div slot="title">$i18n{addUsers}</div>
       <div slot="body">
         <cr-input id="addUserInput" label="$i18n{addUsersEmail}"
-            invalid="[[shouldShowError_(isEmail_, isEmpty_)]]"
-            on-value-changed="onInput_" autofocus>
+            invalid="[[shouldShowError_(errorCode_)]]"
+            on-value-changed="onInput_"
+            error-message="[[getErrorString_(errorCode_)]]" autofocus>
         </cr-input>
       </div>
       <div slot="button-container">
diff --git a/chrome/browser/resources/settings/people_page/users_add_user_dialog.js b/chrome/browser/resources/settings/people_page/users_add_user_dialog.js
index 37210248..a68a908 100644
--- a/chrome/browser/resources/settings/people_page/users_add_user_dialog.js
+++ b/chrome/browser/resources/settings/people_page/users_add_user_dialog.js
@@ -29,11 +29,26 @@
     '^\\s*([\\w\\.!#\\$%&\'\\*\\+-\\/=\\?\\^`\\{\\|\\}~]+)@' +
     '([A-Za-z0-9\-]{2,63}\\..+)\\s*$');
 
+/** @enum {number} */
+const UserAddError = {
+  NO_ERROR: 0,
+  INVALID_EMAIL: 1,
+  USER_EXISTS: 2,
+};
+
 Polymer({
   is: 'settings-users-add-user-dialog',
 
+  behaviors: [I18nBehavior],
+
   properties: {
     /** @private */
+    errorCode_: {
+      type: Number,
+      value: UserAddError.NO_ERROR,
+    },
+
+    /** @private */
     isEmail_: {
       type: Boolean,
       value: false,
@@ -46,6 +61,8 @@
     },
   },
 
+  usersPrivate_: chrome.usersPrivate,
+
   open: function() {
     this.$.addUserInput.value = '';
     this.onInput_();
@@ -74,11 +91,20 @@
       userEmail = emailMatches[1] + '@' + emailMatches[2];
     }
 
-    chrome.usersPrivate.addWhitelistedUser(
-        userEmail,
-        /* callback */ function(success) {});
-    this.$.addUserInput.value = '';
-    this.$.dialog.close();
+    this.usersPrivate_.isWhitelistedUser(userEmail, doesUserExist => {
+      if (doesUserExist) {
+        // This user email had been saved previously
+        this.errorCode_ = UserAddError.USER_EXISTS;
+        return;
+      }
+
+      this.$.dialog.close();
+      this.usersPrivate_.addWhitelistedUser(
+          userEmail,
+          /* callback */ function(success) {});
+
+      this.$.addUserInput.value = '';
+    });
   },
 
   /**
@@ -99,6 +125,13 @@
     const input = this.$.addUserInput.value;
     this.isEmail_ = NAME_ONLY_REGEX.test(input) || EMAIL_REGEX.test(input);
     this.isEmpty_ = input.length == 0;
+
+    if (!this.isEmail_ && !this.isEmpty_) {
+      this.errorCode_ = UserAddError.INVALID_EMAIL;
+      return;
+    }
+
+    this.errorCode_ = UserAddError.NO_ERROR;
   },
 
   /**
@@ -106,7 +139,20 @@
    * @return {boolean}
    */
   shouldShowError_: function() {
-    return !this.isEmail_ && !this.isEmpty_;
+    return this.errorCode_ != UserAddError.NO_ERROR;
+  },
+
+  /**
+   * @private
+   * @return {string}
+   */
+  getErrorString_: function(errorCode_) {
+    if (errorCode_ == UserAddError.USER_EXISTS) {
+      return this.i18n('userExistsError');
+    }
+    //TODO errorString for UserAddError.INVALID_EMAIL crbug/1007481
+
+    return '';
   },
 });
 
diff --git a/chrome/browser/sharing/OWNERS b/chrome/browser/sharing/OWNERS
index 89fac4c..17dcb10e6 100644
--- a/chrome/browser/sharing/OWNERS
+++ b/chrome/browser/sharing/OWNERS
@@ -1,3 +1,4 @@
+alexchau@chromium.org
 knollr@chromium.org
 mvanouwerkerk@chromium.org
 peter@chromium.org
diff --git a/chrome/browser/sharing/shared_clipboard/shared_clipboard_utils.cc b/chrome/browser/sharing/shared_clipboard/shared_clipboard_utils.cc
index 3afa77a1..1087e090 100644
--- a/chrome/browser/sharing/shared_clipboard/shared_clipboard_utils.cc
+++ b/chrome/browser/sharing/shared_clipboard/shared_clipboard_utils.cc
@@ -4,13 +4,23 @@
 
 #include "chrome/browser/sharing/shared_clipboard/shared_clipboard_utils.h"
 
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sharing/shared_clipboard/feature_flags.h"
 #include "chrome/browser/sharing/sharing_service.h"
 #include "chrome/browser/sharing/sharing_service_factory.h"
+#include "chrome/common/pref_names.h"
+#include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_context.h"
 
 bool ShouldOfferSharedClipboard(content::BrowserContext* browser_context,
                                 const base::string16& text) {
+  // Check Chrome enterprise policy for Shared Clipboard.
+  Profile* profile = Profile::FromBrowserContext(browser_context);
+  if (profile &&
+      !profile->GetPrefs()->GetBoolean(prefs::kSharedClipboardEnabled)) {
+    return false;
+  }
+
   SharingService* sharing_service =
       SharingServiceFactory::GetForBrowserContext(browser_context);
   return sharing_service && base::FeatureList::IsEnabled(kSharedClipboardUI) &&
diff --git a/chrome/browser/sharing/shared_clipboard/shared_clipboard_utils_unittest.cc b/chrome/browser/sharing/shared_clipboard/shared_clipboard_utils_unittest.cc
index bc7f3a5..312c313 100644
--- a/chrome/browser/sharing/shared_clipboard/shared_clipboard_utils_unittest.cc
+++ b/chrome/browser/sharing/shared_clipboard/shared_clipboard_utils_unittest.cc
@@ -16,7 +16,9 @@
 #include "chrome/browser/sharing/sharing_service_factory.h"
 #include "chrome/browser/sharing/sharing_sync_preference.h"
 #include "chrome/browser/sharing/vapid_key_manager.h"
+#include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
+#include "components/prefs/pref_service.h"
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -115,3 +117,11 @@
   EXPECT_FALSE(
       ShouldOfferSharedClipboard(&profile_, base::ASCIIToUTF16(kText)));
 }
+
+TEST_F(SharedClipboardUtilsTest, EnterprisePolicy_Disabled) {
+  scoped_feature_list_.InitAndEnableFeature(kSharedClipboardUI);
+  // Set the enterprise policy to false:
+  profile_.GetPrefs()->SetBoolean(prefs::kSharedClipboardEnabled, false);
+  EXPECT_FALSE(
+      ShouldOfferSharedClipboard(&profile_, base::ASCIIToUTF16(kText)));
+}
diff --git a/chrome/browser/sync/sessions/sync_sessions_web_contents_router_factory.h b/chrome/browser/sync/sessions/sync_sessions_web_contents_router_factory.h
index 23471f4..8f8ec5d 100644
--- a/chrome/browser/sync/sessions/sync_sessions_web_contents_router_factory.h
+++ b/chrome/browser/sync/sessions/sync_sessions_web_contents_router_factory.h
@@ -29,10 +29,6 @@
   // Get the singleton instance of the factory.
   static SyncSessionsWebContentsRouterFactory* GetInstance();
 
-  // Creates a SyncSessionsWebContentsRouter service for |context|.
-  static SyncSessionsWebContentsRouter* BuildSyncSessionsWebContentsRouter(
-      content::BrowserContext* context);
-
  private:
   friend struct base::DefaultSingletonTraits<
       SyncSessionsWebContentsRouterFactory>;
diff --git a/chrome/browser/translate/translate_fake_page.cc b/chrome/browser/translate/translate_fake_page.cc
index 7c558291..c2c4d0c 100644
--- a/chrome/browser/translate/translate_fake_page.cc
+++ b/chrome/browser/translate/translate_fake_page.cc
@@ -33,21 +33,17 @@
 #include "content/public/common/url_constants.h"
 #include "content/public/test/navigation_simulator.h"
 #include "content/public/test/test_renderer_host.h"
-#include "mojo/public/cpp/bindings/binding.h"
 #include "url/gurl.h"
 
 FakePageImpl::FakePageImpl()
-    : called_translate_(false),
-      called_revert_translation_(false),
-      binding_(this) {}
+    : called_translate_(false), called_revert_translation_(false) {}
 FakePageImpl::~FakePageImpl() {}
 
-translate::mojom::PagePtr FakePageImpl::BindToNewPagePtr() {
-  binding_.Close();
+mojo::PendingRemote<translate::mojom::Page>
+FakePageImpl::BindToNewPageRemote() {
+  receiver_.reset();
   translate_callback_pending_.Reset();
-  translate::mojom::PagePtr page;
-  binding_.Bind(mojo::MakeRequest(&page));
-  return page;
+  return receiver_.BindNewPipeAndPassRemote();
 }
 
 // translate::mojom::Page implementation.
diff --git a/chrome/browser/translate/translate_fake_page.h b/chrome/browser/translate/translate_fake_page.h
index 41e7b42..668c7068 100644
--- a/chrome/browser/translate/translate_fake_page.h
+++ b/chrome/browser/translate/translate_fake_page.h
@@ -36,7 +36,8 @@
 #include "content/public/common/url_constants.h"
 #include "content/public/test/navigation_simulator.h"
 #include "content/public/test/test_renderer_host.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "url/gurl.h"
 
 class FakePageImpl : public translate::mojom::Page {
@@ -44,7 +45,7 @@
   FakePageImpl();
   ~FakePageImpl() override;
 
-  translate::mojom::PagePtr BindToNewPagePtr();
+  mojo::PendingRemote<translate::mojom::Page> BindToNewPageRemote();
 
   // translate::mojom::Page implementation.
   void Translate(
@@ -68,7 +69,7 @@
 
  private:
   TranslateCallback translate_callback_pending_;
-  mojo::Binding<translate::mojom::Page> binding_;
+  mojo::Receiver<translate::mojom::Page> receiver_{this};
   DISALLOW_COPY_AND_ASSIGN(FakePageImpl);
 };
 
diff --git a/chrome/browser/translate/translate_manager_render_view_host_android_unittest.cc b/chrome/browser/translate/translate_manager_render_view_host_android_unittest.cc
index 93ba658..7ad4d68 100644
--- a/chrome/browser/translate/translate_manager_render_view_host_android_unittest.cc
+++ b/chrome/browser/translate/translate_manager_render_view_host_android_unittest.cc
@@ -56,7 +56,7 @@
     details.adopted_language = lang;
     ChromeTranslateClient::FromWebContents(web_contents())
         ->translate_driver()
-        ->RegisterPage(fake_page_.BindToNewPagePtr(), details,
+        ->RegisterPage(fake_page_.BindToNewPageRemote(), details,
                        page_translatable);
   }
 
diff --git a/chrome/browser/translate/translate_manager_render_view_host_unittest.cc b/chrome/browser/translate/translate_manager_render_view_host_unittest.cc
index 2300bce..c68ecde 100644
--- a/chrome/browser/translate/translate_manager_render_view_host_unittest.cc
+++ b/chrome/browser/translate/translate_manager_render_view_host_unittest.cc
@@ -251,7 +251,7 @@
     details.adopted_language = lang;
     ChromeTranslateClient::FromWebContents(web_contents())
         ->translate_driver()
-        ->RegisterPage(fake_page_.BindToNewPagePtr(), details,
+        ->RegisterPage(fake_page_.BindToNewPageRemote(), details,
                        page_translatable);
   }
 
diff --git a/chrome/browser/ui/app_list/search/search_utils/fuzzy_tokenized_string_match.cc b/chrome/browser/ui/app_list/search/search_utils/fuzzy_tokenized_string_match.cc
index dc3678064..0493cc6 100644
--- a/chrome/browser/ui/app_list/search/search_utils/fuzzy_tokenized_string_match.cc
+++ b/chrome/browser/ui/app_list/search/search_utils/fuzzy_tokenized_string_match.cc
@@ -3,6 +3,12 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/ui/app_list/search/search_utils/fuzzy_tokenized_string_match.h"
+
+#include <algorithm>
+#include <iterator>
+
+#include "base/strings/strcat.h"
+#include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/ui/app_list/search/search_utils/sequence_matcher.h"
 
@@ -11,83 +17,156 @@
 namespace {
 const double kRelevanceThreshold = 0.6;
 
-double PartialRatio(const TokenizedString& query,
-                    const TokenizedString& text,
-                    SequenceMatcher& sequence_matcher) {
-  // TODO(crbug.com/990684): implement the logic of this function.
-  return 0.0;
+// Returns sorted tokens from a TokenizedString.
+std::vector<base::string16> ProcessAndSort(const TokenizedString& text) {
+  std::vector<base::string16> result;
+  for (const auto& token : text.tokens()) {
+    result.emplace_back(token);
+  }
+  std::sort(result.begin(), result.end());
+  return result;
+}
+}  // namespace
+
+FuzzyTokenizedStringMatch::~FuzzyTokenizedStringMatch() {}
+FuzzyTokenizedStringMatch::FuzzyTokenizedStringMatch() {}
+
+double FuzzyTokenizedStringMatch::TokenSetRatio(const TokenizedString& query,
+                                                const TokenizedString& text,
+                                                bool partial) {
+  std::set<base::string16> query_token(query.tokens().begin(),
+                                       query.tokens().end());
+  std::set<base::string16> text_token(text.tokens().begin(),
+                                      text.tokens().end());
+
+  std::vector<base::string16> intersection;
+  std::vector<base::string16> query_diff_text;
+  std::vector<base::string16> text_diff_query;
+
+  // Find the intersection and the differences between two set of tokens.
+  std::set_intersection(query_token.begin(), query_token.end(),
+                        text_token.begin(), text_token.end(),
+                        std::back_inserter(intersection));
+  std::set_difference(query_token.begin(), query_token.end(),
+                      text_token.begin(), text_token.end(),
+                      std::back_inserter(query_diff_text));
+  std::set_difference(text_token.begin(), text_token.end(), query_token.begin(),
+                      query_token.end(), std::back_inserter(text_diff_query));
+
+  const base::string16 intersection_string =
+      base::JoinString(intersection, base::UTF8ToUTF16(" "));
+  const base::string16 query_rewritten =
+      intersection.empty()
+          ? base::JoinString(query_diff_text, base::UTF8ToUTF16(" "))
+          : base::StrCat(
+                {intersection_string, base::UTF8ToUTF16(" "),
+                 base::JoinString(query_diff_text, base::UTF8ToUTF16(" "))});
+  const base::string16 text_rewritten =
+      intersection.empty()
+          ? base::JoinString(text_diff_query, base::UTF8ToUTF16(" "))
+          : base::StrCat(
+                {intersection_string, base::UTF8ToUTF16(" "),
+                 base::JoinString(text_diff_query, base::UTF8ToUTF16(" "))});
+
+  if (partial) {
+    return std::max({PartialRatio(intersection_string, query_rewritten),
+                     PartialRatio(intersection_string, text_rewritten),
+                     PartialRatio(query_rewritten, text_rewritten)});
+  }
+
+  return std::max({SequenceMatcher(intersection_string, query_rewritten)
+                       .Ratio(false /*use_edit_distance*/),
+                   SequenceMatcher(intersection_string, text_rewritten)
+                       .Ratio(false /*use_edit_distance*/),
+                   SequenceMatcher(query_rewritten, text_rewritten)
+                       .Ratio(false /*use_edit_distance*/)});
 }
 
-double PartialTokenSetRatio(const TokenizedString& query,
-                            const TokenizedString& text,
-                            SequenceMatcher& sequence_matcher) {
-  // TODO(crbug.com/990684): implement the logic of this function.
-  return 0.0;
+double FuzzyTokenizedStringMatch::TokenSortRatio(const TokenizedString& query,
+                                                 const TokenizedString& text,
+                                                 bool partial) {
+  const base::string16 query_sorted =
+      base::JoinString(ProcessAndSort(query), base::UTF8ToUTF16(" "));
+  const base::string16 text_sorted =
+      base::JoinString(ProcessAndSort(text), base::UTF8ToUTF16(" "));
+
+  if (partial) {
+    return PartialRatio(query_sorted, text_sorted);
+  }
+  return SequenceMatcher(query_sorted, text_sorted)
+      .Ratio(false /*use_edit_distance*/);
 }
 
-double PartialTokenSortRatio(const TokenizedString& query,
-                             const TokenizedString& text,
-                             SequenceMatcher& sequence_matcher) {
-  // TODO(crbug.com/990684): implement the logic of this function.
-  return 0.0;
+double FuzzyTokenizedStringMatch::PartialRatio(const base::string16& query,
+                                               const base::string16& text) {
+  if (query.empty() || text.empty()) {
+    return 0.0;
+  }
+  base::string16 shorter = query;
+  base::string16 longer = text;
+
+  if (shorter.size() > longer.size()) {
+    shorter = text;
+    longer = query;
+  }
+
+  const auto matching_blocks =
+      SequenceMatcher(shorter, longer).GetMatchingBlocks();
+  double partial_ratio = 0;
+
+  for (const auto& block : matching_blocks) {
+    const int long_start =
+        block.pos_second_string > block.pos_first_string
+            ? block.pos_second_string - block.pos_first_string
+            : 0;
+
+    // TODO(crbug/990684): currently this part re-calculate the ratio for every
+    // pair. Improve this to reduce latency.
+    partial_ratio = std::max(
+        partial_ratio,
+        SequenceMatcher(shorter, longer.substr(long_start, shorter.size()))
+            .Ratio(false /*use_edit_distance*/));
+    if (partial_ratio > 0.995) {
+      return 1;
+    }
+  }
+  return partial_ratio;
 }
 
-double TokenSortRatio(const TokenizedString& query,
-                      const TokenizedString& text,
-                      SequenceMatcher& sequence_matcher) {
-  // TODO(crbug.com/990684): implement the logic of this function.
-  return 0.0;
-}
-
-double TokenSetRatio(const TokenizedString& query,
-                     const TokenizedString& text,
-                     SequenceMatcher& sequence_matcher) {
-  // TODO(crbug.com/990684): implement the logic of this function.
-  return 0.0;
-}
-
-double WeightedRatio(const TokenizedString& query,
-                     const TokenizedString& text,
-                     SequenceMatcher& sequence_matcher) {
+double FuzzyTokenizedStringMatch::WeightedRatio(const TokenizedString& query,
+                                                const TokenizedString& text) {
   const double unbase_scale = 0.95;
-  double weighted_ratio = sequence_matcher.Ratio();
+  double weighted_ratio = SequenceMatcher(query.text(), text.text())
+                              .Ratio(false /*use_edit_distance*/);
   const double length_ratio =
       static_cast<double>(std::max(query.text().size(), text.text().size())) /
       std::min(query.text().size(), text.text().size());
 
   // Use partial if two strings are quite different in sizes.
-  if (length_ratio >= 1.5) {
+  const bool use_partial = length_ratio >= 1.5;
+  double partial_scale = 1;
+
+  if (use_partial) {
     // If one string is much much shorter than the other, set |partial_scale| to
     // be 0.6, otherwise set it to be 0.9.
-    const double partial_scale = length_ratio > 8 ? 0.6 : 0.9;
+    partial_scale = length_ratio > 8 ? 0.6 : 0.9;
     weighted_ratio =
         std::max(weighted_ratio,
-                 PartialRatio(query, text, sequence_matcher) * partial_scale);
-    weighted_ratio = std::max(
-        weighted_ratio, PartialTokenSortRatio(query, text, sequence_matcher) *
-                            unbase_scale * partial_scale);
-    weighted_ratio = std::max(
-        weighted_ratio, PartialTokenSetRatio(query, text, sequence_matcher) *
-                            unbase_scale * partial_scale);
-    return weighted_ratio;
+                 PartialRatio(query.text(), text.text()) * partial_scale);
   }
-  // If strings are similar length, don't use partial.
-  weighted_ratio =
-      std::max(weighted_ratio,
-               TokenSortRatio(query, text, sequence_matcher) * unbase_scale);
-  weighted_ratio =
-      std::max(weighted_ratio,
-               TokenSetRatio(query, text, sequence_matcher) * unbase_scale);
+  weighted_ratio = std::max(
+      weighted_ratio, TokenSortRatio(query, text, /*partial=*/use_partial) *
+                          unbase_scale * partial_scale);
+  weighted_ratio = std::max(
+      weighted_ratio, TokenSetRatio(query, text, /*partial=*/use_partial) *
+                          unbase_scale * partial_scale);
   return weighted_ratio;
 }
-}  // namespace
 
 bool FuzzyTokenizedStringMatch::IsRelevant(const TokenizedString& query,
                                            const TokenizedString& text) {
   // TODO(crbug.com/990684): add prefix matching logic.
-  SequenceMatcher sequence_matcher(base::UTF16ToUTF8(query.text()),
-                                   base::UTF16ToUTF8(text.text()));
-  relevance_ = WeightedRatio(query, text, sequence_matcher);
+  relevance_ = WeightedRatio(query, text);
   return relevance_ > kRelevanceThreshold;
 }
 
diff --git a/chrome/browser/ui/app_list/search/search_utils/fuzzy_tokenized_string_match.h b/chrome/browser/ui/app_list/search/search_utils/fuzzy_tokenized_string_match.h
index 9e173aa7..4a6192a 100644
--- a/chrome/browser/ui/app_list/search/search_utils/fuzzy_tokenized_string_match.h
+++ b/chrome/browser/ui/app_list/search/search_utils/fuzzy_tokenized_string_match.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_UI_APP_LIST_SEARCH_SEARCH_UTILS_FUZZY_TOKENIZED_STRING_MATCH_H_
 
 #include "ash/public/cpp/app_list/tokenized_string.h"
+#include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "ui/gfx/range/range.h"
 
@@ -32,6 +33,33 @@
   double relevance() const { return relevance_; }
 
  private:
+  FRIEND_TEST_ALL_PREFIXES(FuzzyTokenizedStringMatchTest, PartialRatioTest);
+  FRIEND_TEST_ALL_PREFIXES(FuzzyTokenizedStringMatchTest, TokenSetRatioTest);
+  FRIEND_TEST_ALL_PREFIXES(FuzzyTokenizedStringMatchTest, TokenSortRatioTest);
+  FRIEND_TEST_ALL_PREFIXES(FuzzyTokenizedStringMatchTest, WeightedRatio);
+  // Finds the best ratio of shorter text with a part of longer text.
+  // This function assumes that TokenizedString is already normalized (converted
+  // to lower case). The return score is in range of [0, 1].
+  double PartialRatio(const base::string16& query, const base::string16& text);
+  // TokenSetRatio takes two sets of tokens, finds their intersection and
+  // differences. From the intersection and differences, it rewrites the |query|
+  // and |text| and find the similarity ratio between them. This function
+  // assumes that TokenizedString is already normalized (converted to lower
+  // case). Duplicates tokens will be removed for ratio computation.
+  double TokenSetRatio(const TokenizedString& query,
+                       const TokenizedString& text,
+                       bool partial);
+  // TokenSortRatio takes two set of tokens, sorts them and find the similarity
+  // between two sorted strings. This function assumes that TokenizedString is
+  // already normalized (converted to lower case)
+  double TokenSortRatio(const TokenizedString& query,
+                        const TokenizedString& text,
+                        bool partial);
+  // Combines scores from different ratio functions. This function assumes that
+  // TokenizedString is already normalized (converted to lower cases).
+  // The return score is in range of [0, 1].
+  double WeightedRatio(const TokenizedString& query,
+                       const TokenizedString& text);
   // Score in range of [0,1] representing how well the query matches the text.
   double relevance_ = 0;
   Hits hits_;
diff --git a/chrome/browser/ui/app_list/search/search_utils/fuzzy_tokenized_string_match_unittest.cc b/chrome/browser/ui/app_list/search/search_utils/fuzzy_tokenized_string_match_unittest.cc
new file mode 100644
index 0000000..eb7cdef
--- /dev/null
+++ b/chrome/browser/ui/app_list/search/search_utils/fuzzy_tokenized_string_match_unittest.cc
@@ -0,0 +1,147 @@
+// Copyright (c) 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 "chrome/browser/ui/app_list/search/search_utils/fuzzy_tokenized_string_match.h"
+
+#include "ash/public/cpp/app_list/tokenized_string.h"
+#include "base/macros.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/ui/app_list/search/search_utils/sequence_matcher.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace app_list {
+
+class FuzzyTokenizedStringMatchTest : public testing::Test {};
+
+TEST_F(FuzzyTokenizedStringMatchTest, PartialRatioTest) {
+  FuzzyTokenizedStringMatch match;
+  EXPECT_EQ(match.PartialRatio(base::UTF8ToUTF16("abcde"),
+                               base::UTF8ToUTF16("ababcXXXbcdeY")),
+            0.8);
+  EXPECT_NEAR(match.PartialRatio(base::UTF8ToUTF16("big string"),
+                                 base::UTF8ToUTF16("strength")),
+              0.71, 0.01);
+  EXPECT_EQ(match.PartialRatio(base::UTF8ToUTF16("abc"), base::UTF8ToUTF16("")),
+            0);
+  EXPECT_NEAR(match.PartialRatio(base::UTF8ToUTF16("different in order"),
+                                 base::UTF8ToUTF16("order text")),
+              0.67, 0.01);
+}
+
+TEST_F(FuzzyTokenizedStringMatchTest, TokenSetRatioTest) {
+  FuzzyTokenizedStringMatch match;
+  {
+    base::string16 query(base::UTF8ToUTF16("order different in"));
+    base::string16 text(base::UTF8ToUTF16("text order"));
+    EXPECT_EQ(match.TokenSetRatio(TokenizedString(query), TokenizedString(text),
+                                  true),
+              1);
+    EXPECT_NEAR(match.TokenSetRatio(TokenizedString(query),
+                                    TokenizedString(text), false),
+                0.67, 0.01);
+  }
+  {
+    base::string16 query(base::UTF8ToUTF16("short text"));
+    base::string16 text(
+        base::UTF8ToUTF16("this text is really really really long"));
+    EXPECT_EQ(match.TokenSetRatio(TokenizedString(query), TokenizedString(text),
+                                  true),
+              1);
+    EXPECT_NEAR(match.TokenSetRatio(TokenizedString(query),
+                                    TokenizedString(text), false),
+                0.57, 0.01);
+  }
+  {
+    base::string16 query(base::UTF8ToUTF16("common string"));
+    base::string16 text(base::UTF8ToUTF16("nothing is shared"));
+    EXPECT_NEAR(match.TokenSetRatio(TokenizedString(query),
+                                    TokenizedString(text), true),
+                0.38, 0.01);
+    EXPECT_NEAR(match.TokenSetRatio(TokenizedString(query),
+                                    TokenizedString(text), false),
+                0.33, 0.01);
+  }
+  {
+    base::string16 query(
+        base::UTF8ToUTF16("token shared token same shared same"));
+    base::string16 text(base::UTF8ToUTF16("token shared token text text long"));
+    EXPECT_EQ(match.TokenSetRatio(TokenizedString(query), TokenizedString(text),
+                                  true),
+              1);
+    EXPECT_NEAR(match.TokenSetRatio(TokenizedString(query),
+                                    TokenizedString(text), false),
+                0.83, 0.01);
+  }
+}
+
+TEST_F(FuzzyTokenizedStringMatchTest, TokenSortRatioTest) {
+  FuzzyTokenizedStringMatch match;
+  {
+    base::string16 query(base::UTF8ToUTF16("order different in"));
+    base::string16 text(base::UTF8ToUTF16("text order"));
+    EXPECT_NEAR(match.TokenSortRatio(TokenizedString(query),
+                                     TokenizedString(text), true),
+                0.67, 0.01);
+    EXPECT_NEAR(match.TokenSortRatio(TokenizedString(query),
+                                     TokenizedString(text), false),
+                0.36, 0.01);
+  }
+  {
+    base::string16 query(base::UTF8ToUTF16("short text"));
+    base::string16 text(
+        base::UTF8ToUTF16("this text is really really really long"));
+    EXPECT_EQ(match.TokenSortRatio(TokenizedString(query),
+                                   TokenizedString(text), true),
+              0.5);
+    EXPECT_NEAR(match.TokenSortRatio(TokenizedString(query),
+                                     TokenizedString(text), false),
+                0.33, 0.01);
+  }
+  {
+    base::string16 query(base::UTF8ToUTF16("common string"));
+    base::string16 text(base::UTF8ToUTF16("nothing is shared"));
+    EXPECT_NEAR(match.TokenSortRatio(TokenizedString(query),
+                                     TokenizedString(text), true),
+                0.38, 0.01);
+    EXPECT_NEAR(match.TokenSortRatio(TokenizedString(query),
+                                     TokenizedString(text), false),
+                0.33, 0.01);
+  }
+}
+
+TEST_F(FuzzyTokenizedStringMatchTest, WeightedRatio) {
+  FuzzyTokenizedStringMatch match;
+  {
+    base::string16 query(base::UTF8ToUTF16("anonymous"));
+    base::string16 text(base::UTF8ToUTF16("famous"));
+    EXPECT_NEAR(
+        match.WeightedRatio(TokenizedString(query), TokenizedString(text)),
+        0.67, 0.01);
+  }
+  {
+    base::string16 query(base::UTF8ToUTF16("clash of clan"));
+    base::string16 text(base::UTF8ToUTF16("clash of titan"));
+    EXPECT_NEAR(
+        match.WeightedRatio(TokenizedString(query), TokenizedString(text)),
+        0.81, 0.01);
+  }
+  {
+    base::string16 query(base::UTF8ToUTF16("final fantasy"));
+    base::string16 text(base::UTF8ToUTF16("finalfantasy"));
+    EXPECT_NEAR(
+        match.WeightedRatio(TokenizedString(query), TokenizedString(text)),
+        0.96, 0.01);
+  }
+  {
+    base::string16 query(base::UTF8ToUTF16("short text"));
+    base::string16 text(
+        base::UTF8ToUTF16("this sentence is much much much much much longer "
+                          "than the text before"));
+    EXPECT_NEAR(
+        match.WeightedRatio(TokenizedString(query), TokenizedString(text)),
+        0.85, 0.01);
+  }
+}
+}  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/search_utils/sequence_matcher.cc b/chrome/browser/ui/app_list/search/search_utils/sequence_matcher.cc
index 46a6444b..3f415f2 100644
--- a/chrome/browser/ui/app_list/search/search_utils/sequence_matcher.cc
+++ b/chrome/browser/ui/app_list/search/search_utils/sequence_matcher.cc
@@ -26,8 +26,8 @@
   DCHECK_GE(length, 0);
 }
 
-SequenceMatcher::SequenceMatcher(const std::string& first_string,
-                                 const std::string& second_string)
+SequenceMatcher::SequenceMatcher(const base::string16& first_string,
+                                 const base::string16& second_string)
     : first_string_(first_string),
       second_string_(second_string),
       dp_common_string_(second_string.size() + 1, 0) {
diff --git a/chrome/browser/ui/app_list/search/search_utils/sequence_matcher.h b/chrome/browser/ui/app_list/search/search_utils/sequence_matcher.h
index 5233721..5c3d106 100644
--- a/chrome/browser/ui/app_list/search/search_utils/sequence_matcher.h
+++ b/chrome/browser/ui/app_list/search/search_utils/sequence_matcher.h
@@ -31,8 +31,8 @@
     // Length of the common substring.
     int length;
   };
-  SequenceMatcher(const std::string& first_string,
-                  const std::string& second_string);
+  SequenceMatcher(const base::string16& first_string,
+                  const base::string16& second_string);
 
   ~SequenceMatcher() = default;
 
@@ -59,8 +59,8 @@
   std::vector<Match> GetMatchingBlocks();
 
  private:
-  std::string first_string_;
-  std::string second_string_;
+  base::string16 first_string_;
+  base::string16 second_string_;
   double edit_distance_ratio_ = -1.0;
   double block_matching_ratio_ = -1.0;
   std::vector<Match> matching_blocks_;
diff --git a/chrome/browser/ui/app_list/search/search_utils/sequence_matcher_unittest.cc b/chrome/browser/ui/app_list/search/search_utils/sequence_matcher_unittest.cc
index 9036f2e..aab91dfd 100644
--- a/chrome/browser/ui/app_list/search/search_utils/sequence_matcher_unittest.cc
+++ b/chrome/browser/ui/app_list/search/search_utils/sequence_matcher_unittest.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/app_list/search/search_utils/sequence_matcher.h"
 
 #include "base/macros.h"
+#include "base/strings/utf_string_conversions.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -23,45 +24,72 @@
 
 TEST_F(SequenceMatcherTest, TestEditDistance) {
   // Transposition
-  ASSERT_EQ(SequenceMatcher("abcd", "abdc").EditDistance(), 1);
+  ASSERT_EQ(
+      SequenceMatcher(base::UTF8ToUTF16("abcd"), base::UTF8ToUTF16("abdc"))
+          .EditDistance(),
+      1);
 
   // Deletion
-  ASSERT_EQ(SequenceMatcher("abcde", "abcd").EditDistance(), 1);
-  ASSERT_EQ(SequenceMatcher("12", "").EditDistance(), 2);
+  ASSERT_EQ(
+      SequenceMatcher(base::UTF8ToUTF16("abcde"), base::UTF8ToUTF16("abcd"))
+          .EditDistance(),
+      1);
+  ASSERT_EQ(SequenceMatcher(base::UTF8ToUTF16("12"), base::UTF8ToUTF16(""))
+                .EditDistance(),
+            2);
 
   // Insertion
-  ASSERT_EQ(SequenceMatcher("abc", "abxbc").EditDistance(), 2);
-  ASSERT_EQ(SequenceMatcher("", "abxbc").EditDistance(), 5);
+  ASSERT_EQ(
+      SequenceMatcher(base::UTF8ToUTF16("abc"), base::UTF8ToUTF16("abxbc"))
+          .EditDistance(),
+      2);
+  ASSERT_EQ(SequenceMatcher(base::UTF8ToUTF16(""), base::UTF8ToUTF16("abxbc"))
+                .EditDistance(),
+            5);
 
   // Substitution
-  ASSERT_EQ(SequenceMatcher("book", "back").EditDistance(), 2);
+  ASSERT_EQ(
+      SequenceMatcher(base::UTF8ToUTF16("book"), base::UTF8ToUTF16("back"))
+          .EditDistance(),
+      2);
 
   // Combination
-  ASSERT_EQ(SequenceMatcher("caclulation", "calculator").EditDistance(), 3);
-  ASSERT_EQ(SequenceMatcher("sunday", "saturday").EditDistance(), 3);
+  ASSERT_EQ(SequenceMatcher(base::UTF8ToUTF16("caclulation"),
+                            base::UTF8ToUTF16("calculator"))
+                .EditDistance(),
+            3);
+  ASSERT_EQ(SequenceMatcher(base::UTF8ToUTF16("sunday"),
+                            base::UTF8ToUTF16("saturday"))
+                .EditDistance(),
+            3);
 }
 
 TEST_F(SequenceMatcherTest, TestFindLongestMatch) {
-  SequenceMatcher sequence_match("miscellanious", "miscellaneous");
+  SequenceMatcher sequence_match(base::UTF8ToUTF16("miscellanious"),
+                                 base::UTF8ToUTF16("miscellaneous"));
   ASSERT_TRUE(MatchEqual(sequence_match.FindLongestMatch(0, 13, 0, 13),
                          Match(0, 0, 9)));
   ASSERT_TRUE(MatchEqual(sequence_match.FindLongestMatch(7, 13, 7, 13),
                          Match(10, 10, 3)));
 
-  ASSERT_TRUE(
-      MatchEqual(SequenceMatcher("", "abcd").FindLongestMatch(0, 0, 0, 4),
-                 Match(0, 0, 0)));
   ASSERT_TRUE(MatchEqual(
-      SequenceMatcher("abababbababa", "ababbaba").FindLongestMatch(0, 12, 0, 8),
-      Match(2, 0, 8)));
+      SequenceMatcher(base::UTF8ToUTF16(""), base::UTF8ToUTF16("abcd"))
+          .FindLongestMatch(0, 0, 0, 4),
+      Match(0, 0, 0)));
+  ASSERT_TRUE(MatchEqual(SequenceMatcher(base::UTF8ToUTF16("abababbababa"),
+                                         base::UTF8ToUTF16("ababbaba"))
+                             .FindLongestMatch(0, 12, 0, 8),
+                         Match(2, 0, 8)));
   ASSERT_TRUE(MatchEqual(
-      SequenceMatcher("aaaaaa", "aaaaa").FindLongestMatch(0, 6, 0, 5),
+      SequenceMatcher(base::UTF8ToUTF16("aaaaaa"), base::UTF8ToUTF16("aaaaa"))
+          .FindLongestMatch(0, 6, 0, 5),
       Match(0, 0, 5)));
 }
 
 TEST_F(SequenceMatcherTest, TestGetMatchingBlocks) {
-  SequenceMatcher sequence_match("This is a demo sentence!!!",
-                                 "This demo sentence is good!!!");
+  SequenceMatcher sequence_match(
+      base::UTF8ToUTF16("This is a demo sentence!!!"),
+      base::UTF8ToUTF16("This demo sentence is good!!!"));
   const std::vector<Match> true_matches = {Match(0, 0, 4), Match(9, 4, 14),
                                            Match(23, 26, 3), Match(26, 29, 0)};
   const std::vector<Match> matches = sequence_match.GetMatchingBlocks();
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
index c18ba7b..749bf29 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
@@ -357,10 +357,6 @@
 }
 
 #if !defined(OS_ANDROID)
-void AutofillPopupControllerImpl::SetTypesetter(gfx::Typesetter typesetter) {
-  typesetter_ = typesetter;
-}
-
 int AutofillPopupControllerImpl::GetElidedValueWidthForRow(int row) {
   return gfx::GetStringWidth(GetElidedValueAt(row),
                              layout_model_.GetValueFontListForRow(row),
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.h b/chrome/browser/ui/autofill/autofill_popup_controller_impl.h
index 6a0301a..76ce03f2 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller_impl.h
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.h
@@ -67,9 +67,6 @@
 
   bool HandleKeyPressEvent(const content::NativeWebKeyboardEvent& event);
 
-  // Tells the view to capture mouse events. Must be called before |Show()|.
-  void set_hide_on_outside_click(bool hide_on_outside_click);
-
  protected:
   FRIEND_TEST_ALL_PREFIXES(AutofillPopupControllerUnitTest,
                            ProperlyResetController);
@@ -93,7 +90,6 @@
   bool IsRTL() const override;
   const std::vector<Suggestion> GetSuggestions() override;
 #if !defined(OS_ANDROID)
-  void SetTypesetter(gfx::Typesetter typesetter) override;
   int GetElidedValueWidthForRow(int row) override;
   int GetElidedLabelWidthForRow(int row) override;
 #endif
diff --git a/chrome/browser/ui/autofill/autofill_popup_layout_model_unittest.cc b/chrome/browser/ui/autofill/autofill_popup_layout_model_unittest.cc
index f34b926..f04532d 100644
--- a/chrome/browser/ui/autofill/autofill_popup_layout_model_unittest.cc
+++ b/chrome/browser/ui/autofill/autofill_popup_layout_model_unittest.cc
@@ -56,7 +56,6 @@
     return suggestions;
   }
 #if !defined(OS_ANDROID)
-  void SetTypesetter(gfx::Typesetter typesetter) override {}
   int GetElidedValueWidthForRow(int row) override { return 0; }
   int GetElidedLabelWidthForRow(int row) override { return 0; }
 #endif
diff --git a/chrome/browser/ui/autofill/autofill_popup_view_delegate.h b/chrome/browser/ui/autofill/autofill_popup_view_delegate.h
index c0f9146..989d42f 100644
--- a/chrome/browser/ui/autofill/autofill_popup_view_delegate.h
+++ b/chrome/browser/ui/autofill/autofill_popup_view_delegate.h
@@ -63,10 +63,6 @@
   virtual const std::vector<autofill::Suggestion> GetSuggestions() = 0;
 
 #if !defined(OS_ANDROID)
-  // Changes the typesetter used for eliding text. TODO(tapted): Remove this
-  // when autofill_popup_base_view_cocoa.mm is obsolete.
-  virtual void SetTypesetter(gfx::Typesetter typesetter) = 0;
-
   // Returns elided values and labels for the given |row|.
   virtual int GetElidedValueWidthForRow(int row) = 0;
   virtual int GetElidedLabelWidthForRow(int row) = 0;
diff --git a/chrome/browser/ui/bookmarks/bookmark_drag_drop.cc b/chrome/browser/ui/bookmarks/bookmark_drag_drop.cc
index 5b3983e29..424c753 100644
--- a/chrome/browser/ui/bookmarks/bookmark_drag_drop.cc
+++ b/chrome/browser/ui/bookmarks/bookmark_drag_drop.cc
@@ -9,12 +9,14 @@
 #include "build/build_config.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/bookmarks/bookmark_stats.h"
 #include "chrome/browser/undo/bookmark_undo_service_factory.h"
 #include "components/bookmarks/browser/bookmark_client.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/browser/bookmark_node_data.h"
 #include "components/bookmarks/browser/bookmark_utils.h"
 #include "components/bookmarks/browser/scoped_group_bookmark_actions.h"
+#include "components/profile_metrics/browser_profile_type.h"
 #include "components/undo/bookmark_undo_service.h"
 #include "ui/base/dragdrop/drag_drop_types.h"
 
@@ -42,6 +44,7 @@
                   const BookmarkNode* parent_node,
                   size_t index,
                   bool copy) {
+  DCHECK(profile);
   BookmarkModel* model = BookmarkModelFactory::GetForBrowserContext(profile);
 #if !defined(OS_ANDROID)
   bookmarks::ScopedGroupBookmarkActions group_drops(model);
@@ -66,6 +69,7 @@
     }
     return ui::DragDropTypes::DRAG_NONE;
   }
+  RecordBookmarksAdded(profile);
   // Dropping a folder from different profile. Always accept.
   bookmarks::CloneBookmarkNode(model, data.elements, parent_node, index, true);
   return ui::DragDropTypes::DRAG_COPY;
diff --git a/chrome/browser/ui/bookmarks/bookmark_stats.cc b/chrome/browser/ui/bookmarks/bookmark_stats.cc
index ffa936f4..12a3aeef 100644
--- a/chrome/browser/ui/bookmarks/bookmark_stats.cc
+++ b/chrome/browser/ui/bookmarks/bookmark_stats.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/ui/bookmarks/bookmark_stats.h"
+#include "chrome/browser/profiles/profile.h"
 
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
@@ -18,6 +19,14 @@
          location == BOOKMARK_LAUNCH_LOCATION_BAR_SUBFOLDER;
 }
 
+auto GetMetricProfile(const Profile* profile) {
+  DCHECK(profile);
+  DCHECK(profile->IsRegularProfile() || profile->IsIncognitoProfile());
+  return profile->IsRegularProfile()
+             ? profile_metrics::BrowserProfileType::kRegular
+             : profile_metrics::BrowserProfileType::kIncognito;
+}
+
 }  // namespace
 
 void RecordBookmarkLaunch(BookmarkLaunchLocation location,
@@ -55,3 +64,19 @@
         base::UserMetricsAction("ClickedBookmarkBarAppsShortcutButton"));
   }
 }
+
+void RecordBookmarksAdded(const Profile* profile) {
+  auto profile_type = GetMetricProfile(profile);
+  UMA_HISTOGRAM_ENUMERATION("Bookmarks.AddedPerProfileType", profile_type);
+}
+
+void RecordBookmarkAllTabsWithTabsCount(const Profile* profile, int count) {
+  auto profile_type = GetMetricProfile(profile);
+  if (profile_type == profile_metrics::BrowserProfileType::kRegular) {
+    UMA_HISTOGRAM_COUNTS_100("Bookmarks.BookmarkAllTabsWithTabsCount.Regular",
+                             count);
+  } else {
+    UMA_HISTOGRAM_COUNTS_100("Bookmarks.BookmarkAllTabsWithTabsCount.Incognito",
+                             count);
+  }
+}
diff --git a/chrome/browser/ui/bookmarks/bookmark_stats.h b/chrome/browser/ui/bookmarks/bookmark_stats.h
index e5c495b2..0032b96 100644
--- a/chrome/browser/ui/bookmarks/bookmark_stats.h
+++ b/chrome/browser/ui/bookmarks/bookmark_stats.h
@@ -7,38 +7,44 @@
 
 #include "components/profile_metrics/browser_profile_type.h"
 
-// This enum is used for the Bookmarks.EntryPoint histogram.
-enum BookmarkEntryPoint {
-  BOOKMARK_ENTRY_POINT_ACCELERATOR,
-  BOOKMARK_ENTRY_POINT_STAR_GESTURE,
-  BOOKMARK_ENTRY_POINT_STAR_KEY,
-  BOOKMARK_ENTRY_POINT_STAR_MOUSE,
+class Profile;
 
-  BOOKMARK_ENTRY_POINT_LIMIT  // Keep this last.
+// This enum is used for the Bookmarks.EntryPoint histogram.
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum BookmarkEntryPoint {
+  BOOKMARK_ENTRY_POINT_ACCELERATOR = 0,
+  BOOKMARK_ENTRY_POINT_STAR_GESTURE = 1,
+  BOOKMARK_ENTRY_POINT_STAR_KEY = 2,
+  BOOKMARK_ENTRY_POINT_STAR_MOUSE = 3,
+
+  BOOKMARK_ENTRY_POINT_LIMIT = 4  // Keep this last.
 };
 
 // This enum is used for the Bookmarks.LaunchLocation histogram.
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
 enum BookmarkLaunchLocation {
-  BOOKMARK_LAUNCH_LOCATION_NONE,
-  BOOKMARK_LAUNCH_LOCATION_ATTACHED_BAR = 0,
-  BOOKMARK_LAUNCH_LOCATION_DETACHED_BAR,
+  BOOKMARK_LAUNCH_LOCATION_NONE = 0,
+  BOOKMARK_LAUNCH_LOCATION_ATTACHED_BAR = 1,
+  BOOKMARK_LAUNCH_LOCATION_DETACHED_BAR = 2,
   // These two are kind of sub-categories of the bookmark bar. Generally
   // a launch from a context menu or subfolder could be classified in one of
   // the other two bar buckets, but doing so is difficult because the menus
   // don't know of their greater place in Chrome.
-  BOOKMARK_LAUNCH_LOCATION_BAR_SUBFOLDER,
-  BOOKMARK_LAUNCH_LOCATION_CONTEXT_MENU,
+  BOOKMARK_LAUNCH_LOCATION_BAR_SUBFOLDER = 3,
+  BOOKMARK_LAUNCH_LOCATION_CONTEXT_MENU = 4,
 
   // Bookmarks menu within app menu.
-  BOOKMARK_LAUNCH_LOCATION_APP_MENU,
+  BOOKMARK_LAUNCH_LOCATION_APP_MENU = 5,
   // Bookmark manager.
-  BOOKMARK_LAUNCH_LOCATION_MANAGER,
+  BOOKMARK_LAUNCH_LOCATION_MANAGER = 6,
   // Autocomplete suggestion.
-  BOOKMARK_LAUNCH_LOCATION_OMNIBOX,
+  BOOKMARK_LAUNCH_LOCATION_OMNIBOX = 7,
   // System application menu (e.g. on Mac).
-  BOOKMARK_LAUNCH_LOCATION_TOP_MENU,
+  BOOKMARK_LAUNCH_LOCATION_TOP_MENU = 8,
 
-  BOOKMARK_LAUNCH_LOCATION_LIMIT  // Keep this last.
+  BOOKMARK_LAUNCH_LOCATION_LIMIT = 9  // Keep this last.
 };
 
 // Records the launch of a bookmark for UMA purposes.
@@ -55,4 +61,13 @@
 // Records the user opening the apps page for UMA purposes.
 void RecordBookmarkAppsPageOpen(BookmarkLaunchLocation location);
 
+// Records the user adding a bookmark via star action, drag and drop, via
+// Bookmark this tab... and Bookmark all tabs... buttons. For the Bookmark
+// open tabs... the action is recorded only once and not as many times as
+// count of tabs that were bookmarked.
+void RecordBookmarksAdded(const Profile* profile);
+
+// Records the user bookmarking all tabs, along with the open tabs count.
+void RecordBookmarkAllTabsWithTabsCount(const Profile* profile, int count);
+
 #endif  // CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_STATS_H_
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc
index 1c4beb41..9548de2 100644
--- a/chrome/browser/ui/browser_commands.cc
+++ b/chrome/browser/ui/browser_commands.cc
@@ -33,6 +33,7 @@
 #include "chrome/browser/ui/accelerator_utils.h"
 #include "chrome/browser/ui/autofill/payments/manage_migration_ui_controller.h"
 #include "chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.h"
+#include "chrome/browser/ui/bookmarks/bookmark_stats.h"
 #include "chrome/browser/ui/bookmarks/bookmark_utils.h"
 #include "chrome/browser/ui/bookmarks/bookmark_utils_desktop.h"
 #include "chrome/browser/ui/browser.h"
@@ -840,6 +841,9 @@
     // weird situations where the bubble is deleted as soon as it is shown.
     browser->window()->ShowBookmarkBubble(url, was_bookmarked_by_user);
   }
+
+  if (!was_bookmarked_by_user && is_bookmarked_by_user)
+    RecordBookmarksAdded(browser->profile());
 }
 
 void BookmarkCurrentTabAllowingExtensionOverrides(Browser* browser) {
@@ -873,6 +877,10 @@
 
 void BookmarkAllTabs(Browser* browser) {
   base::RecordAction(UserMetricsAction("BookmarkAllTabs"));
+  RecordBookmarkAllTabsWithTabsCount(browser->profile(),
+                                     browser->tab_strip_model()->count());
+  // We record the profile that invoked this option.
+  RecordBookmarksAdded(browser->profile());
   chrome::ShowBookmarkAllTabsDialog(browser);
 }
 
diff --git a/chrome/browser/ui/browser_ui_prefs.cc b/chrome/browser/ui/browser_ui_prefs.cc
index 149f4b566..43e31eb9 100644
--- a/chrome/browser/ui/browser_ui_prefs.cc
+++ b/chrome/browser/ui/browser_ui_prefs.cc
@@ -101,6 +101,7 @@
   // them even though they're only typically controlled via policy.
   registry->RegisterBooleanPref(prefs::kClearPluginLSODataEnabled, true);
   registry->RegisterBooleanPref(prefs::kHideWebStoreIcon, false);
+  registry->RegisterBooleanPref(prefs::kSharedClipboardEnabled, true);
 #if defined(OS_MACOSX)
   // This really belongs in platform code, but there's no good place to
   // initialize it between the time when the AppController is created
diff --git a/chrome/browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller_unittest.mm b/chrome/browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller_unittest.mm
index 5846bc4..90bf859 100644
--- a/chrome/browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller_unittest.mm
@@ -56,7 +56,6 @@
   const std::vector<autofill::Suggestion> GetSuggestions() override {
     return suggestions_;
   }
-  MOCK_METHOD1(SetTypesetter, void(gfx::Typesetter typesetter));
   MOCK_METHOD1(GetElidedValueWidthForRow, int(int row));
   MOCK_METHOD1(GetElidedLabelWidthForRow, int(int row));
 
diff --git a/chrome/browser/ui/passwords/password_generation_popup_controller_impl.cc b/chrome/browser/ui/passwords/password_generation_popup_controller_impl.cc
index 1803fd2..1c7443d 100644
--- a/chrome/browser/ui/passwords/password_generation_popup_controller_impl.cc
+++ b/chrome/browser/ui/passwords/password_generation_popup_controller_impl.cc
@@ -335,9 +335,6 @@
 }
 
 #if !defined(OS_ANDROID)
-void PasswordGenerationPopupControllerImpl::SetTypesetter(
-    gfx::Typesetter typesetter) {}
-
 int PasswordGenerationPopupControllerImpl::GetElidedValueWidthForRow(int row) {
   return 0;
 }
diff --git a/chrome/browser/ui/passwords/password_generation_popup_controller_impl.h b/chrome/browser/ui/passwords/password_generation_popup_controller_impl.h
index 0078b50e..95c8b4d 100644
--- a/chrome/browser/ui/passwords/password_generation_popup_controller_impl.h
+++ b/chrome/browser/ui/passwords/password_generation_popup_controller_impl.h
@@ -138,7 +138,6 @@
   bool IsRTL() const override;
   const std::vector<autofill::Suggestion> GetSuggestions() override;
 #if !defined(OS_ANDROID)
-  void SetTypesetter(gfx::Typesetter typesetter) override;
   int GetElidedValueWidthForRow(int row) override;
   int GetElidedLabelWidthForRow(int row) override;
 #endif
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_base_view_browsertest.cc b/chrome/browser/ui/views/autofill/autofill_popup_base_view_browsertest.cc
index 5aac9eb..e3fdb00 100644
--- a/chrome/browser/ui/views/autofill/autofill_popup_base_view_browsertest.cc
+++ b/chrome/browser/ui/views/autofill/autofill_popup_base_view_browsertest.cc
@@ -43,7 +43,6 @@
   MOCK_CONST_METHOD0(IsRTL, bool());
   MOCK_METHOD0(GetSuggestions, const std::vector<autofill::Suggestion>());
 #if !defined(OS_ANDROID)
-  MOCK_METHOD1(SetTypesetter, void(gfx::Typesetter typesetter));
   MOCK_METHOD1(GetElidedValueWidthForRow, int(int));
   MOCK_METHOD1(GetElidedLabelWidthForRow, int(int));
 #endif
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
index 2db5dcf..bf69cff4 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
@@ -41,6 +41,7 @@
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
 #include "chrome/browser/ui/views/web_apps/web_app_frame_toolbar_view.h"
 #include "chrome/browser/ui/web_applications/app_browser_controller.h"
+#include "chrome/browser/ui/web_applications/system_web_app_ui_utils.h"
 #include "chromeos/constants/chromeos_features.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/service_manager_connection.h"
@@ -423,6 +424,14 @@
 }
 
 gfx::Size BrowserNonClientFrameViewAsh::GetMinimumSize() const {
+  // System web apps (e.g. Settings) may have a fixed minimum size.
+  Browser* browser = browser_view()->browser();
+  if (web_app::IsSystemWebApp(browser)) {
+    gfx::Size minimum_size = web_app::GetSystemWebAppMinimumWindowSize(browser);
+    if (!minimum_size.IsEmpty())
+      return minimum_size;
+  }
+
   gfx::Size min_client_view_size(frame()->client_view()->GetMinimumSize());
   const int min_frame_width = frame_header_->GetMinimumHeaderWidth();
   int min_width = std::max(min_frame_width, min_client_view_size.width());
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
index db81f1c..f97342b 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
@@ -43,6 +43,7 @@
 #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
 #include "chrome/browser/ui/exclusive_access/fullscreen_controller_test.h"
 #include "chrome/browser/ui/passwords/passwords_client_ui_delegate.h"
+#include "chrome/browser/ui/settings_window_manager_chromeos.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/toolbar/browser_actions_bar_browsertest.h"
 #include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h"
@@ -63,6 +64,8 @@
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
 #include "chrome/browser/ui/views/web_apps/web_app_frame_toolbar_view.h"
 #include "chrome/browser/ui/views/web_apps/web_app_menu_button.h"
+#include "chrome/browser/web_applications/system_web_app_manager.h"
+#include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/common/web_application_info.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
@@ -350,6 +353,28 @@
   EXPECT_GT(min_window_size.height(), min_height_no_bookmarks);
 }
 
+IN_PROC_BROWSER_TEST_P(BrowserNonClientFrameViewAshTest,
+                       SettingsSystemWebAppHasMinimumWindowSize) {
+  // Install the Settings System Web App.
+  web_app::WebAppProvider::Get(browser()->profile())
+      ->system_web_app_manager()
+      .InstallSystemAppsForTesting();
+
+  // Open a settings window.
+  auto* settings_manager = chrome::SettingsWindowManager::GetInstance();
+  settings_manager->ShowOSSettings(browser()->profile());
+  Browser* settings_browser =
+      settings_manager->FindBrowserForProfile(browser()->profile());
+
+  // Try to set the bounds to a tiny value.
+  settings_browser->window()->SetBounds(gfx::Rect(1, 1));
+
+  // The window has a reasonable size.
+  gfx::Rect actual_bounds = settings_browser->window()->GetBounds();
+  EXPECT_LE(200, actual_bounds.width());
+  EXPECT_LE(100, actual_bounds.height());
+}
+
 // This is a regression test that session restore minimized browser should
 // re-layout the header (https://crbug.com/827444).
 IN_PROC_BROWSER_TEST_P(BrowserNonClientFrameViewAshTest,
diff --git a/chrome/browser/ui/views/frame/browser_view_layout.h b/chrome/browser/ui/views/frame/browser_view_layout.h
index 8417e02..c8c9833 100644
--- a/chrome/browser/ui/views/frame/browser_view_layout.h
+++ b/chrome/browser/ui/views/frame/browser_view_layout.h
@@ -122,11 +122,6 @@
   // the bookmark bar and the toolbar.
   void UpdateTopContainerBounds();
 
-  // Returns the top margin to adjust the contents_container_ by. This is used
-  // to make the bookmark bar and contents_container_ overlap so that the
-  // preview contents hides the bookmark bar.
-  int GetTopMarginForActiveContent();
-
   // Layout the Download Shelf, returns the coordinate of the top of the
   // control, for laying out the previous control.
   int LayoutDownloadShelf(int bottom);
diff --git a/chrome/browser/ui/views/global_media_controls/media_notification_list_view.cc b/chrome/browser/ui/views/global_media_controls/media_notification_list_view.cc
index e32561e..d29747b 100644
--- a/chrome/browser/ui/views/global_media_controls/media_notification_list_view.cc
+++ b/chrome/browser/ui/views/global_media_controls/media_notification_list_view.cc
@@ -15,6 +15,7 @@
 }  // anonymous namespace
 
 MediaNotificationListView::MediaNotificationListView() {
+  SetBackgroundColor(SK_ColorTRANSPARENT);
   SetContents(std::make_unique<views::View>());
   contents()->SetLayoutManager(std::make_unique<views::BoxLayout>(
       views::BoxLayout::Orientation::kVertical));
diff --git a/chrome/browser/ui/views/passwords/credentials_item_view.cc b/chrome/browser/ui/views/passwords/credentials_item_view.cc
index 2f7ca7c..fa3ea8f 100644
--- a/chrome/browser/ui/views/passwords/credentials_item_view.cc
+++ b/chrome/browser/ui/views/passwords/credentials_item_view.cc
@@ -14,23 +14,16 @@
 #include "third_party/skia/include/core/SkPath.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/canvas.h"
+#include "ui/gfx/geometry/insets.h"
 #include "ui/views/border.h"
 #include "ui/views/bubble/tooltip_icon.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/view_class_properties.h"
 
 namespace {
 
-gfx::Size GetTextLabelsSize(const views::Label* upper_label,
-                            const views::Label* lower_label) {
-  gfx::Size upper_label_size = upper_label ? upper_label->GetPreferredSize()
-                                           : gfx::Size();
-  gfx::Size lower_label_size = lower_label ? lower_label->GetPreferredSize()
-                                           : gfx::Size();
-  return gfx::Size(std::max(upper_label_size.width(), lower_label_size.width()),
-                   upper_label_size.height() + lower_label_size.height());
-}
-
 class CircularImageView : public views::ImageView {
  public:
   CircularImageView() = default;
@@ -67,6 +60,11 @@
     int lower_text_style)
     : Button(button_listener), form_(form), hover_color_(hover_color) {
   set_notify_enter_exit_on_child(true);
+  views::BoxLayout* layout =
+      SetLayoutManager(std::make_unique<views::BoxLayout>(
+          views::BoxLayout::Orientation::kHorizontal));
+  layout->set_cross_axis_alignment(
+      views::BoxLayout::CrossAxisAlignment::kCenter);
   // Create an image-view for the avatar. Make sure it ignores events so that
   // the parent can receive the events instead.
   auto image_view = std::make_unique<CircularImageView>();
@@ -89,11 +87,28 @@
   // http://crbug.com/651681.
   const int kLabelContext = CONTEXT_BODY_TEXT_SMALL;
 
+  views::View* text_container = nullptr;
+  if (!upper_text.empty() || !lower_text.empty()) {
+    text_container = AddChildView(std::make_unique<views::View>());
+    views::BoxLayout* text_layout =
+        text_container->SetLayoutManager(std::make_unique<views::BoxLayout>(
+            views::BoxLayout::Orientation::kVertical));
+    text_layout->set_cross_axis_alignment(
+        views::BoxLayout::CrossAxisAlignment::kStart);
+    text_container->SetProperty(
+        views::kMarginsKey,
+        gfx::Insets(0,
+                    ChromeLayoutProvider::Get()->GetDistanceMetric(
+                        views::DISTANCE_RELATED_LABEL_HORIZONTAL),
+                    0, 0));
+    layout->SetFlexForView(text_container, 1);
+  }
+
   if (!upper_text.empty()) {
     auto upper_label = std::make_unique<views::Label>(upper_text, kLabelContext,
                                                       upper_text_style);
     upper_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-    upper_label_ = AddChildView(std::move(upper_label));
+    upper_label_ = text_container->AddChildView(std::move(upper_label));
   }
 
   if (!lower_text.empty()) {
@@ -101,7 +116,7 @@
                                                       lower_text_style);
     lower_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
     lower_label->SetMultiLine(true);
-    lower_label_ = AddChildView(std::move(lower_label));
+    lower_label_ = text_container->AddChildView(std::move(lower_label));
   }
 
   if (form_->is_public_suffix_match) {
@@ -136,58 +151,6 @@
   return GetPreferredSize().height();
 }
 
-gfx::Size CredentialsItemView::CalculatePreferredSize() const {
-  gfx::Size labels_size = GetTextLabelsSize(upper_label_, lower_label_);
-  gfx::Size size = gfx::Size(kAvatarImageSize + labels_size.width(),
-                             std::max(kAvatarImageSize, labels_size.height()));
-  const gfx::Insets insets(GetInsets());
-  size.Enlarge(insets.width(), insets.height());
-  size.Enlarge(ChromeLayoutProvider::Get()->GetDistanceMetric(
-                   views::DISTANCE_RELATED_LABEL_HORIZONTAL),
-               0);
-
-  // Make the size at least as large as the minimum size needed by the border.
-  size.SetToMax(border() ? border()->GetMinimumSize() : gfx::Size());
-  return size;
-}
-
-int CredentialsItemView::GetHeightForWidth(int w) const {
-  return View::GetHeightForWidth(w);
-}
-
-void CredentialsItemView::Layout() {
-  gfx::Rect child_area = GetContentsBounds();
-
-  gfx::Size image_size(image_view_->GetPreferredSize());
-  image_size.SetToMin(child_area.size());
-  gfx::Point image_origin(child_area.origin());
-  image_origin.Offset(0, (child_area.height() - image_size.height()) / 2);
-  image_view_->SetBoundsRect(gfx::Rect(image_origin, image_size));
-
-  gfx::Size upper_size =
-      upper_label_ ? upper_label_->GetPreferredSize() : gfx::Size();
-  gfx::Size lower_size =
-      lower_label_ ? lower_label_->GetPreferredSize() : gfx::Size();
-  int y_offset = (child_area.height() -
-      (upper_size.height() + lower_size.height())) / 2;
-  gfx::Point label_origin(image_origin.x() + image_size.width() +
-                              ChromeLayoutProvider::Get()->GetDistanceMetric(
-                                  views::DISTANCE_RELATED_LABEL_HORIZONTAL),
-                          child_area.origin().y() + y_offset);
-  if (upper_label_)
-    upper_label_->SetBoundsRect(gfx::Rect(label_origin, upper_size));
-  if (lower_label_) {
-    label_origin.Offset(0, upper_size.height());
-    lower_label_->SetBoundsRect(gfx::Rect(label_origin, lower_size));
-  }
-  if (info_icon_) {
-    info_icon_->SizeToPreferredSize();
-    info_icon_->SetPosition(
-        gfx::Point(child_area.right() - info_icon_->width(),
-                   child_area.CenterPoint().y() - info_icon_->height() / 2));
-  }
-}
-
 void CredentialsItemView::OnPaintBackground(gfx::Canvas* canvas) {
   if (state() == STATE_PRESSED || state() == STATE_HOVERED)
     canvas->DrawColor(hover_color_);
diff --git a/chrome/browser/ui/views/passwords/credentials_item_view.h b/chrome/browser/ui/views/passwords/credentials_item_view.h
index c7dbde1d..f0aa0f7 100644
--- a/chrome/browser/ui/views/passwords/credentials_item_view.h
+++ b/chrome/browser/ui/views/passwords/credentials_item_view.h
@@ -57,9 +57,6 @@
 
  private:
   // views::View:
-  gfx::Size CalculatePreferredSize() const override;
-  int GetHeightForWidth(int w) const override;
-  void Layout() override;
   void OnPaintBackground(gfx::Canvas* canvas) override;
 
   const autofill::PasswordForm* form_;
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view.cc b/chrome/browser/ui/views/profiles/profile_menu_view.cc
index 5ff56855..3ff53da 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view.cc
+++ b/chrome/browser/ui/views/profiles/profile_menu_view.cc
@@ -412,20 +412,22 @@
           account);
 
   if (account_info.has_value()) {
-    SetIdentityInfo(account_info.value().account_image,
+    SetIdentityInfo(account_info.value().account_image.AsImageSkia(),
+                    GetIdentityBadge(),
                     base::UTF8ToUTF16(account_info.value().full_name),
                     base::UTF8ToUTF16(account_info.value().email));
   } else {
     ProfileAttributesEntry* profile_attributes =
         GetProfileAttributesEntry(profile);
     SetIdentityInfo(
-        profile_attributes->GetAvatarIcon(), profile_attributes->GetName(),
+        profile_attributes->GetAvatarIcon().AsImageSkia(), GetIdentityBadge(),
+        profile_attributes->GetName(),
         l10n_util::GetStringUTF16(IDS_PROFILES_LOCAL_PROFILE_STATE));
   }
 }
 
 void ProfileMenuView::BuildGuestIdentity() {
-  SetIdentityInfo(gfx::Image(ImageForMenu(kUserAccountAvatarIcon)),
+  SetIdentityInfo(ImageForMenu(kUserAccountAvatarIcon), GetIdentityBadge(),
                   l10n_util::GetStringUTF16(IDS_GUEST_PROFILE_NAME));
 }
 
@@ -434,7 +436,7 @@
       BrowserList::GetIncognitoSessionsActiveForProfile(browser()->profile());
 
   SetIdentityInfo(
-      gfx::Image(ImageForMenu(kIncognitoProfileIcon)),
+      ImageForMenu(kIncognitoProfileIcon), GetIdentityBadge(),
       l10n_util::GetStringUTF16(IDS_INCOGNITO_PROFILE_MENU_TITLE),
       incognito_window_count > 1
           ? l10n_util::GetPluralStringFUTF16(IDS_INCOGNITO_WINDOW_COUNT_MESSAGE,
@@ -442,6 +444,43 @@
           : base::string16());
 }
 
+gfx::ImageSkia ProfileMenuView::GetIdentityBadge() {
+  Profile* profile = browser()->profile();
+  signin::IdentityManager* identity_manager =
+      IdentityManagerFactory::GetForProfile(profile);
+  ui::NativeTheme* native_theme = ui::NativeTheme::GetInstanceForNativeUi();
+
+  if (!profile->IsRegularProfile())
+    return gfx::ImageSkia();
+
+  if (!identity_manager->HasPrimaryAccount())
+    return ColoredImageForMenu(kSyncPausedCircleIcon, gfx::kGoogleGrey400);
+
+  const gfx::VectorIcon* icon = nullptr;
+  ui::NativeTheme::ColorId color_id;
+  int unused;
+  switch (
+      sync_ui_util::GetMessagesForAvatarSyncError(profile, &unused, &unused)) {
+    case sync_ui_util::NO_SYNC_ERROR:
+      icon = &kSyncCircleIcon;
+      color_id = ui::NativeTheme::kColorId_AlertSeverityLow;
+      break;
+    case sync_ui_util::AUTH_ERROR:
+      icon = &kSyncPausedCircleIcon;
+      color_id = ui::NativeTheme::kColorId_ProminentButtonColor;
+      break;
+    case sync_ui_util::MANAGED_USER_UNRECOVERABLE_ERROR:
+    case sync_ui_util::UNRECOVERABLE_ERROR:
+    case sync_ui_util::UPGRADE_CLIENT_ERROR:
+    case sync_ui_util::PASSPHRASE_ERROR:
+    case sync_ui_util::SETTINGS_UNCONFIRMED_ERROR:
+      icon = &kSyncPausedCircleIcon;
+      color_id = ui::NativeTheme::kColorId_AlertSeverityHigh;
+      break;
+  }
+  return ColoredImageForMenu(*icon, native_theme->GetSystemColor(color_id));
+}
+
 void ProfileMenuView::BuildAutofillButtons() {
   AddShortcutFeatureButton(
       ImageForMenu(kKeyIcon, kShortcutIconToImageRatio),
@@ -536,7 +575,7 @@
       continue;
 
     AddSelectableProfile(
-        profile_entry->GetAvatarIcon(), profile_entry->GetName(),
+        profile_entry->GetAvatarIcon().AsImageSkia(), profile_entry->GetName(),
         base::BindRepeating(&ProfileMenuView::OnOtherProfileSelected,
                             base::Unretained(this), profile_entry->GetPath()));
   }
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view.h b/chrome/browser/ui/views/profiles/profile_menu_view.h
index bcb16f0..d6f0e02 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view.h
+++ b/chrome/browser/ui/views/profiles/profile_menu_view.h
@@ -103,6 +103,7 @@
   void BuildIdentity();
   void BuildGuestIdentity();
   void BuildIncognitoIdentity();
+  gfx::ImageSkia GetIdentityBadge();
   void BuildAutofillButtons();
   void BuildSyncInfo();
   void BuildAccountFeatureButtons();
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view_base.cc b/chrome/browser/ui/views/profiles/profile_menu_view_base.cc
index e1f009b..5010883 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view_base.cc
+++ b/chrome/browser/ui/views/profiles/profile_menu_view_base.cc
@@ -80,6 +80,35 @@
   return gfx::ImageSkiaOperations::CreateColorMask(image, color);
 }
 
+gfx::ImageSkia CreateCircle(int size, SkColor color = SK_ColorWHITE) {
+  float radius = size / 2.0f;
+  gfx::Canvas canvas(gfx::Size(size, size), /*image_scale=*/1.0f,
+                     /*is_opaque=*/false);
+  cc::PaintFlags flags;
+  flags.setAntiAlias(true);
+  flags.setStyle(cc::PaintFlags::kFill_Style);
+  flags.setColor(color);
+  canvas.DrawCircle(gfx::PointF(radius, radius), radius, flags);
+
+  return gfx::ImageSkia::CreateFrom1xBitmap(canvas.GetBitmap());
+}
+
+gfx::ImageSkia CropCircle(const gfx::ImageSkia& image) {
+  DCHECK_EQ(image.width(), image.height());
+  return gfx::ImageSkiaOperations::CreateMaskedImage(
+      image, CreateCircle(image.width()));
+}
+
+gfx::ImageSkia AddCircularBackground(const gfx::ImageSkia& image,
+                                     SkColor bg_color,
+                                     int size) {
+  if (image.isNull())
+    return gfx::ImageSkia();
+
+  return gfx::ImageSkiaOperations::CreateSuperimposedImage(
+      CreateCircle(size, bg_color), image);
+}
+
 std::unique_ptr<views::BoxLayout> CreateBoxLayout(
     views::BoxLayout::Orientation orientation,
     views::BoxLayout::CrossAxisAlignment cross_axis_alignment,
@@ -231,12 +260,15 @@
   DCHECK(menu_item_groups_.empty());
 }
 
-void ProfileMenuViewBase::SetIdentityInfo(const gfx::Image& image,
+void ProfileMenuViewBase::SetIdentityInfo(const gfx::ImageSkia& image,
+                                          const gfx::ImageSkia& badge,
                                           const base::string16& title,
                                           const base::string16& subtitle) {
   constexpr int kTopMargin = 16;
   constexpr int kBottomMargin = 8;
   constexpr int kImageToLabelSpacing = 4;
+  constexpr int kBadgeSize = 16;
+  constexpr int kBadgePadding = 1;
 
   identity_info_container_->RemoveAllChildViews(/*delete_children=*/true);
   identity_info_container_->SetLayoutManager(
@@ -248,14 +280,17 @@
       std::make_unique<views::ImageView>());
   // Fall back on |kUserAccountAvatarIcon| if |image| is empty. This can happen
   // in tests and when the account image hasn't been fetched yet.
-  image_view->SetImage(
-      image.IsEmpty()
+  gfx::ImageSkia sized_image =
+      image.isNull()
           ? gfx::CreateVectorIcon(kUserAccountAvatarIcon, kIdentityImageSize,
                                   kIdentityImageSize)
-          : profiles::GetSizedAvatarIcon(image, /*is_rectangle=*/true,
-                                         kIdentityImageSize, kIdentityImageSize,
-                                         profiles::SHAPE_CIRCLE)
-                .AsImageSkia());
+          : CropCircle(SizeImage(image, kIdentityImageSize));
+  gfx::ImageSkia sized_badge =
+      AddCircularBackground(SizeImage(badge, kBadgeSize), SK_ColorWHITE,
+                            kBadgeSize + 2 * kBadgePadding);
+  gfx::ImageSkia badged_image =
+      gfx::ImageSkiaOperations::CreateIconWithBadge(sized_image, sized_badge);
+  image_view->SetImage(badged_image);
 
   views::View* title_label =
       identity_info_container_->AddChildView(std::make_unique<views::Label>(
@@ -363,7 +398,7 @@
   label->SetBorder(views::CreateEmptyBorder(gfx::Insets(0, kMenuEdgeMargin)));
 }
 
-void ProfileMenuViewBase::AddSelectableProfile(const gfx::Image& image,
+void ProfileMenuViewBase::AddSelectableProfile(const gfx::ImageSkia& image,
                                                const base::string16& name,
                                                base::RepeatingClosure action) {
   constexpr int kTopMargin = 8;
@@ -377,11 +412,9 @@
             gfx::Insets(kTopMargin, 0, 0, 0)));
   }
 
-  gfx::Image sized_image =
-      profiles::GetSizedAvatarIcon(image, /*is_rectangle=*/true, kImageSize,
-                                   kImageSize, profiles::SHAPE_CIRCLE);
+  gfx::ImageSkia sized_image = CropCircle(SizeImage(image, kImageSize));
   views::Button* button = selectable_profiles_container_->AddChildView(
-      std::make_unique<HoverButton>(this, sized_image.AsImageSkia(), name));
+      std::make_unique<HoverButton>(this, sized_image, name));
 
   RegisterClickAction(button, std::move(action));
 }
@@ -433,6 +466,12 @@
   return gfx::CanvasImageSource::CreatePadded(sized_icon, gfx::Insets(padding));
 }
 
+gfx::ImageSkia ProfileMenuViewBase::ColoredImageForMenu(
+    const gfx::VectorIcon& icon,
+    SkColor color) {
+  return gfx::CreateVectorIcon(icon, kMaxImageSize, color);
+}
+
 ax::mojom::Role ProfileMenuViewBase::GetAccessibleWindowRole() {
   // Return |ax::mojom::Role::kDialog| which will make screen readers announce
   // the following in the listed order:
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view_base.h b/chrome/browser/ui/views/profiles/profile_menu_view_base.h
index 00ec903..b2321d7 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view_base.h
+++ b/chrome/browser/ui/views/profiles/profile_menu_view_base.h
@@ -95,7 +95,8 @@
   virtual void BuildMenu() = 0;
 
   // API to build the profile menu.
-  void SetIdentityInfo(const gfx::Image& image,
+  void SetIdentityInfo(const gfx::ImageSkia& image,
+                       const gfx::ImageSkia& badge,
                        const base::string16& title,
                        const base::string16& subtitle = base::string16());
   void SetSyncInfo(const base::string16& description,
@@ -108,7 +109,7 @@
                                const base::string16& text,
                                base::RepeatingClosure action);
   void SetProfileHeading(const base::string16& heading);
-  void AddSelectableProfile(const gfx::Image& image,
+  void AddSelectableProfile(const gfx::ImageSkia& image,
                             const base::string16& name,
                             base::RepeatingClosure action);
   void AddProfileShortcutFeatureButton(const gfx::ImageSkia& icon,
@@ -122,6 +123,8 @@
   // returned image, with the rest being padding around it.
   gfx::ImageSkia ImageForMenu(const gfx::VectorIcon& icon,
                               float icon_to_image_ratio = 1.0f);
+  gfx::ImageSkia ColoredImageForMenu(const gfx::VectorIcon& icon,
+                                     SkColor color);
 
   // Initializes a new group of menu items. A separator is added before them if
   // |add_separator| is true.
diff --git a/chrome/browser/ui/web_applications/system_web_app_ui_utils.cc b/chrome/browser/ui/web_applications/system_web_app_ui_utils.cc
index 1cf8259..cb2ff59 100644
--- a/chrome/browser/ui/web_applications/system_web_app_ui_utils.cc
+++ b/chrome/browser/ui/web_applications/system_web_app_ui_utils.cc
@@ -7,6 +7,7 @@
 #include <string>
 #include <utility>
 
+#include "base/logging.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
@@ -15,6 +16,7 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/extensions/app_launch_params.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
+#include "chrome/browser/ui/web_applications/app_browser_controller.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "chrome/browser/web_applications/system_web_app_manager.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
@@ -109,4 +111,27 @@
   return nullptr;
 }
 
+bool IsSystemWebApp(Browser* browser) {
+  DCHECK(browser);
+  return browser->app_controller() &&
+         browser->app_controller()->IsForSystemWebApp();
+}
+
+gfx::Size GetSystemWebAppMinimumWindowSize(Browser* browser) {
+  DCHECK(browser);
+  if (!browser->app_controller())
+    return gfx::Size();  // Not an app.
+
+  base::Optional<AppId> app_id = browser->app_controller()->GetAppId();
+  if (!app_id)
+    return gfx::Size();
+
+  auto* provider = WebAppProvider::Get(browser->profile());
+  if (!provider)
+    return gfx::Size();
+
+  return provider->system_web_app_manager().GetMinimumWindowSize(
+      app_id.value());
+}
+
 }  // namespace web_app
diff --git a/chrome/browser/ui/web_applications/system_web_app_ui_utils.h b/chrome/browser/ui/web_applications/system_web_app_ui_utils.h
index d7fcac6..6e30d2f 100644
--- a/chrome/browser/ui/web_applications/system_web_app_ui_utils.h
+++ b/chrome/browser/ui/web_applications/system_web_app_ui_utils.h
@@ -33,6 +33,13 @@
 // not found.
 Browser* FindSystemWebAppBrowser(Profile* profile, SystemAppType app_type);
 
+// Returns true if the |browser| is a system web app.
+bool IsSystemWebApp(Browser* browser);
+
+// Returns the minimum window size for a system web app, or an empty size if
+// the app does not specify a minimum size.
+gfx::Size GetSystemWebAppMinimumWindowSize(Browser* browser);
+
 }  // namespace web_app
 
 #endif  // CHROME_BROWSER_UI_WEB_APPLICATIONS_SYSTEM_WEB_APP_UI_UTILS_H_
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
index c6a734b..0a64451 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -3125,6 +3125,7 @@
       {"removeUserTooltip", IDS_SETTINGS_USERS_REMOVE_USER_TOOLTIP},
       {"addUsers", IDS_SETTINGS_USERS_ADD_USERS},
       {"addUsersEmail", IDS_SETTINGS_USERS_ADD_USERS_EMAIL},
+      {"userExistsError", IDS_SETTINGS_USER_EXISTS_ERROR},
   };
   AddLocalizedStringsBulk(html_source, kLocalizedStrings,
                           base::size(kLocalizedStrings));
diff --git a/chrome/browser/upgrade_detector/upgrade_detector_impl.cc b/chrome/browser/upgrade_detector/upgrade_detector_impl.cc
index 5b53d070..432e378 100644
--- a/chrome/browser/upgrade_detector/upgrade_detector_impl.cc
+++ b/chrome/browser/upgrade_detector/upgrade_detector_impl.cc
@@ -33,6 +33,7 @@
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/google/google_brand.h"
+#include "chrome/browser/obsolete_system/obsolete_system.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "components/network_time/network_time_tracker.h"
@@ -392,6 +393,13 @@
   if (!base::FeatureList::IsEnabled(kOutdatedBuildDetector))
     return false;
 
+  // Don't detect outdated builds for obsolete operating systems when new builds
+  // are no longer available.
+  if (ObsoleteSystem::IsObsoleteNowOrSoon() &&
+      ObsoleteSystem::IsEndOfTheLine()) {
+    return false;
+  }
+
   // Don't show the bubble if we have a brand code that is NOT organic, unless
   // an outdated build is being simulated by command line switches.
   if (!simulating_outdated_) {
diff --git a/chrome/browser/util/DEPS b/chrome/browser/util/DEPS
new file mode 100644
index 0000000..a8a0eaca
--- /dev/null
+++ b/chrome/browser/util/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "-content/public/android",
+  "+content/public/android/java/src/org/chromium/content_public",
+]
diff --git a/chrome/browser/util/android/BUILD.gn b/chrome/browser/util/android/BUILD.gn
index efb79a4..295b3b0 100644
--- a/chrome/browser/util/android/BUILD.gn
+++ b/chrome/browser/util/android/BUILD.gn
@@ -6,14 +6,30 @@
 
 android_library("java") {
   java_files = [
+    "java/src/org/chromium/chrome/browser/util/BitmapCache.java",
+    "java/src/org/chromium/chrome/browser/util/ConversionUtils.java",
+    "java/src/org/chromium/chrome/browser/util/FileSizeUtil.java",
     "java/src/org/chromium/chrome/browser/util/HashUtil.java",
     "java/src/org/chromium/chrome/browser/util/IntentUtils.java",
+    "java/src/org/chromium/chrome/browser/util/KeyNavigationUtil.java",
+    "java/src/org/chromium/chrome/browser/util/MathUtils.java",
+    "java/src/org/chromium/chrome/browser/util/ChromeFileProvider.java",
+    "java/src/org/chromium/chrome/browser/util/UrlConstants.java",
+    "java/src/org/chromium/chrome/browser/util/UrlUtilities.java",
   ]
   deps = [
     "//base:base_java",
+    "//base:jni_java",
     "//content/public/android:content_java",
     "//third_party/android_deps:com_android_support_collections_java",
     "//third_party/android_deps:com_android_support_support_compat_java",
     "//third_party/android_deps:com_android_support_support_core_utils_java",
   ]
+  annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
+}
+
+generate_jni("jni_headers") {
+  sources = [
+    "java/src/org/chromium/chrome/browser/util/UrlUtilities.java",
+  ]
 }
diff --git a/chrome/lib/util/public/android/java/src/org/chromium/chrome/browser/util/BitmapCache.java b/chrome/browser/util/android/java/src/org/chromium/chrome/browser/util/BitmapCache.java
similarity index 100%
rename from chrome/lib/util/public/android/java/src/org/chromium/chrome/browser/util/BitmapCache.java
rename to chrome/browser/util/android/java/src/org/chromium/chrome/browser/util/BitmapCache.java
diff --git a/chrome/lib/util/public/android/java/src/org/chromium/chrome/browser/util/ChromeFileProvider.java b/chrome/browser/util/android/java/src/org/chromium/chrome/browser/util/ChromeFileProvider.java
similarity index 100%
rename from chrome/lib/util/public/android/java/src/org/chromium/chrome/browser/util/ChromeFileProvider.java
rename to chrome/browser/util/android/java/src/org/chromium/chrome/browser/util/ChromeFileProvider.java
diff --git a/chrome/lib/util/public/android/java/src/org/chromium/chrome/browser/util/ConversionUtils.java b/chrome/browser/util/android/java/src/org/chromium/chrome/browser/util/ConversionUtils.java
similarity index 100%
rename from chrome/lib/util/public/android/java/src/org/chromium/chrome/browser/util/ConversionUtils.java
rename to chrome/browser/util/android/java/src/org/chromium/chrome/browser/util/ConversionUtils.java
diff --git a/chrome/lib/util/public/android/java/src/org/chromium/chrome/browser/util/FileSizeUtil.java b/chrome/browser/util/android/java/src/org/chromium/chrome/browser/util/FileSizeUtil.java
similarity index 100%
rename from chrome/lib/util/public/android/java/src/org/chromium/chrome/browser/util/FileSizeUtil.java
rename to chrome/browser/util/android/java/src/org/chromium/chrome/browser/util/FileSizeUtil.java
diff --git a/chrome/lib/util/public/android/java/src/org/chromium/chrome/browser/util/KeyNavigationUtil.java b/chrome/browser/util/android/java/src/org/chromium/chrome/browser/util/KeyNavigationUtil.java
similarity index 100%
rename from chrome/lib/util/public/android/java/src/org/chromium/chrome/browser/util/KeyNavigationUtil.java
rename to chrome/browser/util/android/java/src/org/chromium/chrome/browser/util/KeyNavigationUtil.java
diff --git a/chrome/lib/util/public/android/java/src/org/chromium/chrome/browser/util/MathUtils.java b/chrome/browser/util/android/java/src/org/chromium/chrome/browser/util/MathUtils.java
similarity index 100%
rename from chrome/lib/util/public/android/java/src/org/chromium/chrome/browser/util/MathUtils.java
rename to chrome/browser/util/android/java/src/org/chromium/chrome/browser/util/MathUtils.java
diff --git a/chrome/lib/util/public/android/java/src/org/chromium/chrome/browser/util/UrlConstants.java b/chrome/browser/util/android/java/src/org/chromium/chrome/browser/util/UrlConstants.java
similarity index 100%
rename from chrome/lib/util/public/android/java/src/org/chromium/chrome/browser/util/UrlConstants.java
rename to chrome/browser/util/android/java/src/org/chromium/chrome/browser/util/UrlConstants.java
diff --git a/chrome/lib/util/public/android/java/src/org/chromium/chrome/browser/util/UrlUtilities.java b/chrome/browser/util/android/java/src/org/chromium/chrome/browser/util/UrlUtilities.java
similarity index 100%
rename from chrome/lib/util/public/android/java/src/org/chromium/chrome/browser/util/UrlUtilities.java
rename to chrome/browser/util/android/java/src/org/chromium/chrome/browser/util/UrlUtilities.java
diff --git a/chrome/browser/web_applications/system_web_app_manager.cc b/chrome/browser/web_applications/system_web_app_manager.cc
index ed3ec02..39a6025 100644
--- a/chrome/browser/web_applications/system_web_app_manager.cc
+++ b/chrome/browser/web_applications/system_web_app_manager.cc
@@ -63,6 +63,9 @@
     infos[SystemAppType::SETTINGS].uninstall_and_replace = {
         app_list::kInternalAppIdSettings};
   }
+  // Large enough to see the heading text "Settings" in the top-left.
+  infos[SystemAppType::SETTINGS].minimum_window_size = {200, 100};
+
   if (SystemWebAppManager::IsAppEnabled(SystemAppType::TERMINAL)) {
     constexpr char kChromeTerminalPWAURL[] = "chrome://terminal/html/pwa.html";
     infos[SystemAppType::TERMINAL].install_url = GURL(kChromeTerminalPWAURL);
@@ -194,6 +197,17 @@
       app_id, ExternalInstallSource::kSystemInstalled);
 }
 
+gfx::Size SystemWebAppManager::GetMinimumWindowSize(const AppId& app_id) const {
+  auto app_type_it = app_id_to_app_type_.find(app_id);
+  if (app_type_it == app_id_to_app_type_.end())
+    return gfx::Size();
+  const SystemAppType& app_type = app_type_it->second;
+  auto app_info_it = system_app_infos_.find(app_type);
+  if (app_info_it == system_app_infos_.end())
+    return gfx::Size();
+  return app_info_it->second.minimum_window_size;
+}
+
 void SystemWebAppManager::SetSystemAppsForTesting(
     base::flat_map<SystemAppType, SystemAppInfo> system_apps) {
   system_app_infos_ = std::move(system_apps);
@@ -229,6 +243,15 @@
   RecordExternalAppInstallResultCode(kInstallResultHistogramName,
                                      install_results);
 
+  // Build the map from installed app id to app type.
+  for (const auto& it : system_app_infos_) {
+    const SystemAppType& app_type = it.first;
+    base::Optional<AppId> app_id =
+        registrar_->LookupExternalAppId(it.second.install_url);
+    if (app_id.has_value())
+      app_id_to_app_type_[app_id.value()] = app_type;
+  }
+
   // May be called more than once in tests.
   if (!on_apps_synchronized_->is_signaled())
     on_apps_synchronized_->Signal();
diff --git a/chrome/browser/web_applications/system_web_app_manager.h b/chrome/browser/web_applications/system_web_app_manager.h
index fad7d363..8256343 100644
--- a/chrome/browser/web_applications/system_web_app_manager.h
+++ b/chrome/browser/web_applications/system_web_app_manager.h
@@ -16,6 +16,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/one_shot_event.h"
 #include "chrome/browser/web_applications/components/pending_app_manager.h"
+#include "ui/gfx/geometry/size.h"
 #include "url/gurl.h"
 
 namespace base {
@@ -55,6 +56,11 @@
   // If specified, the apps in |uninstall_and_replace| will have their data
   // migrated to this System App.
   std::vector<AppId> uninstall_and_replace;
+
+  // Minimum window size in DIPs. Empty if the app does not have a minimum.
+  // TODO(https://github.com/w3c/manifest/issues/436): Replace with PWA manifest
+  // properties for window size.
+  gfx::Size minimum_window_size;
 };
 
 // Installs, uninstalls, and updates System Web Apps.
@@ -104,6 +110,10 @@
   // Returns whether |app_id| points to an installed System App.
   bool IsSystemWebApp(const AppId& app_id) const;
 
+  // Returns the minimum window size for |app_id| or an empty size if the app
+  // doesn't specify a minimum.
+  gfx::Size GetMinimumWindowSize(const AppId& app_id) const;
+
   const base::OneShotEvent& on_apps_synchronized() const {
     return *on_apps_synchronized_;
   }
@@ -127,6 +137,8 @@
 
   base::flat_map<SystemAppType, SystemAppInfo> system_app_infos_;
 
+  base::flat_map<AppId, SystemAppType> app_id_to_app_type_;
+
   PrefService* pref_service_;
 
   // Used to install, uninstall, and update apps. Should outlive this class.
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index febb1e8..0b334d1 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -518,6 +518,14 @@
 const base::Feature kNoReferrers{"NoReferrers",
                                  base::FEATURE_DISABLED_BY_DEFAULT};
 
+#if defined(OS_WIN)
+// Changes behavior of requireInteraction for notifications. Instead of staying
+// on-screen until dismissed, they are instead shown for a very long time.
+const base::Feature kNotificationDurationLongForRequireInteraction{
+    "NotificationDurationLongForRequireInteraction",
+    base::FEATURE_DISABLED_BY_DEFAULT};
+#endif  // OS_WIN
+
 #if defined(OS_POSIX)
 // Enables NTLMv2, which implicitly disables NTLMv1.
 const base::Feature kNtlmV2Enabled{"NtlmV2Enabled",
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 48f9e8f0..bac1345 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -333,6 +333,11 @@
 
 COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kNoReferrers;
 
+#if defined(OS_WIN)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kNotificationDurationLongForRequireInteraction;
+#endif
+
 #if defined(OS_POSIX)
 COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kNtlmV2Enabled;
 #endif
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json
index 3a24e6d..b175c47 100644
--- a/chrome/common/extensions/api/_api_features.json
+++ b/chrome/common/extensions/api/_api_features.json
@@ -662,6 +662,10 @@
     "contexts": ["blessed_extension"],
     "disallow_for_service_workers": true
   }],
+  "printingMetrics": {
+    "dependencies": ["permission:printingMetrics"],
+    "contexts": ["blessed_extension"]
+  },
   "privacy": {
     "dependencies": ["permission:privacy"],
     "contexts": ["blessed_extension"]
diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json
index 195d76f..def914b 100644
--- a/chrome/common/extensions/api/_permission_features.json
+++ b/chrome/common/extensions/api/_permission_features.json
@@ -615,6 +615,12 @@
     "channel": "stable",
     "extension_types": ["extension", "legacy_packaged_app"]
   },
+  "printingMetrics": {
+    "channel": "dev",
+    "platforms": ["chromeos"],
+    "extension_types": ["extension"],
+    "location": "policy"
+  },
   "privacy": {
     "channel": "stable",
     "extension_types": ["extension", "legacy_packaged_app"]
diff --git a/chrome/common/extensions/api/api_sources.gni b/chrome/common/extensions/api/api_sources.gni
index 67e412b..77ce3a76 100644
--- a/chrome/common/extensions/api/api_sources.gni
+++ b/chrome/common/extensions/api/api_sources.gni
@@ -103,6 +103,7 @@
     "login_state.idl",
     "platform_keys.idl",
     "platform_keys_internal.idl",
+    "printing_metrics.idl",
     "quick_unlock_private.idl",
     "terminal_private.json",
     "users_private.idl",
diff --git a/chrome/common/extensions/api/printing_metrics.idl b/chrome/common/extensions/api/printing_metrics.idl
new file mode 100644
index 0000000..eb0b1ec
--- /dev/null
+++ b/chrome/common/extensions/api/printing_metrics.idl
@@ -0,0 +1,147 @@
+// 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.
+
+// Use the <code>chrome.printingMetrics</code> API to fetch data about
+// printing usage.
+[platforms=("chromeos"),
+ implemented_in="chrome/browser/chromeos/extensions/printing_metrics/printing_metrics_api.h"]
+namespace printingMetrics {
+  // The source of the print job.
+  enum PrintJobSource {
+    // The job was created from the Print Preview page initiated by the user.
+    PRINT_PREVIEW,
+
+    // The job was created from an Android App.
+    ANDROID_APP
+  };
+
+  // The final status of the print job.
+  enum PrintJobStatus {
+    // Print job was interrupted due to some error.
+   FAILED,
+
+   // Print job was canceled by the user or via API.
+   CANCELED,
+
+   // Print job was printed without any errors.
+   PRINTED
+  };
+
+  // The source of the printer.
+  enum PrinterSource {
+    // Printer was added by user.
+    USER,
+
+    // Printer was added via policy.
+    POLICY
+  };
+
+  enum ColorMode {
+    // Black and white mode was used.
+    BLACK_AND_WHITE,
+
+    // Color mode was used.
+    COLOR
+  };
+
+  enum DuplexMode {
+    // One-sided printing was used.
+    ONE_SIDED,
+
+    // Two-sided printing was used, flipping on long edge.
+    TWO_SIDED_LONG_EDGE,
+
+    // Two-sided printing was used, flipping on short edge.
+    TWO_SIDED_SHORT_EDGE
+  };
+
+  // The size of requested media.
+  dictionary MediaSize {
+    // Width (in micrometers) of the media used for printing.
+    long width;
+
+    // Height (in micrometers) of the media used for printing.
+    long height;
+
+    // Vendor-provided ID, e.g. "iso_a3_297x420mm" or "na_index-3x5_3x5in".
+    // Possible values are values of "media" IPP attribute and can be found on
+    // <a href="https://www.iana.org/assignments/ipp-registrations/ipp-registrations.xhtml">
+    // IANA page</a> .
+    DOMString vendorId;
+  };
+
+  // The requested settings of print job.
+  dictionary PrintSettings {
+    // The requested color mode.
+    ColorMode color;
+
+    // The requested duplex mode.
+    DuplexMode duplex;
+
+    // The requested media size.
+    MediaSize mediaSize;
+
+    // The requested number of copies.
+    long copies;
+  };
+
+  // The printer info.
+  dictionary Printer {
+    // Displayed name of the printer.
+    DOMString name;
+
+    // The full path for the printer.
+    // Contains protocol, hostname, port, and queue.
+    DOMString uri;
+
+    // The source of the printer.
+    PrinterSource source;
+  };
+
+  // Print job information.
+  dictionary PrintJobInfo {
+    // The ID of the job.
+    DOMString id;
+
+    // The title of the document which was printed.
+    DOMString title;
+
+    // Source showing who initiated the print job.
+    PrintJobSource source;
+
+    // ID of source. Null if source is PRINT_PREVIEW or ANDROID_APP.
+    DOMString? sourceId;
+
+    // The final status of the job.
+    PrintJobStatus status;
+
+    // The job creation time (in milliseconds past the Unix epoch).
+    double creationTime;
+
+    // The job completion time (in milliseconds past the Unix epoch).
+    double completionTime;
+
+    // The info about the printer which printed the document.
+    Printer printer;
+
+    // The settings of the print job.
+    PrintSettings settings;
+
+    // The number of pages in the document.
+    long numberOfPages;
+  };
+
+  callback GetPrintJobsCallback = void(PrintJobInfo[] jobs);
+
+  interface Functions {
+    // Returns the list of the finished print jobs.
+    static void getPrintJobs(GetPrintJobsCallback callback);
+  };
+
+  interface Events {
+    // Event fired when the print job is finished.
+    // This includes any of termination statuses: FAILED, CANCELED and PRINTED.
+    static void onPrintJobFinished(PrintJobInfo jobInfo);
+  };
+};
diff --git a/chrome/common/extensions/permissions/permission_set_unittest.cc b/chrome/common/extensions/permissions/permission_set_unittest.cc
index e43cd3f..c5f2e90c 100644
--- a/chrome/common/extensions/permissions/permission_set_unittest.cc
+++ b/chrome/common/extensions/permissions/permission_set_unittest.cc
@@ -794,6 +794,9 @@
   // and don't require a prompt, i.e. they're restricted to location 'policy'.
   skip.insert(APIPermission::kEnterprisePlatformKeys);
   skip.insert(APIPermission::kEnterpriseDeviceAttributes);
+  // TODO (crbug/992889): Remove this when permission warning strings will be
+  // added.
+  skip.insert(APIPermission::kPrintingMetrics);
 
   // TODO(erikkay) add a string for this permission.
   skip.insert(APIPermission::kBackground);
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index d8a3807..ab6018a 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -1587,6 +1587,10 @@
 const char kDefaultTasksBySuffix[] =
     "filebrowser.tasks.default_by_suffix";
 
+// A flag to enable/disable the Shared Clipboard feature which enables users to
+// send text across devices.
+const char kSharedClipboardEnabled[] = "browser.shared_clipboard_enabled";
+
 // Extensions which should be opened upon completion.
 const char kDownloadExtensionsToOpen[] = "download.extensions_to_open";
 
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 1bb60ef1..1fa644a 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -528,6 +528,8 @@
 extern const char kDefaultTasksByMimeType[];
 extern const char kDefaultTasksBySuffix[];
 
+extern const char kSharedClipboardEnabled[];
+
 extern const char kSelectFileLastDirectory[];
 
 extern const char kExcludedSchemes[];
diff --git a/chrome/lib/util/public/android/BUILD.gn b/chrome/lib/util/public/android/BUILD.gn
index b75a088..5f6ac9c7 100644
--- a/chrome/lib/util/public/android/BUILD.gn
+++ b/chrome/lib/util/public/android/BUILD.gn
@@ -4,30 +4,9 @@
 
 import("//build/config/android/rules.gni")
 
-android_library("java") {
+# Temporary target until clank removes this as a dependency.
+java_group("java") {
   deps = [
-    "//base:base_java",
-    "//base:jni_java",
-    "//content/public/android:content_java",
-    "//third_party/android_deps:com_android_support_collections_java",
-    "//third_party/android_deps:com_android_support_support_compat_java",
-    "//third_party/android_deps:com_android_support_support_core_utils_java",
-  ]
-  annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
-  java_files = [
-    "java/src/org/chromium/chrome/browser/util/BitmapCache.java",
-    "java/src/org/chromium/chrome/browser/util/ConversionUtils.java",
-    "java/src/org/chromium/chrome/browser/util/FileSizeUtil.java",
-    "java/src/org/chromium/chrome/browser/util/KeyNavigationUtil.java",
-    "java/src/org/chromium/chrome/browser/util/MathUtils.java",
-    "java/src/org/chromium/chrome/browser/util/ChromeFileProvider.java",
-    "java/src/org/chromium/chrome/browser/util/UrlConstants.java",
-    "java/src/org/chromium/chrome/browser/util/UrlUtilities.java",
-  ]
-}
-
-generate_jni("jni_headers") {
-  sources = [
-    "java/src/org/chromium/chrome/browser/util/UrlUtilities.java",
+    "//chrome/browser/util/android:java",
   ]
 }
diff --git a/chrome/renderer/autofill/autofill_renderer_browsertest.cc b/chrome/renderer/autofill/autofill_renderer_browsertest.cc
index 7c61f2dd..f83951e 100644
--- a/chrome/renderer/autofill/autofill_renderer_browsertest.cc
+++ b/chrome/renderer/autofill/autofill_renderer_browsertest.cc
@@ -389,16 +389,12 @@
   while (!full_name.Focused())
     GetMainFrame()->View()->AdvanceFocus(false);
 
-  // Not a user gesture, so no IPC message to browser.
-  DisableUserGestureSimulationForAutofill();
   ASSERT_FALSE(fake_driver_.called_field_change());
   full_name.SetValue("Alice", true);
   GetMainFrame()->AutofillClient()->TextFieldDidChange(full_name);
   base::RunLoop().RunUntilIdle();
   ASSERT_FALSE(fake_driver_.called_field_change());
 
-  // A user gesture will send a message to the browser.
-  EnableUserGestureSimulationForAutofill();
   SimulateUserInputChangeForElement(&full_name, "Alice");
   ASSERT_TRUE(fake_driver_.called_field_change());
 }
diff --git a/chrome/renderer/chrome_render_frame_observer_browsertest.cc b/chrome/renderer/chrome_render_frame_observer_browsertest.cc
index ddd41b0..cc98abd 100644
--- a/chrome/renderer/chrome_render_frame_observer_browsertest.cc
+++ b/chrome/renderer/chrome_render_frame_observer_browsertest.cc
@@ -16,6 +16,7 @@
 #include "content/public/renderer/render_frame.h"
 #include "content/public/renderer/render_view.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "third_party/blink/public/web/web_view.h"
 #include "third_party/blink/public/web/web_widget.h"
@@ -35,7 +36,7 @@
   }
 
   // translate::mojom::ContentTranslateDriver implementation.
-  void RegisterPage(translate::mojom::PagePtr page,
+  void RegisterPage(mojo::PendingRemote<translate::mojom::Page> page,
                     const translate::LanguageDetectionDetails& details,
                     bool page_needs_translation) override {
     called_new_page_ = true;
diff --git a/chrome/renderer/translate/translate_helper_browsertest.cc b/chrome/renderer/translate/translate_helper_browsertest.cc
index d8888c7..762d982 100644
--- a/chrome/renderer/translate/translate_helper_browsertest.cc
+++ b/chrome/renderer/translate/translate_helper_browsertest.cc
@@ -17,6 +17,7 @@
 #include "content/public/renderer/render_view.h"
 #include "extensions/common/constants.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -41,7 +42,7 @@
   }
 
   // translate::mojom::ContentTranslateDriver implementation.
-  void RegisterPage(translate::mojom::PagePtr page,
+  void RegisterPage(mojo::PendingRemote<translate::mojom::Page> page,
                     const translate::LanguageDetectionDetails& details,
                     bool page_needs_translation) override {
     called_new_page_ = true;
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index fbf6a99..8964c0e 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -5147,6 +5147,7 @@
       "../browser/ui/app_list/search/search_result_ranker/recurrence_ranker_unittest.cc",
       "../browser/ui/app_list/search/search_result_ranker/recurrence_ranker_util_unittest.cc",
       "../browser/ui/app_list/search/search_result_ranker/search_result_ranker_unittest.cc",
+      "../browser/ui/app_list/search/search_utils/fuzzy_tokenized_string_match_unittest.cc",
       "../browser/ui/app_list/search/search_utils/sequence_matcher_unittest.cc",
       "../browser/ui/app_list/search/settings_shortcut/settings_shortcut_provider_unittest.cc",
       "../browser/ui/app_list/search/settings_shortcut/settings_shortcut_result_unittest.cc",
diff --git a/chrome/test/base/chrome_render_view_test.cc b/chrome/test/base/chrome_render_view_test.cc
index f8af975..0ae9d1ca 100644
--- a/chrome/test/base/chrome_render_view_test.cc
+++ b/chrome/test/base/chrome_render_view_test.cc
@@ -65,7 +65,6 @@
                       password_autofill_agent,
                       password_generation_agent,
                       registry) {
-    ON_CALL(*this, IsUserGesture()).WillByDefault(Return(true));
   }
 
   ~MockAutofillAgent() override {}
@@ -77,8 +76,6 @@
     run_loop_.reset();
   }
 
-  MOCK_CONST_METHOD0(IsUserGesture, bool());
-
  private:
   void DidAssociateFormControlsDynamically() override {
     AutofillAgent::DidAssociateFormControlsDynamically();
@@ -100,8 +97,7 @@
       chrome_render_thread_(NULL) {
 }
 
-ChromeRenderViewTest::~ChromeRenderViewTest() {
-}
+ChromeRenderViewTest::~ChromeRenderViewTest() = default;
 
 void ChromeRenderViewTest::SetUp() {
   ChromeUnitTestSuite::InitializeProviders();
@@ -177,16 +173,6 @@
 #endif
 }
 
-void ChromeRenderViewTest::EnableUserGestureSimulationForAutofill() {
-  EXPECT_CALL(*(static_cast<MockAutofillAgent*>(autofill_agent_)),
-              IsUserGesture()).WillRepeatedly(Return(true));
-}
-
-void ChromeRenderViewTest::DisableUserGestureSimulationForAutofill() {
-  EXPECT_CALL(*(static_cast<MockAutofillAgent*>(autofill_agent_)),
-              IsUserGesture()).WillRepeatedly(Return(false));
-}
-
 void ChromeRenderViewTest::WaitForAutofillDidAssociateFormControl() {
   static_cast<MockAutofillAgent*>(autofill_agent_)
       ->WaitForAutofillDidAssociateFormControl();
diff --git a/chrome/test/base/chrome_render_view_test.h b/chrome/test/base/chrome_render_view_test.h
index c997b5dd..5a56e1e 100644
--- a/chrome/test/base/chrome_render_view_test.h
+++ b/chrome/test/base/chrome_render_view_test.h
@@ -41,8 +41,6 @@
   // Use when overriding CreateContentRendererClient.
   void InitChromeContentRendererClient(ChromeContentRendererClient* client);
 
-  void EnableUserGestureSimulationForAutofill();
-  void DisableUserGestureSimulationForAutofill();
   void WaitForAutofillDidAssociateFormControl();
 
   autofill::TestPasswordAutofillAgent* password_autofill_agent_;
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index 4475875..23ceadb 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -3808,6 +3808,12 @@
     ]
   },
 
+  "SharedClipboardEnabled" : {
+    "os": ["win", "linux", "mac", "chromeos", "android"],
+    "test_policy": { "SharedClipboardEnabled": false },
+    "pref_mappings": [{ "pref": "browser.shared_clipboard_enabled" }]
+  },
+
   "----- Chrome OS device policies ---------------------------------------": {},
 
   "DevicePolicyRefreshRate": {
diff --git a/chrome/test/data/webui/settings/chromeos/add_users_tests.js b/chrome/test/data/webui/settings/chromeos/add_users_tests.js
index 926fb06a..280aedf 100644
--- a/chrome/test/data/webui/settings/chromeos/add_users_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/add_users_tests.js
@@ -9,6 +9,7 @@
     PolymerTest.clearBody();
 
     dialog = document.createElement('settings-users-add-user-dialog');
+    dialog.usersPrivate_ = new settings.FakeUsersPrivate();
 
     document.body.appendChild(dialog);
 
@@ -48,4 +49,56 @@
     assertTrue(addButton.disabled);
     assertTrue(userInputBox.invalid);
   });
+
+  test('Add duplicate user', function() {
+    const userInputBox = dialog.$$('#addUserInput');
+    const addButton = dialog.$$('.action-button');
+    const duplicateUserEmail = 'duplicateUser@google.com';
+
+    // Add user for the first time.
+    userInputBox.value = duplicateUserEmail;
+    addButton.click();
+    assertEquals('', userInputBox.value);
+    assertFalse(userInputBox.invalid);
+    assertEquals('', userInputBox.errorMessage);
+
+    // Add user for the second time. It should be registered as a duplicate and
+    // will create an error message.
+    userInputBox.value = duplicateUserEmail;
+    addButton.click();
+    assertEquals(duplicateUserEmail, userInputBox.value);
+    assertTrue(userInputBox.invalid);
+    assertNotEquals('', userInputBox.errorMessage);
+  });
+
+  test('Add new user', function() {
+    const userInputBox = dialog.$$('#addUserInput');
+    const addButton = dialog.$$('.action-button');
+    const newUserEmail = 'newUser@google.com';
+
+    userInputBox.value = newUserEmail;
+    addButton.click();
+    assertEquals('', userInputBox.value);
+    assertFalse(userInputBox.invalid);
+    assertEquals('', userInputBox.errorMessage);
+  });
+
+  test('Add two new users', function() {
+    const userInputBox = dialog.$$('#addUserInput');
+    const addButton = dialog.$$('.action-button');
+    const firstUserEmail = 'firstUser@google.com';
+    const secondUserEmail = 'secondUser@google.com';
+
+    userInputBox.value = firstUserEmail;
+    addButton.click();
+    assertEquals('', userInputBox.value);
+    assertFalse(userInputBox.invalid);
+    assertEquals('', userInputBox.errorMessage);
+
+    userInputBox.value = secondUserEmail;
+    addButton.click();
+    assertEquals('', userInputBox.value);
+    assertFalse(userInputBox.invalid);
+    assertEquals('', userInputBox.errorMessage);
+  });
 });
diff --git a/chrome/test/data/webui/settings/chromeos/fake_users_private.js b/chrome/test/data/webui/settings/chromeos/fake_users_private.js
new file mode 100644
index 0000000..e437122
--- /dev/null
+++ b/chrome/test/data/webui/settings/chromeos/fake_users_private.js
@@ -0,0 +1,33 @@
+// 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.
+
+/**
+ * @fileoverview Fake implementation of chrome.usersPrivate
+ * for testing.
+ */
+cr.define('settings', function() {
+  /**
+   * Fake of the chrome.usersPrivate API. Only methods that are called
+   * during testing have been implemented.
+   *
+   * @constructor
+   * @implements {UsersPrivate}
+   */
+  function FakeUsersPrivate() {
+  }
+
+  FakeUsersPrivate.prototype = {
+    users: [],
+
+    addWhitelistedUser: function(user) {
+      this.users.push(user);
+    },
+
+    isWhitelistedUser: function(user, callback) {
+      callback(this.users.includes(user));
+    },
+  };
+
+  return {FakeUsersPrivate: FakeUsersPrivate};
+});
\ No newline at end of file
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
index ce06f70..3f1844942 100644
--- a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
@@ -89,6 +89,8 @@
   /** @override */
   get extraLibraries() {
     return super.extraLibraries.concat([
+      BROWSER_SETTINGS_PATH + '../fake_chrome_event.js',
+      'fake_users_private.js',
       'add_users_tests.js',
     ]);
   }
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js
index a652b35..ffaa061 100644
--- a/chrome/test/data/webui/settings/cr_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -2495,6 +2495,8 @@
 
   /** @override */
   extraLibraries: CrSettingsBrowserTestCrOS.prototype.extraLibraries.concat([
+    '../fake_chrome_event.js',
+    'chromeos/fake_users_private.js',
     'chromeos/add_users_tests.js',
   ]),
 };
diff --git a/chromecast/common/extensions_api/i18n.json b/chromecast/common/extensions_api/i18n.json
index d9fc392..d819d311 100644
--- a/chromecast/common/extensions_api/i18n.json
+++ b/chromecast/common/extensions_api/i18n.json
@@ -44,6 +44,18 @@
             "name": "substitutions",
             "optional": true,
             "description": "Up to 9 substitution strings, if the message requires any."
+          },
+          {
+            "type": "object",
+            "name": "options",
+            "optional": true,
+            "properties": {
+              "escapeLt": {
+                "type": "boolean",
+                "optional": true,
+                "description": "Escape <code>&lt;</code> in translation to <code>&amp;lt;</code>. This applies only to the message itself, not to the placeholders. Developers might want to use this if the translation is used in an HTML context. Closure Templates used with Closure Compiler generate this automatically."
+              }
+            }
           }
         ],
         "returns": {
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc
index 5917687..65f42c9c 100644
--- a/components/autofill/content/renderer/autofill_agent.cc
+++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -820,11 +820,6 @@
   GetAutofillDriver()->HidePopup();
 }
 
-bool AutofillAgent::IsUserGesture() const {
-  return WebUserGestureIndicator::IsProcessingUserGesture(
-      render_frame()->GetWebFrame());
-}
-
 void AutofillAgent::DidAssociateFormControlsDynamically() {
   // If the control flow is here than the document was at least loaded. The
   // whole page doesn't have to be loaded.
diff --git a/components/autofill/content/renderer/autofill_agent.h b/components/autofill/content/renderer/autofill_agent.h
index 69231a1..cdf54f0 100644
--- a/components/autofill/content/renderer/autofill_agent.h
+++ b/components/autofill/content/renderer/autofill_agent.h
@@ -40,7 +40,6 @@
 namespace autofill {
 
 struct FormData;
-struct FormFieldData;
 class PasswordAutofillAgent;
 class PasswordGenerationAgent;
 
@@ -229,12 +228,6 @@
   // Sets the element value to reflect the selected |suggested_value|.
   void DoAcceptDataListSuggestion(const base::string16& suggested_value);
 
-  // Fills |form| and |field| with the FormData and FormField corresponding to
-  // |node|. Returns true if the data was found; and false otherwise.
-  bool FindFormAndFieldForNode(const blink::WebNode& node,
-                               FormData* form,
-                               FormFieldData* field) WARN_UNUSED_RESULT;
-
   // Set |node| to display the given |value|.
   void DoFillFieldWithValue(const base::string16& value,
                             blink::WebInputElement* node);
@@ -248,24 +241,9 @@
   // Notifies browser of new fillable forms in |render_frame|.
   void ProcessForms();
 
-  // Sends a message to the browser that the form is about to be submitted,
-  // only if the particular message has not been previously submitted for the
-  // form in the current frame.
-  // Additionally, depending on |send_submitted_event| a message is sent to the
-  // browser that the form was submitted.
-  void SendFormEvents(const blink::WebFormElement& form,
-                      bool send_submitted_event);
-
   // Hides any currently showing Autofill popup.
   void HidePopup();
 
-  // TODO(crbug.com/785524): Investigate why this method need to be mocked in
-  // chrome_render_view_test.cc, this isn't called now, but this is no test
-  // failed.
-  // Returns true if the text field change is due to a user gesture. Can be
-  // overriden in tests.
-  virtual bool IsUserGesture() const;
-
   // Attempt to get submitted FormData from last_interacted_form_ or
   // provisionally_saved_form_, return true if |form| is set.
   bool GetSubmittedForm(FormData* form);
diff --git a/components/autofill/content/renderer/form_autofill_util.cc b/components/autofill/content/renderer/form_autofill_util.cc
index c33dba2f..2d96baf 100644
--- a/components/autofill/content/renderer/form_autofill_util.cc
+++ b/components/autofill/content/renderer/form_autofill_util.cc
@@ -1486,57 +1486,22 @@
       data, nullptr);
 }
 
-bool IsFormVisible(blink::WebLocalFrame* frame,
-                   const blink::WebFormElement& form_element,
-                   const GURL& canonical_action,
-                   const GURL& canonical_origin,
-                   const FormData& form_data) {
-  const GURL frame_origin = GetCanonicalOriginForDocument(frame->GetDocument());
-  blink::WebVector<WebFormElement> forms;
-  frame->GetDocument().Forms(forms);
+bool IsFormVisible(blink::WebLocalFrame* frame, uint32_t form_renderer_id) {
+  WebDocument doc = frame->GetDocument();
+  if (doc.IsNull())
+    return false;
+  WebFormElement form = FindFormByUniqueRendererId(doc, form_renderer_id);
+  return form.IsNull() ? false : AreFormContentsVisible(form);
+}
 
-  // Omitting the action attribute would result in |canonical_origin| for
-  // hierarchical schemes like http:, and in an empty URL for non-hierarchical
-  // schemes like about: or data: etc.
-  const bool action_is_empty = canonical_action.is_empty()
-                               || canonical_action == canonical_origin;
-
-  // Since empty or unspecified action fields are automatically set to page URL,
-  // action field for forms cannot be used for comparing (all forms with
-  // empty/unspecified actions have the same value). If an action field is set
-  // to the page URL, this method checks ALL fields of the form instead (using
-  // FormData.SameFormAs). This is also true if the action was set to the page
-  // URL on purpose.
-  for (const WebFormElement& form : forms) {
-    if (!AreFormContentsVisible(form))
-      continue;
-
-    // Try to match the WebFormElement reference first.
-    if (!form_element.IsNull() && form == form_element) {
-      return true;  // Form still exists.
-    }
-
-    GURL iter_canonical_action = GetCanonicalActionForForm(form);
-    bool form_action_is_empty = iter_canonical_action.is_empty() ||
-                                iter_canonical_action == frame_origin;
-    if (action_is_empty != form_action_is_empty)
-      continue;
-
-    if (action_is_empty) {  // Both actions are empty, compare all fields.
-      FormData extracted_form_data;
-      WebFormElementToFormData(form, WebFormControlElement(), nullptr,
-                               EXTRACT_NONE, &extracted_form_data, nullptr);
-      if (form_data.SameFormAs(extracted_form_data)) {
-        return true;  // Form still exists.
-      }
-    } else {  // Both actions are non-empty, compare actions only.
-      if (canonical_action == iter_canonical_action) {
-        return true;  // Form still exists.
-      }
-    }
-  }
-
-  return false;
+bool IsFormControlVisible(blink::WebLocalFrame* frame,
+                          uint32_t field_renderer_id) {
+  WebDocument doc = frame->GetDocument();
+  if (doc.IsNull())
+    return false;
+  WebFormControlElement field =
+      FindFormControlElementsByUniqueRendererId(doc, field_renderer_id);
+  return field.IsNull() ? false : IsWebElementVisible(field);
 }
 
 bool IsSomeControlElementVisible(
diff --git a/components/autofill/content/renderer/form_autofill_util.h b/components/autofill/content/renderer/form_autofill_util.h
index bb64fb7..bb82da8 100644
--- a/components/autofill/content/renderer/form_autofill_util.h
+++ b/components/autofill/content/renderer/form_autofill_util.h
@@ -71,15 +71,14 @@
 // successful.
 bool ExtractFormData(const blink::WebFormElement& form_element, FormData* data);
 
-// Helper function to check if there exist any visible form on |frame| which
-// equals |form_element|. If |form_element| is null, checks if forms action
-// equals |action|. Returns true if so. For forms with empty or unspecified
-// actions, all form data are used for comparison.
-bool IsFormVisible(blink::WebLocalFrame* frame,
-                   const blink::WebFormElement& form_element,
-                   const GURL& action,
-                   const GURL& origin,
-                   const FormData& form_data);
+// Helper function to check if a form with renderer id |form_renderer_id| exists
+// in |frame| and is visible.
+bool IsFormVisible(blink::WebLocalFrame* frame, uint32_t form_renderer_id);
+
+// Helper function to check if a field with renderer id |field_renderer_id|
+// exists in |frame| and is visible.
+bool IsFormControlVisible(blink::WebLocalFrame* frame,
+                          uint32_t field_renderer_id);
 
 // Returns true if at least one element from |control_elements| is visible.
 bool IsSomeControlElementVisible(
diff --git a/components/autofill/content/renderer/form_autofill_util_browsertest.cc b/components/autofill/content/renderer/form_autofill_util_browsertest.cc
index 18df823..bbec17a5 100644
--- a/components/autofill/content/renderer/form_autofill_util_browsertest.cc
+++ b/components/autofill/content/renderer/form_autofill_util_browsertest.cc
@@ -692,3 +692,30 @@
   EXPECT_EQ(autofill::form_util::GetAriaDescription(doc, element),
             base::UTF8ToUTF16(""));
 }
+
+TEST_F(FormAutofillUtilsTest, IsFormVisible) {
+  LoadHTML("<body><form id='form1'><input id='i1'></form></body>");
+  WebDocument doc = GetMainFrame()->GetDocument();
+  auto form = doc.GetElementById("form1").To<WebFormElement>();
+  uint32_t form_id = form.UniqueRendererFormId();
+
+  EXPECT_TRUE(autofill::form_util::IsFormVisible(GetMainFrame(), form_id));
+
+  // Hide a form.
+  form.SetAttribute("style", "display:none");
+  EXPECT_FALSE(autofill::form_util::IsFormVisible(GetMainFrame(), form_id));
+}
+
+TEST_F(FormAutofillUtilsTest, IsFormControlVisible) {
+  LoadHTML("<body><input id='input1'></body>");
+  WebDocument doc = GetMainFrame()->GetDocument();
+  auto input = doc.GetElementById("input1").To<WebFormControlElement>();
+  uint32_t input_id = input.UniqueRendererFormControlId();
+
+  EXPECT_TRUE(
+      autofill::form_util::IsFormControlVisible(GetMainFrame(), input_id));
+
+  // Hide a field.
+  input.SetAttribute("style", "display:none");
+  EXPECT_FALSE(autofill::form_util::IsFormVisible(GetMainFrame(), input_id));
+}
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc
index fa7f585..e5006fd0 100644
--- a/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -72,6 +72,9 @@
 
 namespace autofill {
 
+using form_util::IsFormControlVisible;
+using form_util::IsFormVisible;
+
 using mojom::FocusedFieldType;
 using mojom::SubmissionIndicatorEvent;
 using mojom::SubmissionSource;
@@ -117,11 +120,6 @@
                base::ASCIIToUTF16(kDummyUsernameField)));
 }
 
-bool IsUnownedPasswordFormVisible(const WebInputElement& input_element) {
-  return !input_element.IsNull() &&
-         form_util::IsWebElementVisible(input_element);
-}
-
 bool IsElementEditable(const WebInputElement& element) {
   return element.IsEnabled() && !element.IsReadOnly();
 }
@@ -898,18 +896,22 @@
   // Prompt to save only if the form is now gone, either invisible or
   // removed from the DOM.
   WebLocalFrame* frame = render_frame()->GetWebFrame();
-  const auto& password_form = provisionally_saved_form_.password_form();
   // TODO(crbug.com/720347): This method could be called often and checking form
-  // visibility could be expesive. Add performance metrics for this.
+  // visibility could be expensive. Add performance metrics for this.
   if (event != SubmissionIndicatorEvent::DOM_MUTATION_AFTER_XHR) {
-    if (form_util::IsFormVisible(frame,
-                                 provisionally_saved_form_.form_element(),
-                                 password_form.action, password_form.origin,
-                                 password_form.form_data) ||
-        (provisionally_saved_form_.form_element().IsNull() &&
-         IsUnownedPasswordFormVisible(
-             provisionally_saved_form_.input_element()))) {
-      return;
+    bool is_last_updated_field_in_form =
+        last_updated_form_renderer_id_ != FormData::kNotSetFormRendererId;
+    // Check whether the form which is the candidate for submission disappeared.
+    // If yes this form is considered to be successfully submitted.
+    if (is_last_updated_field_in_form) {
+      // A form is inside <form> tag. Check the visibility of the whole form.
+      if (IsFormVisible(frame, last_updated_form_renderer_id_))
+        return;
+    } else {
+      // A form is without <form> tag. Check the visibility of the last updated
+      // field.
+      if (IsFormControlVisible(frame, last_updated_field_renderer_id_))
+        return;
     }
   }
 
@@ -1401,6 +1403,8 @@
   username_detector_cache_.clear();
   forms_structure_cache_.clear();
   autofilled_elements_cache_.clear();
+  last_updated_field_renderer_id_ = FormData::kNotSetFormRendererId;
+  last_updated_form_renderer_id_ = FormData::kNotSetFormRendererId;
 #if !defined(OS_ANDROID) && !defined(OS_IOS)
   page_passwords_analyser_.Reset();
 #endif
@@ -1425,6 +1429,7 @@
     ProvisionallySaveRestriction restriction) {
   DCHECK(!form.IsNull() || !element.IsNull());
 
+  SetLastUpdatedFormAndField(form, element);
   std::unique_ptr<PasswordForm> password_form;
   if (form.IsNull()) {
     password_form = GetPasswordFormFromUnownedInputElements();
@@ -1827,4 +1832,17 @@
                                      WebString::FromUTF16(value));
 }
 
+void SetLastUpdatedFormAndField(const blink::WebFormElement& Form,
+                                const blink::WebFormControlElement& input);
+void PasswordAutofillAgent::SetLastUpdatedFormAndField(
+    const WebFormElement& form,
+    const WebFormControlElement& input) {
+  last_updated_form_renderer_id_ = form.IsNull()
+                                       ? FormData::kNotSetFormRendererId
+                                       : form.UniqueRendererFormId();
+  last_updated_field_renderer_id_ = input.IsNull()
+                                        ? FormData::kNotSetFormRendererId
+                                        : input.UniqueRendererFormControlId();
+}
+
 }  // namespace autofill
diff --git a/components/autofill/content/renderer/password_autofill_agent.h b/components/autofill/content/renderer/password_autofill_agent.h
index 069545e..a957b5c 100644
--- a/components/autofill/content/renderer/password_autofill_agent.h
+++ b/components/autofill/content/renderer/password_autofill_agent.h
@@ -196,11 +196,6 @@
                        bool show_all,
                        bool generation_popup_showing);
 
-  // Shows an Autofill-style popup with a warning that the form is not secure.
-  // This UI is shown when a username or password field is autofilled or edited
-  // on a non-secure page.
-  void ShowNotSecureWarning(const blink::WebInputElement& element);
-
   // Called when new form controls are inserted.
   void OnDynamicFormsSeen();
 
@@ -453,6 +448,9 @@
   // non-null.
   void AutofillField(const base::string16& value, blink::WebInputElement field);
 
+  void SetLastUpdatedFormAndField(const blink::WebFormElement& form,
+                                  const blink::WebFormControlElement& input);
+
   // The logins we have filled so far with their associated info.
   WebInputToPasswordInfoMap web_input_to_password_info_;
   // A (sort-of) reverse map to |web_input_to_password_info_|.
@@ -537,6 +535,11 @@
   // DidCommitProvisionalLoad() but only for non-same-document-navigations.
   bool recorded_first_filling_result_ = false;
 
+  // Contains renderer id of last updated input element.
+  uint32_t last_updated_field_renderer_id_ = FormData::kNotSetFormRendererId;
+  // Contains renderer id of the form of the last updated input element.
+  uint32_t last_updated_form_renderer_id_ = FormData::kNotSetFormRendererId;
+
   DISALLOW_COPY_AND_ASSIGN(PasswordAutofillAgent);
 };
 
diff --git a/components/autofill/core/common/form_data.h b/components/autofill/core/common/form_data.h
index 920152e..2f69f52 100644
--- a/components/autofill/core/common/form_data.h
+++ b/components/autofill/core/common/form_data.h
@@ -29,6 +29,8 @@
 
 // Holds information about a form to be filled and/or submitted.
 struct FormData {
+  // TODO(https://crbug.com/875768): Rename this const to kNotSetRendererId, and
+  // use it also for not set renderer ids in FormFieldData.
   static constexpr uint32_t kNotSetFormRendererId =
       std::numeric_limits<uint32_t>::max();
 
diff --git a/components/autofill_assistant/browser/website_login_fetcher_impl.cc b/components/autofill_assistant/browser/website_login_fetcher_impl.cc
index 46a50894..8352ced 100644
--- a/components/autofill_assistant/browser/website_login_fetcher_impl.cc
+++ b/components/autofill_assistant/browser/website_login_fetcher_impl.cc
@@ -46,14 +46,21 @@
     // This needs to be done asynchronously, because it will lead to the
     // destruction of |this|, which needs to happen *after* this call has
     // returned.
-    base::PostTask(FROM_HERE, {content::BrowserThread::UI},
-                   base::BindOnce(&PendingRequest::NotifyFinished,
-                                  weak_ptr_factory_.GetWeakPtr()));
+    if (notify_finished_callback_) {
+      base::PostTask(FROM_HERE, {content::BrowserThread::UI},
+                     base::BindOnce(&PendingRequest::NotifyFinished,
+                                    weak_ptr_factory_.GetWeakPtr(),
+                                    std::move(notify_finished_callback_)));
+    }
   }
   std::unique_ptr<password_manager::FormFetcher> form_fetcher_;
 
  private:
-  void NotifyFinished() { std::move(notify_finished_callback_).Run(this); }
+  void NotifyFinished(
+      base::OnceCallback<void(const PendingRequest*)> callback) {
+    form_fetcher_->RemoveConsumer(this);
+    std::move(callback).Run(this);
+  }
 
   base::OnceCallback<void(const PendingRequest*)> notify_finished_callback_;
   base::WeakPtrFactory<PendingRequest> weak_ptr_factory_;
diff --git a/components/module_installer/android/BUILD.gn b/components/module_installer/android/BUILD.gn
index e69502f..456bab4 100644
--- a/components/module_installer/android/BUILD.gn
+++ b/components/module_installer/android/BUILD.gn
@@ -29,8 +29,6 @@
   srcjar_deps = [ ":module_installer_build_config" ]
 
   jar_excluded_patterns = [ "*/ModuleInstallerConfig.class" ]
-
-  jacoco_never_instrument = true
 }
 
 android_library("module_installer_test_java") {
diff --git a/components/password_manager/core/browser/android_affiliation/affiliation_database.cc b/components/password_manager/core/browser/android_affiliation/affiliation_database.cc
index 9d87d48..840cae4 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliation_database.cc
+++ b/components/password_manager/core/browser/android_affiliation/affiliation_database.cc
@@ -174,24 +174,6 @@
   transaction.Commit();
 }
 
-void AffiliationDatabase::DeleteAffiliationsAndBrandingOlderThan(
-    const base::Time& cutoff_threshold) {
-  // Children will get deleted due to 'ON DELETE CASCADE'.
-  sql::Statement statement_parent(sql_connection_->GetCachedStatement(
-      SQL_FROM_HERE,
-      "DELETE FROM eq_classes "
-      "WHERE eq_classes.last_update_time < ?"));
-  statement_parent.BindInt64(0, cutoff_threshold.ToInternalValue());
-  statement_parent.Run();
-}
-
-void AffiliationDatabase::DeleteAllAffiliationsAndBranding() {
-  // Children will get deleted due to 'ON DELETE CASCADE'.
-  sql::Statement statement_parent(
-      sql_connection_->GetUniqueStatement("DELETE FROM eq_classes"));
-  statement_parent.Run();
-}
-
 bool AffiliationDatabase::Store(
     const AffiliatedFacetsWithUpdateTime& affiliated_facets) {
   DCHECK(!affiliated_facets.facets.empty());
diff --git a/components/password_manager/core/browser/android_affiliation/affiliation_database.h b/components/password_manager/core/browser/android_affiliation/affiliation_database.h
index d3cc524..84ea89d 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliation_database.h
+++ b/components/password_manager/core/browser/android_affiliation/affiliation_database.h
@@ -57,14 +57,6 @@
   // containing |facet_uri|.
   void DeleteAffiliationsAndBrandingForFacetURI(const FacetURI& facet_uri);
 
-  // Removes stored equivalence classes and branding information that were last
-  // updated before the |cutoff_threshold|.
-  void DeleteAffiliationsAndBrandingOlderThan(
-      const base::Time& cutoff_threshold);
-
-  // Removes all records from all tables of the database.
-  void DeleteAllAffiliationsAndBranding();
-
   // Stores the equivalence class and branding information defined by
   // |affiliated_facets| to the DB and returns true unless it has a non-empty
   // subset with a preexisting class, in which case no changes are made and the
diff --git a/components/password_manager/core/browser/android_affiliation/affiliation_database_unittest.cc b/components/password_manager/core/browser/android_affiliation/affiliation_database_unittest.cc
index 41a22de..56d311b 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliation_database_unittest.cc
+++ b/components/password_manager/core/browser/android_affiliation/affiliation_database_unittest.cc
@@ -243,40 +243,6 @@
   }
 }
 
-TEST_F(AffiliationDatabaseTest, DeleteAllAffiliationsAndBranding) {
-  db().DeleteAllAffiliationsAndBranding();
-
-  ASSERT_NO_FATAL_FAILURE(StoreInitialTestData());
-
-  db().DeleteAllAffiliationsAndBranding();
-
-  std::vector<AffiliatedFacetsWithUpdateTime> affiliations;
-  db().GetAllAffiliationsAndBranding(&affiliations);
-  ASSERT_EQ(0u, affiliations.size());
-}
-
-TEST_F(AffiliationDatabaseTest, DeleteAffiliationsAndBrandingOlderThan) {
-  db().DeleteAffiliationsAndBrandingOlderThan(base::Time::FromInternalValue(0));
-
-  ASSERT_NO_FATAL_FAILURE(StoreInitialTestData());
-
-  db().DeleteAffiliationsAndBrandingOlderThan(
-      base::Time::FromInternalValue(kTestTimeUs2));
-
-  std::vector<AffiliatedFacetsWithUpdateTime> affiliations;
-  db().GetAllAffiliationsAndBranding(&affiliations);
-  ASSERT_EQ(2u, affiliations.size());
-  ExpectEquivalenceClassesIncludingBrandingInfoAreEqual(TestEquivalenceClass2(),
-                                                        affiliations[0]);
-  ExpectEquivalenceClassesIncludingBrandingInfoAreEqual(TestEquivalenceClass3(),
-                                                        affiliations[1]);
-
-  db().DeleteAffiliationsAndBrandingOlderThan(base::Time::Max());
-
-  db().GetAllAffiliationsAndBranding(&affiliations);
-  ASSERT_EQ(0u, affiliations.size());
-}
-
 // Verify that an existing DB can be reopened, and data is retained.
 TEST_F(AffiliationDatabaseTest, DBRetainsDataAfterReopening) {
   ASSERT_NO_FATAL_FAILURE(StoreInitialTestData());
diff --git a/components/password_manager/core/browser/hash_password_manager.cc b/components/password_manager/core/browser/hash_password_manager.cc
index 4e5fae3357..6a32fdc 100644
--- a/components/password_manager/core/browser/hash_password_manager.cc
+++ b/components/password_manager/core/browser/hash_password_manager.cc
@@ -295,16 +295,6 @@
   return state_callback_list_.Add(callback);
 }
 
-bool HashPasswordManager::EncryptAndSaveToPrefs(const std::string& pref_name,
-                                                const std::string& s) {
-  std::string encrypted_base64_text = EncryptString(s);
-  if (encrypted_base64_text.empty())
-    return false;
-
-  prefs_->SetString(pref_name, encrypted_base64_text);
-  return true;
-}
-
 bool HashPasswordManager::EncryptAndSave(
     const PasswordHashData& password_hash_data) {
   if (!prefs_ || password_hash_data.username.empty()) {
@@ -366,11 +356,4 @@
   return true;
 }
 
-std::string HashPasswordManager::RetrievedDecryptedStringFromPrefs(
-    const std::string& pref_name) {
-  DCHECK(prefs_);
-  std::string encrypted_base64_text = prefs_->GetString(pref_name);
-  return DecryptBase64String(encrypted_base64_text);
-}
-
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/hash_password_manager.h b/components/password_manager/core/browser/hash_password_manager.h
index 37c62f7..e0e49dc 100644
--- a/components/password_manager/core/browser/hash_password_manager.h
+++ b/components/password_manager/core/browser/hash_password_manager.h
@@ -62,18 +62,9 @@
       const base::Callback<void(const std::string& username)>& callback);
 
  private:
-  // Saves encrypted string |s| in a preference |pref_name|. Returns true on
-  // success.
-  bool EncryptAndSaveToPrefs(const std::string& pref_name,
-                             const std::string& s);
-
   // Encrypts and saves |password_hash_data| to prefs. Returns true on success.
   bool EncryptAndSave(const PasswordHashData& password_hash_data);
 
-  // Retrieves and decrypts string value from a preference |pref_name|. Returns
-  // an empty string on failure.
-  std::string RetrievedDecryptedStringFromPrefs(const std::string& pref_name);
-
   PrefService* prefs_ = nullptr;
 
   // Callbacks when |kPasswordHashDataList| might have changed.
diff --git a/components/password_manager/core/browser/password_manager_util.cc b/components/password_manager/core/browser/password_manager_util.cc
index 382df281..b9cb10d4 100644
--- a/components/password_manager/core/browser/password_manager_util.cc
+++ b/components/password_manager/core/browser/password_manager_util.cc
@@ -97,37 +97,6 @@
          password_manager::SYNCING_NORMAL_ENCRYPTION;
 }
 
-void FindDuplicates(std::vector<std::unique_ptr<PasswordForm>>* forms,
-                    std::vector<std::unique_ptr<PasswordForm>>* duplicates,
-                    std::vector<std::vector<PasswordForm*>>* tag_groups) {
-  if (forms->empty())
-    return;
-
-  // Linux backends used to treat the first form as a prime oneamong the
-  // duplicates. Therefore, the caller should try to preserve it.
-  std::stable_sort(forms->begin(), forms->end(), autofill::LessThanUniqueKey());
-
-  std::vector<std::unique_ptr<PasswordForm>> unique_forms;
-  unique_forms.push_back(std::move(forms->front()));
-  if (tag_groups) {
-    tag_groups->clear();
-    tag_groups->push_back(std::vector<PasswordForm*>());
-    tag_groups->front().push_back(unique_forms.front().get());
-  }
-  for (auto it = forms->begin() + 1; it != forms->end(); ++it) {
-    if (ArePasswordFormUniqueKeysEqual(**it, *unique_forms.back())) {
-      if (tag_groups)
-        tag_groups->back().push_back(it->get());
-      duplicates->push_back(std::move(*it));
-    } else {
-      if (tag_groups)
-        tag_groups->push_back(std::vector<PasswordForm*>(1, it->get()));
-      unique_forms.push_back(std::move(*it));
-    }
-  }
-  forms->swap(unique_forms);
-}
-
 void TrimUsernameOnlyCredentials(
     std::vector<std::unique_ptr<PasswordForm>>* android_credentials) {
   // Remove username-only credentials which are not federated.
diff --git a/components/password_manager/core/browser/password_manager_util.h b/components/password_manager/core/browser/password_manager_util.h
index ad0667f..97a7d13c 100644
--- a/components/password_manager/core/browser/password_manager_util.h
+++ b/components/password_manager/core/browser/password_manager_util.h
@@ -50,17 +50,6 @@
 // custom passphrase.
 bool IsSyncingWithNormalEncryption(const syncer::SyncService* sync_service);
 
-// Finds the forms with a duplicate sync tags in |forms|. The first one of
-// the duplicated entries stays in |forms|, the others are moved to
-// |duplicates|.
-// |tag_groups| is optional. It will contain |forms| and |duplicates| grouped by
-// the sync tag. The first element in each group is one from |forms|. It's
-// followed by the duplicates.
-void FindDuplicates(
-    std::vector<std::unique_ptr<autofill::PasswordForm>>* forms,
-    std::vector<std::unique_ptr<autofill::PasswordForm>>* duplicates,
-    std::vector<std::vector<autofill::PasswordForm*>>* tag_groups);
-
 // Removes Android username-only credentials from |android_credentials|.
 // Transforms federated credentials into non zero-click ones.
 void TrimUsernameOnlyCredentials(
diff --git a/components/password_manager/core/browser/password_reuse_detector.cc b/components/password_manager/core/browser/password_reuse_detector.cc
index 9877c4b3..6b199907 100644
--- a/components/password_manager/core/browser/password_reuse_detector.cc
+++ b/components/password_manager/core/browser/password_reuse_detector.cc
@@ -208,16 +208,6 @@
   return longest_match_len;
 }
 
-void PasswordReuseDetector::UseSyncPasswordHash(
-    base::Optional<PasswordHashData> sync_password_data) {
-  // TODO(crbug.com/841438): Remove this function when the migration is done.
-  if (sync_password_data) {
-    gaia_password_hash_data_list_ =
-        base::make_optional<std::vector<PasswordHashData>>();
-    gaia_password_hash_data_list_->push_back(sync_password_data.value());
-  }
-}
-
 void PasswordReuseDetector::UseGaiaPasswordHash(
     base::Optional<std::vector<PasswordHashData>> password_hash_data_list) {
   gaia_password_hash_data_list_ = std::move(password_hash_data_list);
diff --git a/components/password_manager/core/browser/password_reuse_detector.h b/components/password_manager/core/browser/password_reuse_detector.h
index c3da09c..b5e0998 100644
--- a/components/password_manager/core/browser/password_reuse_detector.h
+++ b/components/password_manager/core/browser/password_reuse_detector.h
@@ -54,9 +54,6 @@
                   const std::string& domain,
                   PasswordReuseDetectorConsumer* consumer);
 
-  // Stores internal |sync_password_data| for password reuse checking.
-  void UseSyncPasswordHash(base::Optional<PasswordHashData> sync_password_data);
-
   // Stores a vector of PasswordHashData for Gaia password reuse checking.
   void UseGaiaPasswordHash(
       base::Optional<std::vector<PasswordHashData>> password_hash_data_list);
diff --git a/components/password_manager/core/browser/password_store.cc b/components/password_manager/core/browser/password_store.cc
index 77a159be..66477240 100644
--- a/components/password_manager/core/browser/password_store.cc
+++ b/components/password_manager/core/browser/password_store.cc
@@ -328,12 +328,6 @@
       base::BindOnce(&PasswordStore::RemoveSiteStatsImpl, this, origin_domain));
 }
 
-void PasswordStore::GetAllSiteStats(PasswordStoreConsumer* consumer) {
-  DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
-  PostStatsTaskAndReplyToConsumerWithResult(
-      consumer, base::BindOnce(&PasswordStore::GetAllSiteStatsImpl, this));
-}
-
 void PasswordStore::GetSiteStats(const GURL& origin_domain,
                                  PasswordStoreConsumer* consumer) {
   DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
@@ -378,11 +372,6 @@
   return false;
 }
 
-scoped_refptr<base::SequencedTaskRunner>
-PasswordStore::GetBackgroundTaskRunner() {
-  return background_task_runner_;
-}
-
 bool PasswordStore::IsAbleToSavePasswords() const {
   DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
   return init_status_ == InitStatus::kSuccess;
diff --git a/components/password_manager/core/browser/password_store.h b/components/password_manager/core/browser/password_store.h
index e170aeb..4382a75b 100644
--- a/components/password_manager/core/browser/password_store.h
+++ b/components/password_manager/core/browser/password_store.h
@@ -236,10 +236,6 @@
   // Removes the statistics for |origin_domain|.
   void RemoveSiteStats(const GURL& origin_domain);
 
-  // Retrieves the statistics for all sites and notifies |consumer| on
-  // completion. The request will be cancelled if the consumer is destroyed.
-  void GetAllSiteStats(PasswordStoreConsumer* consumer);
-
   // Retrieves the statistics for |origin_domain| and notifies |consumer| on
   // completion. The request will be cancelled if the consumer is destroyed.
   void GetSiteStats(const GURL& origin_domain, PasswordStoreConsumer* consumer);
@@ -266,8 +262,6 @@
   // Schedules the given |task| to be run on the PasswordStore's TaskRunner.
   bool ScheduleTask(base::OnceClosure task);
 
-  scoped_refptr<base::SequencedTaskRunner> GetBackgroundTaskRunner();
-
   // Returns true iff initialization was successful.
   virtual bool IsAbleToSavePasswords() const;
 
diff --git a/components/password_manager/core/browser/password_store_default.cc b/components/password_manager/core/browser/password_store_default.cc
index 061bed7..715afc05 100644
--- a/components/password_manager/core/browser/password_store_default.cc
+++ b/components/password_manager/core/browser/password_store_default.cc
@@ -296,11 +296,4 @@
   login_db_.reset();
 }
 
-#if defined(USE_X11)
-void PasswordStoreDefault::SetLoginDB(std::unique_ptr<LoginDatabase> login_db) {
-  DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
-  login_db_ = std::move(login_db);
-}
-#endif  // defined(USE_X11)
-
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/password_store_default.h b/components/password_manager/core/browser/password_store_default.h
index e89d044..f7c7d86 100644
--- a/components/password_manager/core/browser/password_store_default.h
+++ b/components/password_manager/core/browser/password_store_default.h
@@ -25,15 +25,6 @@
 
   void ShutdownOnUIThread() override;
 
-#if defined(USE_X11)
-  // Dispose the current |login_db_| and use |login_db|. |login_db| is expected
-  // to have been initialised. A null value is equivalent to a database which
-  // can't be opened.
-  // TODO(crbug.com/571003) This is only used to migrate Linux to an encrypted
-  // LoginDatabase.
-  void SetLoginDB(std::unique_ptr<LoginDatabase> login_db);
-#endif  // defined(USE_X11)
-
   // To be used only for testing or in subclasses.
   LoginDatabase* login_db() const { return login_db_.get(); }
 
diff --git a/components/password_manager/core/browser/password_sync_util.cc b/components/password_manager/core/browser/password_sync_util.cc
index 1827978..a783dace 100644
--- a/components/password_manager/core/browser/password_sync_util.cc
+++ b/components/password_manager/core/browser/password_sync_util.cc
@@ -64,38 +64,6 @@
       GetSyncUsernameIfSyncingPasswords(sync_service, identity_manager));
 }
 
-bool ShouldSavePasswordHash(const autofill::PasswordForm& form,
-                            const signin::IdentityManager* identity_manager,
-                            PrefService* prefs) {
-#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
-  bool is_protected_credential_url =
-      gaia::IsGaiaSignonRealm(GURL(form.signon_realm)) ||
-      form.signon_realm == kGoogleChangePasswordSignonRealm ||
-      safe_browsing::MatchesPasswordProtectionLoginURL(form.origin, *prefs) ||
-      safe_browsing::MatchesPasswordProtectionChangePasswordURL(form.origin,
-                                                                *prefs);
-
-  if (!is_protected_credential_url)
-    return false;
-
-  std::string sync_email = identity_manager->GetPrimaryAccountInfo().email;
-  std::string username = base::UTF16ToUTF8(form.username_value);
-
-  if (sync_email.empty() || username.empty())
-    return false;
-
-  // Add @domain.name to the username if it is absent.
-  std::string email =
-      username + (username.find('@') == std::string::npos
-                      ? "@" + gaia::ExtractDomainName(sync_email)
-                      : std::string());
-
-  return email == sync_email;
-#else
-  return false;
-#endif  // SYNC_PASSWORD_REUSE_DETECTION_ENABLED
-}
-
 bool IsSyncAccountEmail(const std::string& username,
                         const signin::IdentityManager* identity_manager) {
   // |identity_manager| can be null if user is not signed in.
diff --git a/components/password_manager/core/browser/password_sync_util.h b/components/password_manager/core/browser/password_sync_util.h
index ae8097e3c..990fab7 100644
--- a/components/password_manager/core/browser/password_sync_util.h
+++ b/components/password_manager/core/browser/password_sync_util.h
@@ -34,12 +34,6 @@
                              const syncer::SyncService* sync_service,
                              const signin::IdentityManager* identity_manager);
 
-// If |form| doesn't match GAIA sign-on realm or enterprise-specified password
-// protection URL, returns false. Otherwise, return true.
-bool ShouldSavePasswordHash(const autofill::PasswordForm& form,
-                            const signin::IdentityManager* identity_manager,
-                            PrefService* prefs);
-
 // If |username| matches sync account.
 bool IsSyncAccountEmail(const std::string& username,
                         const signin::IdentityManager* identity_manager);
diff --git a/components/password_manager/core/browser/password_sync_util_unittest.cc b/components/password_manager/core/browser/password_sync_util_unittest.cc
index 9a02d6a..320ce3c 100644
--- a/components/password_manager/core/browser/password_sync_util_unittest.cc
+++ b/components/password_manager/core/browser/password_sync_util_unittest.cc
@@ -149,58 +149,6 @@
   TestingPrefServiceSimple prefs_;
 };
 
-TEST_F(PasswordSyncUtilEnterpriseTest, ShouldSavePasswordHash) {
-  prefs_.SetString(prefs::kPasswordProtectionChangePasswordURL,
-                   "https://pwchange.mydomain.com/");
-  base::ListValue login_url;
-  login_url.AppendString("https://login.mydomain.com/");
-  prefs_.Set(prefs::kPasswordProtectionLoginURLs, login_url);
-  const struct {
-    PasswordForm form;
-    std::string fake_sync_username;
-    bool expected_result;
-  } kTestCases[] = {
-      {SimpleNonGaiaForm("sync_user@mydomain.com",
-                         "https://pwchange.mydomain.com/"),
-       "sync_user@mydomain.com", true},
-      {SimpleNonGaiaForm("sync_user@mydomain.com",
-                         "https://login.mydomain.com/"),
-       "sync_user@mydomain.com", true},
-      {SimpleNonGaiaForm("non_sync_user@mydomain.com",
-                         "https://pwchange.mydomain.com/"),
-       "sync_user@mydomain.com", false},
-      {SimpleNonGaiaForm("non_sync_user@mydomain.com",
-                         "https://login.mydomain.com/"),
-       "sync_user@mydomain.com", false},
-      {SimpleNonGaiaForm("sync_user", "https://pwchange.mydomain.com/"),
-       "sync_user@mydomain.com", true},
-      {SimpleNonGaiaForm("sync_user", "https://login.mydomain.com/"),
-       "sync_user@mydomain.com", true},
-      {SimpleNonGaiaForm("non_sync_user", "https://pwchange.mydomain.com/"),
-       "sync_user@mydomain.com", false},
-      {SimpleNonGaiaForm("non_sync_user", "https://login.mydomain.com/"),
-       "sync_user@mydomain.com", false},
-      {SimpleNonGaiaForm("", "https://pwchange.mydomain.com/"),
-       "sync_user@mydomain.com", false},
-      {SimpleNonGaiaForm("", "https://login.mydomain.com/"),
-       "sync_user@mydomain.com", false},
-      {SimpleNonGaiaForm("sync_user@mydomain.com", "https://otherdomain.com/"),
-       "sync_user@mydomain.com", false},
-      {SimpleNonGaiaForm("sync_user", "https://otherdomain.com/"),
-       "sync_user@mydomain.com", false},
-  };
-
-  for (bool syncing_passwords : {false, true}) {
-    for (size_t i = 0; i < base::size(kTestCases); ++i) {
-      SCOPED_TRACE(testing::Message() << "i=" << i);
-      SetSyncingPasswords(syncing_passwords);
-      FakeSigninAs(kTestCases[i].fake_sync_username);
-      EXPECT_EQ(kTestCases[i].expected_result,
-                ShouldSavePasswordHash(kTestCases[i].form, identity_manager(),
-                                       &prefs_));
-    }
-  }
-}
 #endif  // SYNC_PASSWORD_REUSE_DETECTION_ENABLED
 
 }  // namespace sync_util
diff --git a/components/password_manager/core/browser/psl_matching_helper.cc b/components/password_manager/core/browser/psl_matching_helper.cc
index 567a6e1..4a81f92 100644
--- a/components/password_manager/core/browser/psl_matching_helper.cc
+++ b/components/password_manager/core/browser/psl_matching_helper.cc
@@ -124,27 +124,4 @@
       net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
 }
 
-std::string GetOrganizationIdentifyingName(const GURL& url) {
-  if (!url.is_valid())
-    return std::string();
-
-  const std::string organization_and_registrar =
-      net::registry_controlled_domains::GetDomainAndRegistry(
-          url, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
-  const size_t registrar_length =
-      net::registry_controlled_domains::GetRegistryLength(
-          url, net::registry_controlled_domains::INCLUDE_UNKNOWN_REGISTRIES,
-          net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
-
-  if (organization_and_registrar.empty() || !registrar_length ||
-      registrar_length == std::string::npos) {
-    return std::string();
-  }
-
-  // No CHECK, std::string::substr gracefully handles an underflow there.
-  DCHECK_LT(registrar_length, organization_and_registrar.size());
-  return organization_and_registrar.substr(
-      0, organization_and_registrar.size() - registrar_length - 1);
-}
-
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/psl_matching_helper.h b/components/password_manager/core/browser/psl_matching_helper.h
index 15d565a..43ecb41 100644
--- a/components/password_manager/core/browser/psl_matching_helper.h
+++ b/components/password_manager/core/browser/psl_matching_helper.h
@@ -64,11 +64,6 @@
 // registry-controlled domain part.
 std::string GetRegistryControlledDomain(const GURL& signon_realm);
 
-// Returns the organization-identifying name of the host of |url|, that is, the
-// first domain name label below the effective TLD. Returns the empty string for
-// URLs where these concepts are ill-defined, as well as for invalid URLs.
-std::string GetOrganizationIdentifyingName(const GURL& url);
-
 }  // namespace password_manager
 
 #endif  // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PSL_MATCHING_HELPER_H_
diff --git a/components/password_manager/core/browser/psl_matching_helper_unittest.cc b/components/password_manager/core/browser/psl_matching_helper_unittest.cc
index 5b068ed6..84a703f 100644
--- a/components/password_manager/core/browser/psl_matching_helper_unittest.cc
+++ b/components/password_manager/core/browser/psl_matching_helper_unittest.cc
@@ -400,102 +400,6 @@
   }
 }
 
-TEST(PSLMatchingUtilsTest, GetOrganizationIdentifyingName) {
-  static constexpr const struct {
-    const char* url;
-    const char* expected_organization_name;
-  } kTestCases[] = {
-      {"http://example.com/login", "example"},
-      {"https://example.com", "example"},
-      {"ftp://example.com/ftp_realm", "example"},
-
-      {"http://foo.bar.example.com", "example"},
-      {"http://example.co.uk", "example"},
-      {"http://bar.example.appspot.com", "example"},
-      {"http://foo.bar", "foo"},
-      {"https://user:pass@www.example.com:80/path?query#ref", "example"},
-
-      {"http://www.foo+bar.com", "foo+bar"},
-      {"http://www.foo-bar.com", "foo-bar"},
-      {"https://foo_bar.com", "foo_bar"},
-      {"http://www.foo%2Bbar.com", "foo+bar"},
-      {"http://www.foo%2Dbar.com", "foo-bar"},
-      {"https://foo%5Fbar.com", "foo_bar"},
-      {"http://www.foo%2Ebar.com", "bar"},
-
-      // Internationalized Domain Names: each dot-separated label of the domain
-      // name is individually Punycode-encoded, so the organization-identifying
-      // name is still well-defined and can be determined as normal.
-      //       , ,
-      //     szotar = sz\xc3\xb3t\xc3\xa1r (UTF-8) = xn--sztr-7na0i (IDN)
-      //       | |
-      //  U+00E1 U+00F3
-      {"https://www.sz\xc3\xb3t\xc3\xa1r.appspot.com", "xn--sztr-7na0i"},
-
-      {"http://www.foo!bar.com", "foo%21bar"},
-      {"http://www.foo%21bar.com", "foo%21bar"},
-      {"http://www.foo$bar.com", "foo%24bar"},
-      {"http://www.foo&bar.com", "foo%26bar"},
-      {"http://www.foo\'bar.com", "foo%27bar"},
-      {"http://www.foo(bar.com", "foo%28bar"},
-      {"http://www.foo)bar.com", "foo%29bar"},
-      {"http://www.foo*bar.com", "foo%2Abar"},
-      {"http://www.foo,bar.com", "foo%2Cbar"},
-      {"http://www.foo=bar.com", "foo%3Dbar"},
-
-      // URLs without host portions, hosts without registry controlled domains
-      // should, or hosts consisting of a registry yield the empty string.
-      {"http://localhost", ""},
-      {"http://co.uk", ""},
-      {"http://google", ""},
-      {"http://127.0.0.1", ""},
-      {"file:///usr/bin/stuff", ""},
-      {"federation://example.com/google.com", ""},
-      {"android://hash@com.example/", ""},
-      {"http://[1080:0:0:0:8:800:200C:417A]/", ""},
-      {"http://[3ffe:2a00:100:7031::1]", ""},
-      {"http://[::192.9.5.5]/", ""},
-
-      // Invalid URLs should yield the empty string.
-      {"", ""},
-      {"http://", ""},
-      {"bad url", ""},
-      {"http://www.example.com/%00", ""},
-      {"http://www.foo;bar.com", ""},
-      {"http://www.foo~bar.com", ""},
-  };
-
-  for (const auto& test_case : kTestCases) {
-    SCOPED_TRACE(test_case.url);
-    GURL url(test_case.url);
-    EXPECT_EQ(test_case.expected_organization_name,
-              GetOrganizationIdentifyingName(url));
-  }
-}
-
-// Apart from alphanumeric characters and '.', only |kExpectedUnescapedChars|
-// are expected to appear without percent-encoding in the domain of a valid,
-// canonicalized URL.
-//
-// The purpose of this test is to ensure that the test cases around unescaped
-// special characters in `GetOrganizationIdentifyingName` are exhaustive.
-TEST(PSLMatchingUtilsTest,
-     GetOrganizationIdentifyingName_UnescapedSpecialChars) {
-  static constexpr const char kExpectedNonAlnumChars[] = {'+', '-', '_', '.'};
-  for (int chr = 0; chr <= 255; ++chr) {
-    const auto percent_encoded = base::StringPrintf("http://a%%%02Xb.hu/", chr);
-    const GURL url(percent_encoded);
-    if (isalnum(chr) || base::Contains(kExpectedNonAlnumChars, chr)) {
-      ASSERT_TRUE(url.is_valid());
-      const auto percent_decoded = base::StringPrintf(
-          "http://a%cb.hu/", base::ToLowerASCII(static_cast<char>(chr)));
-      EXPECT_EQ(percent_decoded, url.spec());
-    } else if (url.is_valid()) {
-      EXPECT_EQ(percent_encoded, url.spec());
-    }
-  }
-}
-
 }  // namespace
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/votes_uploader.h b/components/password_manager/core/browser/votes_uploader.h
index acf0fc13..c699846 100644
--- a/components/password_manager/core/browser/votes_uploader.h
+++ b/components/password_manager/core/browser/votes_uploader.h
@@ -95,14 +95,10 @@
       uint32_t username_element_renderer_id,
       autofill::FormStructure* form_structure);
 
-  bool get_generation_popup_was_shown() const {
-    return generation_popup_was_shown_;
-  }
   void set_generation_popup_was_shown(bool generation_popup_was_shown) {
     generation_popup_was_shown_ = generation_popup_was_shown;
   }
 
-  bool is_manual_generation() const { return is_manual_generation_; }
   void set_is_manual_generation(bool is_manual_generation) {
     is_manual_generation_ = is_manual_generation;
   }
@@ -110,6 +106,7 @@
   const base::string16& get_generation_element() const {
     return generation_element_;
   }
+
   void set_generation_element(const base::string16& generation_element) {
     generation_element_ = generation_element;
   }
@@ -149,9 +146,6 @@
   // Adds a vote on password generation usage to |form_structure|.
   void AddGeneratedVote(autofill::FormStructure* form_structure);
 
-  // Adds a vote from HTML parsing based form classifier to |form_structure|.
-  void AddFormClassifierVote(autofill::FormStructure* form_structure);
-
   // Sets the known-value flag for each field, indicating that the field
   // contained a previously stored credential on submission.
   void SetKnownValueFlag(
diff --git a/components/password_manager/core/common/password_manager_features.cc b/components/password_manager/core/common/password_manager_features.cc
index 77186d1..7a848c0 100644
--- a/components/password_manager/core/common/password_manager_features.cc
+++ b/components/password_manager/core/common/password_manager_features.cc
@@ -48,6 +48,10 @@
 const base::Feature kLeakDetection = {"PasswordLeakDetection",
                                       base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Enables storing leaked credentials in the database.
+const base::Feature kLeakHistory = {"PasswordLeakHistory",
+                                    base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Controls whether to offer manual password generation in the accessory sheet
 // on Android.
 const base::Feature kManualPasswordGenerationAndroid{
diff --git a/components/password_manager/core/common/password_manager_features.h b/components/password_manager/core/common/password_manager_features.h
index 9742fafc..62781d11 100644
--- a/components/password_manager/core/common/password_manager_features.h
+++ b/components/password_manager/core/common/password_manager_features.h
@@ -25,6 +25,7 @@
 extern const base::Feature kGenerationNoOverwrites;
 extern const base::Feature kGooglePasswordManager;
 extern const base::Feature kLeakDetection;
+extern const base::Feature kLeakHistory;
 extern const base::Feature kManualPasswordGenerationAndroid;
 extern const base::Feature kPasswordEditingAndroid;
 extern const base::Feature kPasswordImport;
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 0707af7..cb1cc4d 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -10301,6 +10301,32 @@
           If this policy is left unset, the virtual keyboard is disabled on the login screen initially but can be enabled by the user anytime.''',
     },
     {
+      'name': 'SharedClipboardEnabled',
+      'owners': ['mvanouwerkerk@chromium.org', 'yasmo@chromium.org'],
+      'type': 'main',
+      'schema': { 'type': 'boolean' },
+      'supported_on': ['chrome.*:79-', 'chrome_os:79-', 'android:79-'],
+      'features': {
+        'dynamic_refresh': True,
+        'per_profile': True,
+      },
+      'example_value': True,
+      'id': 610,
+      'caption': '''Enable the Shared Clipboard Feature''',
+      'tags': [],
+      'desc': '''Enable the Shared Clipboard feature which allows users to send text between Chrome Desktops and an Android device when Sync is enabled and the user is Signed-in.
+
+          If this policy is set to true, the capability of sending text, cross device, for chrome user is enabled.
+
+          If this policy is set to false, the capability of sending text, cross device, for chrome user is disabled.
+
+          If you set this policy, users cannot change or override it.
+
+          If this policy is left unset, the shared clipboard feature is enabled by default.
+
+          It is up to the admins to set policies in all platforms they care about. It's recommended to set this policy to one value in all platforms.''',
+    },
+    {
       'name': 'DeviceLoginScreenDefaultScreenMagnifierType',
       'owners': ['file://components/policy/resources/OWNERS'],
       'type': 'int-enum',
@@ -18631,6 +18657,6 @@
   ],
   'placeholders': [],
   'deleted_policy_ids': [412, 546, 562, 569],
-  'highest_id_currently_used': 609,
+  'highest_id_currently_used': 610,
   'highest_atomic_group_id_currently_used': 37
 }
diff --git a/components/security_interstitials_strings.grdp b/components/security_interstitials_strings.grdp
index 09613421..1689dbf 100644
--- a/components/security_interstitials_strings.grdp
+++ b/components/security_interstitials_strings.grdp
@@ -65,17 +65,17 @@
   </message>
 
   <!-- Lookalike URL warning -->
-  <message name="IDS_LOOKALIKE_URL_TITLE" desc="Tab title. Context: the requested URL might be trying to trick the user since it looks like a more popular URL.">
-    Continue to <ph name="DOMAIN">$1<ex>example.com</ex></ph>?
+  <message name="IDS_LOOKALIKE_URL_TITLE" desc="Tab title. Context: the requested URL might be trying to trick the user since it looks like a more popular URL. This interstitial points the user to the safe site instead.">
+    Did you mean <ph name="DOMAIN">$1<ex>example.com</ex></ph>?
   </message>
-  <message name="IDS_LOOKALIKE_URL_HEADING" desc="Large heading. Context: the error page that's shown when the requested URL might be trying to trick the user since it looks like a more popular URL.">
-    Continue to &lt;a href="#" id="dont-proceed-link"&gt;<ph name="DOMAIN">$1<ex>example.com</ex></ph>&lt;/a&gt;?
+  <message name="IDS_LOOKALIKE_URL_HEADING" desc="Large heading. Context: the error page that's shown when the requested URL might be trying to trick the user since it looks like a more popular URL. This interstitial points the user to the safe site instead.">
+    Did you mean &lt;a href="#" id="dont-proceed-link"&gt;<ph name="DOMAIN">$1<ex>example.com</ex></ph>&lt;/a&gt;?
   </message>
   <message name="IDS_LOOKALIKE_URL_IGNORE" desc="Button text. Context: the error page that's shown when the requested URL might be trying to trick the user since it looks like a more popular URL. This button dismisses the interstitial and navigates to the originally-requested URL.">
     Ignore
   </message>
   <message name="IDS_LOOKALIKE_URL_CONTINUE" desc="Button text. Context: the error page that's shown when the requested URL might be trying to trick the user since it looks like a more popular URL. This button dismisses the interstitial and navigates to the suggested (safe) URL.">
-    Continue
+    Go to <ph name="DOMAIN">$1<ex>example.com</ex></ph>
   </message>
   <message name="IDS_LOOKALIKE_URL_PRIMARY_PARAGRAPH" desc="Main paragraph of an error message. Context: the error page that's shown when the requested URL might be trying to trick the user since it looks like a more popular URL.">
     The site you just tried to visit looks fake. Attackers sometimes mimic sites by making small, hard-to-see changes to the URL.
diff --git a/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_CONTINUE.png.sha1 b/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_CONTINUE.png.sha1
index 55b5d17..6484e32 100644
--- a/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_CONTINUE.png.sha1
+++ b/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_CONTINUE.png.sha1
@@ -1 +1 @@
-260a7f133f2a8fcec1743f8f2bb7538cc7a2fc50
\ No newline at end of file
+94e03c4a69925c4c0ddc5362977fb31a388f513b
\ No newline at end of file
diff --git a/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_HEADING.png.sha1 b/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_HEADING.png.sha1
index 55b5d17..6484e32 100644
--- a/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_HEADING.png.sha1
+++ b/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_HEADING.png.sha1
@@ -1 +1 @@
-260a7f133f2a8fcec1743f8f2bb7538cc7a2fc50
\ No newline at end of file
+94e03c4a69925c4c0ddc5362977fb31a388f513b
\ No newline at end of file
diff --git a/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_IGNORE.png.sha1 b/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_IGNORE.png.sha1
index 55b5d17..6484e32 100644
--- a/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_IGNORE.png.sha1
+++ b/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_IGNORE.png.sha1
@@ -1 +1 @@
-260a7f133f2a8fcec1743f8f2bb7538cc7a2fc50
\ No newline at end of file
+94e03c4a69925c4c0ddc5362977fb31a388f513b
\ No newline at end of file
diff --git a/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_PRIMARY_PARAGRAPH.png.sha1 b/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_PRIMARY_PARAGRAPH.png.sha1
index 8303002..6484e32 100644
--- a/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_PRIMARY_PARAGRAPH.png.sha1
+++ b/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_PRIMARY_PARAGRAPH.png.sha1
@@ -1 +1 @@
-a0e10eb89867355fc98c930e468397e8dadf4f17
\ No newline at end of file
+94e03c4a69925c4c0ddc5362977fb31a388f513b
\ No newline at end of file
diff --git a/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_TITLE.png.sha1 b/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_TITLE.png.sha1
index 55b5d17..6484e32 100644
--- a/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_TITLE.png.sha1
+++ b/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_TITLE.png.sha1
@@ -1 +1 @@
-260a7f133f2a8fcec1743f8f2bb7538cc7a2fc50
\ No newline at end of file
+94e03c4a69925c4c0ddc5362977fb31a388f513b
\ No newline at end of file
diff --git a/components/signin/public/identity_manager/identity_manager.cc b/components/signin/public/identity_manager/identity_manager.cc
index 76ddd6a..f63c259c 100644
--- a/components/signin/public/identity_manager/identity_manager.cc
+++ b/components/signin/public/identity_manager/identity_manager.cc
@@ -478,17 +478,34 @@
   return base::nullopt;
 #else
   AccountsInCookieJarInfo cookie_info = GetAccountsInCookieJar();
-  if (!cookie_info.accounts_are_fresh)
-    return base::nullopt;
+
+  if (AreRefreshTokensLoaded() && GetAccountsWithRefreshTokens().empty())
+    return CoreAccountInfo();
 
   std::vector<gaia::ListedAccount> cookie_accounts =
       cookie_info.signed_in_accounts;
-  if (cookie_accounts.empty())
+  if (cookie_info.accounts_are_fresh && cookie_accounts.empty())
     return CoreAccountInfo();
 
-  if (!AreRefreshTokensLoaded())
+  if (!AreRefreshTokensLoaded() || !cookie_info.accounts_are_fresh) {
+    // If cookies or tokens are not loaded, it is not possible to fully compute
+    // the unconsented primary account. However, if the current unconsented
+    // primary account is no longer valid, it has to be removed.
+    CoreAccountId current_account = GetUnconsentedPrimaryAccountId();
+    if (!current_account.empty()) {
+      if (AreRefreshTokensLoaded() &&
+          !HasAccountWithRefreshToken(current_account)) {
+        return CoreAccountInfo();
+      }
+      if (cookie_info.accounts_are_fresh &&
+          cookie_accounts[0].id != current_account) {
+        return CoreAccountInfo();
+      }
+    }
     return base::nullopt;
+  }
 
+  // At this point, cookies and tokens are loaded and neither are empty.
   const CoreAccountId first_account_id = cookie_accounts[0].id;
   if (!HasAccountWithRefreshToken(first_account_id))
     return CoreAccountInfo();
diff --git a/components/signin/public/identity_manager/identity_manager_unittest.cc b/components/signin/public/identity_manager/identity_manager_unittest.cc
index 5847b58..807e089 100644
--- a/components/signin/public/identity_manager/identity_manager_unittest.cc
+++ b/components/signin/public/identity_manager/identity_manager_unittest.cc
@@ -1553,6 +1553,58 @@
       empty_info);
   EXPECT_EQ(identity_manager()->GetUnconsentedPrimaryAccountInfo(), empty_info);
 }
+
+TEST_F(IdentityManagerTest,
+       UnconsentedPrimaryAccountTokenRevokedWithStaleCookies) {
+  ClearPrimaryAccount(identity_manager(), ClearPrimaryAccountPolicy::DEFAULT);
+
+  // Add an unconsented primary account, incl. proper cookies.
+  AccountInfo account_info = MakeAccountAvailableWithCookies(
+      identity_manager(), test_url_loader_factory(), kTestEmail2, kTestGaiaId2);
+  EXPECT_EQ(kTestEmail2, account_info.email);
+
+  EXPECT_EQ(identity_manager()->GetUnconsentedPrimaryAccountInfo(),
+            account_info);
+
+  // Make the cookies stale and remove the account.
+  signin::SetFreshnessOfAccountsInGaiaCookie(identity_manager(), false);
+  RemoveRefreshTokenForAccount(identity_manager(), account_info.account_id);
+  AccountsInCookieJarInfo cookie_info =
+      identity_manager()->GetAccountsInCookieJar();
+  ASSERT_FALSE(cookie_info.accounts_are_fresh);
+  // Unconsented account was removed.
+  EXPECT_EQ(identity_manager()->GetUnconsentedPrimaryAccountInfo(),
+            CoreAccountInfo());
+}
+
+TEST_F(IdentityManagerTest,
+       UnconsentedPrimaryAccountTokenRevokedWithStaleCookiesMultipleAccounts) {
+  ClearPrimaryAccount(identity_manager(), ClearPrimaryAccountPolicy::DEFAULT);
+
+  // Add two accounts with cookies.
+  AccountInfo main_account_info =
+      MakeAccountAvailable(identity_manager(), kTestEmail2);
+  AccountInfo secondary_account_info =
+      MakeAccountAvailable(identity_manager(), kTestEmail3);
+  SetCookieAccounts(
+      identity_manager(), test_url_loader_factory(),
+      {{main_account_info.email, main_account_info.gaia},
+       {secondary_account_info.email, secondary_account_info.gaia}});
+
+  EXPECT_EQ(identity_manager()->GetUnconsentedPrimaryAccountInfo(),
+            main_account_info);
+
+  // Make the cookies stale and remove the main account.
+  signin::SetFreshnessOfAccountsInGaiaCookie(identity_manager(), false);
+  RemoveRefreshTokenForAccount(identity_manager(),
+                               main_account_info.account_id);
+  AccountsInCookieJarInfo cookie_info =
+      identity_manager()->GetAccountsInCookieJar();
+  ASSERT_FALSE(cookie_info.accounts_are_fresh);
+  // Unconsented account was removed.
+  EXPECT_EQ(identity_manager()->GetUnconsentedPrimaryAccountInfo(),
+            CoreAccountInfo());
+}
 #endif
 
 TEST_F(IdentityManagerTest, CallbackSentOnRefreshTokenRemovalOfUnknownAccount) {
diff --git a/components/sync/BUILD.gn b/components/sync/BUILD.gn
index d360d64..6905a3bb 100644
--- a/components/sync/BUILD.gn
+++ b/components/sync/BUILD.gn
@@ -311,6 +311,8 @@
     "model_impl/syncable_service_based_bridge.h",
     "nigori/cryptographer.cc",
     "nigori/cryptographer.h",
+    "nigori/cryptographer_impl.cc",
+    "nigori/cryptographer_impl.h",
     "nigori/forwarding_model_type_processor.cc",
     "nigori/forwarding_model_type_processor.h",
     "nigori/keystore_keys_handler.h",
@@ -642,6 +644,7 @@
     "model_impl/model_type_store_impl_unittest.cc",
     "model_impl/processor_entity_unittest.cc",
     "model_impl/syncable_service_based_bridge_unittest.cc",
+    "nigori/cryptographer_impl_unittest.cc",
     "nigori/nigori_key_bag_unittest.cc",
     "nigori/nigori_model_type_processor_unittest.cc",
     "nigori/nigori_storage_impl_unittest.cc",
diff --git a/components/sync/base/BUILD.gn b/components/sync/base/BUILD.gn
index 6bf51a7c..5146d93 100644
--- a/components/sync/base/BUILD.gn
+++ b/components/sync/base/BUILD.gn
@@ -48,7 +48,6 @@
     "sync_mode.h",
     "sync_prefs.cc",
     "sync_prefs.h",
-    "sync_stop_metadata_fate.cc",
     "sync_stop_metadata_fate.h",
     "syncer_error.cc",
     "syncer_error.h",
diff --git a/components/sync/base/model_type.cc b/components/sync/base/model_type.cc
index bcbb2e88f..f8cd9d7 100644
--- a/components/sync/base/model_type.cc
+++ b/components/sync/base/model_type.cc
@@ -374,14 +374,6 @@
   return kModelTypeInfoMap[model_type].specifics_field_number;
 }
 
-FullModelTypeSet ToFullModelTypeSet(ModelTypeSet in) {
-  FullModelTypeSet out;
-  for (ModelType type : in) {
-    out.Put(type);
-  }
-  return out;
-}
-
 // Note: keep this consistent with GetModelType in entry.cc!
 ModelType GetModelType(const sync_pb::SyncEntity& sync_entity) {
   ModelType specifics_type = GetModelTypeFromSpecifics(sync_entity.specifics());
diff --git a/components/sync/base/model_type.h b/components/sync/base/model_type.h
index 74de9da..d78f394 100644
--- a/components/sync/base/model_type.h
+++ b/components/sync/base/model_type.h
@@ -350,8 +350,6 @@
 // a model type.
 int GetSpecificsFieldNumberFromModelType(ModelType model_type);
 
-FullModelTypeSet ToFullModelTypeSet(ModelTypeSet in);
-
 // TODO(sync): The functions below badly need some cleanup.
 
 // Returns a string with application lifetime that represents the name of
diff --git a/components/sync/base/sync_stop_metadata_fate.cc b/components/sync/base/sync_stop_metadata_fate.cc
deleted file mode 100644
index c8fa6ca4..0000000
--- a/components/sync/base/sync_stop_metadata_fate.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/sync/base/sync_stop_metadata_fate.h"
-
-#include "base/logging.h"
-
-namespace syncer {
-
-const char* SyncStopMetadataFateToString(SyncStopMetadataFate metadata_fate) {
-  switch (metadata_fate) {
-    case KEEP_METADATA:
-      return "KEEP_METADATA";
-    case CLEAR_METADATA:
-      return "CLEAR_METADATA";
-  }
-
-  NOTREACHED() << "Invalid metadata fate " << static_cast<int>(metadata_fate);
-  return "INVALID";
-}
-
-}  // namespace syncer
diff --git a/components/sync/base/sync_stop_metadata_fate.h b/components/sync/base/sync_stop_metadata_fate.h
index b56e093..26f74c2 100644
--- a/components/sync/base/sync_stop_metadata_fate.h
+++ b/components/sync/base/sync_stop_metadata_fate.h
@@ -12,8 +12,6 @@
 // TODO(mastiz): Unify with SyncStopDataFate.
 enum SyncStopMetadataFate { KEEP_METADATA, CLEAR_METADATA };
 
-const char* SyncStopMetadataFateToString(SyncStopMetadataFate metadata_fate);
-
 }  // namespace syncer
 
 #endif  // COMPONENTS_SYNC_BASE_SYNC_STOP_METADATA_FATE_H_
diff --git a/components/sync/driver/async_directory_type_controller.cc b/components/sync/driver/async_directory_type_controller.cc
index 626458f8..34c8c55 100644
--- a/components/sync/driver/async_directory_type_controller.cc
+++ b/components/sync/driver/async_directory_type_controller.cc
@@ -111,8 +111,6 @@
   DCHECK_EQ(state_, MODEL_LOADED);
   state_ = ASSOCIATING;
 
-  // Store UserShare now while on UI thread to avoid potential race
-  // condition in StartAssociationWithSharedChangeProcessor.
   user_share_ = sync_service()->GetUserShare();
 
   start_callback_ = std::move(start_callback);
diff --git a/components/sync/driver/async_directory_type_controller.h b/components/sync/driver/async_directory_type_controller.h
index dce7a0e0..3e0369a 100644
--- a/components/sync/driver/async_directory_type_controller.h
+++ b/components/sync/driver/async_directory_type_controller.h
@@ -52,8 +52,6 @@
   // For testing only.
   AsyncDirectoryTypeController();
 
-  SyncClient* sync_client() { return sync_client_; }
-
   // Start any dependent services that need to be running before we can
   // associate models. The default implementation is a no-op.
   // Return value:
@@ -98,10 +96,6 @@
   std::unique_ptr<DataTypeErrorHandler> CreateErrorHandler() override;
 
  private:
-  // Posted on the backend thread by StartAssociationAsync().
-  void StartAssociationWithSharedChangeProcessor(
-      const scoped_refptr<SharedChangeProcessor>& shared_change_processor);
-
   // Calls Disconnect() on |shared_change_processor_|, then sets it to
   // null.  Must be called only by StartDoneImpl() or Stop() (on the
   // UI thread) and only after a call to Start() (i.e.,
@@ -140,9 +134,7 @@
   // The shared change processor is the thread-safe interface to the
   // datatype.  We hold a reference to it from the UI thread so that
   // we can call Disconnect() on it from Stop()/StartDoneImpl().  Most
-  // of the work is done on the backend thread, and in
-  // StartAssociationWithSharedChangeProcessor() for this class in
-  // particular.
+  // of the work is done on the backend thread.
   //
   // Lifetime: The SharedChangeProcessor object is created on the UI
   // thread and passed on to the backend thread.  This reference is
diff --git a/components/sync/driver/data_type_controller.cc b/components/sync/driver/data_type_controller.cc
index 0a17a6b..9ce9bf0 100644
--- a/components/sync/driver/data_type_controller.cc
+++ b/components/sync/driver/data_type_controller.cc
@@ -14,11 +14,6 @@
 DataTypeController::~DataTypeController() {}
 
 // static
-bool DataTypeController::IsUnrecoverableResult(ConfigureResult result) {
-  return (result == UNRECOVERABLE_ERROR);
-}
-
-// static
 bool DataTypeController::IsSuccessfulResult(ConfigureResult result) {
   return (result == OK || result == OK_FIRST_RUN);
 }
diff --git a/components/sync/driver/data_type_controller.h b/components/sync/driver/data_type_controller.h
index 3146b7ef..1bdd8980 100644
--- a/components/sync/driver/data_type_controller.h
+++ b/components/sync/driver/data_type_controller.h
@@ -97,10 +97,6 @@
   using TypeMap = std::map<ModelType, std::unique_ptr<DataTypeController>>;
   using TypeVector = std::vector<std::unique_ptr<DataTypeController>>;
 
-  // Returns true if the start result should trigger an unrecoverable error.
-  // Public so unit tests can use this function as well.
-  static bool IsUnrecoverableResult(ConfigureResult result);
-
   // Returns true if the datatype started successfully.
   static bool IsSuccessfulResult(ConfigureResult result);
 
diff --git a/components/sync/driver/glue/sync_engine_backend.h b/components/sync/driver/glue/sync_engine_backend.h
index 7e8092f..1624e52 100644
--- a/components/sync/driver/glue/sync_engine_backend.h
+++ b/components/sync/driver/glue/sync_engine_backend.h
@@ -122,10 +122,6 @@
   // Ask the syncer to check for updates for the specified types.
   void DoRefreshTypes(ModelTypeSet types);
 
-  // Invoked if we failed to download the necessary control types at startup.
-  // Invokes SyncEngine::HandleControlTypesDownloadRetry.
-  void OnControlTypesDownloadRetry();
-
   // Called to perform tasks which require the control data to be downloaded.
   // This includes refreshing encryption, etc.
   void DoInitialProcessControlTypes();
@@ -147,7 +143,6 @@
   void DoFinishConfigureDataTypes(
       ModelTypeSet types_to_config,
       const base::Callback<void(ModelTypeSet, ModelTypeSet)>& ready_task);
-  void DoRetryConfiguration(const base::Closure& retry_callback);
 
   // Set the base request context to use when making HTTP calls.
   // This method will add a reference to the context to persist it
diff --git a/components/sync/driver/model_association_manager.h b/components/sync/driver/model_association_manager.h
index 4b610ed..b451f16 100644
--- a/components/sync/driver/model_association_manager.h
+++ b/components/sync/driver/model_association_manager.h
@@ -116,10 +116,6 @@
   State state() const { return state_; }
 
  private:
-  // Called at the end of association to reset state to prepare for next
-  // round of association.
-  void ResetForNextAssociation();
-
   // Start loading non-running types that are in |desired_types_|.
   void LoadEnabledTypes();
 
diff --git a/components/sync/driver/profile_sync_service.h b/components/sync/driver/profile_sync_service.h
index 8be1975..19694857 100644
--- a/components/sync/driver/profile_sync_service.h
+++ b/components/sync/driver/profile_sync_service.h
@@ -348,9 +348,6 @@
   // Tell the sync server that this client has disabled sync.
   void RemoveClientFromServer() const;
 
-  // Check if previous shutdown is shutdown cleanly.
-  void ReportPreviousSessionMemoryWarningCount();
-
   // Estimates and records memory usage histograms per type.
   void RecordMemoryUsageHistograms();
 
diff --git a/components/sync/driver/profile_sync_service_bundle.h b/components/sync/driver/profile_sync_service_bundle.h
index fbd6216..e76cc7f 100644
--- a/components/sync/driver/profile_sync_service_bundle.h
+++ b/components/sync/driver/profile_sync_service_bundle.h
@@ -10,7 +10,6 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "components/invalidation/impl/fake_invalidation_service.h"
 #include "components/invalidation/impl/profile_identity_provider.h"
 #include "components/signin/public/identity_manager/identity_test_environment.h"
 #include "components/sync/driver/profile_sync_service.h"
@@ -42,10 +41,6 @@
 
   // Accessors
 
-  network::TestURLLoaderFactory* url_loader_factory() {
-    return &test_url_loader_factory_;
-  }
-
   sync_preferences::TestingPrefServiceSyncable* pref_service() {
     return &pref_service_;
   }
@@ -66,16 +61,11 @@
     return identity_provider_.get();
   }
 
-  invalidation::FakeInvalidationService* fake_invalidation_service() {
-    return &fake_invalidation_service_;
-  }
-
  private:
   sync_preferences::TestingPrefServiceSyncable pref_service_;
   signin::IdentityTestEnvironment identity_test_env_;
   testing::NiceMock<SyncApiComponentFactoryMock> component_factory_;
   std::unique_ptr<invalidation::ProfileIdentityProvider> identity_provider_;
-  invalidation::FakeInvalidationService fake_invalidation_service_;
   network::TestURLLoaderFactory test_url_loader_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ProfileSyncServiceBundle);
diff --git a/components/sync/engine/cycle/model_neutral_state.h b/components/sync/engine/cycle/model_neutral_state.h
index 2a7faba..c1888e7 100644
--- a/components/sync/engine/cycle/model_neutral_state.h
+++ b/components/sync/engine/cycle/model_neutral_state.h
@@ -23,9 +23,6 @@
   // The set of types for which updates were requested from the server.
   ModelTypeSet get_updates_request_types;
 
-  // The set of types for which commits were sent to the server.
-  ModelTypeSet commit_request_types;
-
   int num_successful_commits;
 
   // This is needed for monitoring extensions activity.
diff --git a/components/sync/engine/engine_components_factory.h b/components/sync/engine/engine_components_factory.h
index 639d78e..f53cf426 100644
--- a/components/sync/engine/engine_components_factory.h
+++ b/components/sync/engine/engine_components_factory.h
@@ -96,10 +96,6 @@
       const std::string& dir_name,
       const base::RepeatingCallback<std::string()>& cache_guid_generator,
       const base::FilePath& backing_filepath) = 0;
-
-  // Returns the Switches struct that this object is using as configuration, if
-  // the implementation is making use of one.
-  virtual Switches GetSwitches() const = 0;
 };
 
 }  // namespace syncer
diff --git a/components/sync/engine/engine_components_factory_impl.cc b/components/sync/engine/engine_components_factory_impl.cc
index 7deb70d..9490e037 100644
--- a/components/sync/engine/engine_components_factory_impl.cc
+++ b/components/sync/engine/engine_components_factory_impl.cc
@@ -56,9 +56,8 @@
     base::TimeDelta poll_interval) {
   return std::make_unique<SyncCycleContext>(
       connection_manager, directory, extensions_activity, listeners,
-      debug_info_getter, model_type_registry,
-      switches_.encryption_method == ENCRYPTION_KEYSTORE,
-      invalidation_client_id, store_birthday, bag_of_chips, poll_interval);
+      debug_info_getter, model_type_registry, invalidation_client_id,
+      store_birthday, bag_of_chips, poll_interval);
 }
 
 std::unique_ptr<syncable::DirectoryBackingStore>
@@ -77,9 +76,4 @@
   }
 }
 
-EngineComponentsFactory::Switches EngineComponentsFactoryImpl::GetSwitches()
-    const {
-  return switches_;
-}
-
 }  // namespace syncer
diff --git a/components/sync/engine/engine_components_factory_impl.h b/components/sync/engine/engine_components_factory_impl.h
index 7b28c09..dd812c5 100644
--- a/components/sync/engine/engine_components_factory_impl.h
+++ b/components/sync/engine/engine_components_factory_impl.h
@@ -45,8 +45,6 @@
       const base::RepeatingCallback<std::string()>& cache_guid_generator,
       const base::FilePath& backing_filepath) override;
 
-  Switches GetSwitches() const override;
-
  private:
   const Switches switches_;
   DISALLOW_COPY_AND_ASSIGN(EngineComponentsFactoryImpl);
diff --git a/components/sync/engine/sync_status.h b/components/sync/engine/sync_status.h
index e28d221..21e23b08 100644
--- a/components/sync/engine/sync_status.h
+++ b/components/sync/engine/sync_status.h
@@ -67,6 +67,7 @@
   int num_server_overwrites_total;
 
   // Nudge counts for each possible source
+  // TODO(crbug.com/1007969): Remove these; they're always 0.
   int nudge_source_notification;
   int nudge_source_local;
   int nudge_source_local_refresh;
diff --git a/components/sync/engine/test_engine_components_factory.cc b/components/sync/engine/test_engine_components_factory.cc
index c57fdbd..015aff8f 100644
--- a/components/sync/engine/test_engine_components_factory.cc
+++ b/components/sync/engine/test_engine_components_factory.cc
@@ -13,12 +13,9 @@
 namespace syncer {
 
 TestEngineComponentsFactory::TestEngineComponentsFactory(
-    const Switches& switches,
     StorageOption option,
     StorageOption* storage_used)
-    : switches_(switches),
-      storage_override_(option),
-      storage_used_(storage_used) {}
+    : storage_override_(option), storage_used_(storage_used) {}
 
 TestEngineComponentsFactory::~TestEngineComponentsFactory() {}
 
@@ -45,8 +42,7 @@
   std::vector<SyncEngineEventListener*> empty_listeners;
   return std::unique_ptr<SyncCycleContext>(new SyncCycleContext(
       connection_manager, directory, monitor, empty_listeners,
-      debug_info_getter, model_type_registry,
-      switches_.encryption_method == ENCRYPTION_KEYSTORE, invalidator_client_id,
+      debug_info_getter, model_type_registry, invalidator_client_id,
       store_birthday, bag_of_chips, poll_interval));
 }
 
@@ -76,9 +72,4 @@
   return std::unique_ptr<syncable::DirectoryBackingStore>();
 }
 
-EngineComponentsFactory::Switches TestEngineComponentsFactory::GetSwitches()
-    const {
-  return switches_;
-}
-
 }  // namespace syncer
diff --git a/components/sync/engine/test_engine_components_factory.h b/components/sync/engine/test_engine_components_factory.h
index b6164a0..39b642a 100644
--- a/components/sync/engine/test_engine_components_factory.h
+++ b/components/sync/engine/test_engine_components_factory.h
@@ -16,8 +16,7 @@
 
 class TestEngineComponentsFactory : public EngineComponentsFactory {
  public:
-  explicit TestEngineComponentsFactory(const Switches& switches,
-                                       StorageOption option,
+  explicit TestEngineComponentsFactory(StorageOption option,
                                        StorageOption* storage_used);
   ~TestEngineComponentsFactory() override;
 
@@ -45,10 +44,7 @@
       const base::RepeatingCallback<std::string()>& cache_guid_generator,
       const base::FilePath& backing_filepath) override;
 
-  Switches GetSwitches() const override;
-
  private:
-  const Switches switches_;
   const StorageOption storage_override_;
   StorageOption* storage_used_;
 
diff --git a/components/sync/engine_impl/all_status.cc b/components/sync/engine_impl/all_status.cc
index 177c930..d9903be 100644
--- a/components/sync/engine_impl/all_status.cc
+++ b/components/sync/engine_impl/all_status.cc
@@ -165,26 +165,6 @@
   status_.invalidator_client_id = invalidator_client_id;
 }
 
-void AllStatus::IncrementNudgeCounter(NudgeSource source) {
-  ScopedStatusLock lock(this);
-  switch (source) {
-    case NUDGE_SOURCE_LOCAL_REFRESH:
-      status_.nudge_source_local_refresh++;
-      return;
-    case NUDGE_SOURCE_LOCAL:
-      status_.nudge_source_local++;
-      return;
-    case NUDGE_SOURCE_NOTIFICATION:
-      status_.nudge_source_notification++;
-      return;
-    case NUDGE_SOURCE_UNKNOWN:
-      break;
-  }
-  // If we're here, the source is most likely
-  // NUDGE_SOURCE_UNKNOWN. That shouldn't happen.
-  NOTREACHED();
-}
-
 void AllStatus::SetLocalBackendFolder(const std::string& folder) {
   ScopedStatusLock lock(this);
   status_.local_sync_folder = folder;
diff --git a/components/sync/engine_impl/all_status.h b/components/sync/engine_impl/all_status.h
index 48cb51c..0db9fdc 100644
--- a/components/sync/engine_impl/all_status.h
+++ b/components/sync/engine_impl/all_status.h
@@ -50,8 +50,6 @@
 
   void SetNotificationsEnabled(bool notifications_enabled);
 
-  void IncrementNotifiableCommits();
-
   void IncrementNotificationsReceived();
 
   void SetEncryptedTypes(ModelTypeSet types);
@@ -66,8 +64,6 @@
   void SetSyncId(const std::string& sync_id);
   void SetInvalidatorClientId(const std::string& invalidator_client_id);
 
-  void IncrementNudgeCounter(NudgeSource source);
-
   void SetLocalBackendFolder(const std::string& folder);
 
  protected:
diff --git a/components/sync/engine_impl/commit.cc b/components/sync/engine_impl/commit.cc
index 7cbfbdd..703f0f43 100644
--- a/components/sync/engine_impl/commit.cc
+++ b/components/sync/engine_impl/commit.cc
@@ -118,7 +118,6 @@
                               ModelTypeToHistogramInt(request_type),
                               static_cast<int>(ModelType::NUM_ENTRIES));
   }
-  cycle->mutable_status_controller()->set_commit_request_types(request_types);
 
   if (cycle->context()->debug_info_getter()) {
     sync_pb::DebugInfo* debug_info = message_.mutable_debug_info();
diff --git a/components/sync/engine_impl/cycle/status_controller.cc b/components/sync/engine_impl/cycle/status_controller.cc
index c4182df..c5d07856 100644
--- a/components/sync/engine_impl/cycle/status_controller.cc
+++ b/components/sync/engine_impl/cycle/status_controller.cc
@@ -21,14 +21,6 @@
   model_neutral_.get_updates_request_types = value;
 }
 
-const ModelTypeSet StatusController::commit_request_types() const {
-  return model_neutral_.commit_request_types;
-}
-
-void StatusController::set_commit_request_types(ModelTypeSet value) {
-  model_neutral_.commit_request_types = value;
-}
-
 void StatusController::increment_num_updates_downloaded_by(int value) {
   model_neutral_.num_updates_downloaded_total += value;
 }
@@ -51,10 +43,6 @@
   poll_finish_time_ = base::Time::Now();
 }
 
-void StatusController::set_num_successful_bookmark_commits(int value) {
-  model_neutral_.num_successful_bookmark_commits = value;
-}
-
 void StatusController::increment_num_successful_bookmark_commits() {
   model_neutral_.num_successful_bookmark_commits++;
 }
diff --git a/components/sync/engine_impl/cycle/status_controller.h b/components/sync/engine_impl/cycle/status_controller.h
index 7fc554a..bd12d18 100644
--- a/components/sync/engine_impl/cycle/status_controller.h
+++ b/components/sync/engine_impl/cycle/status_controller.h
@@ -32,11 +32,9 @@
   StatusController();
   ~StatusController();
 
-  // The types included in the get updates and commit client to server requests.
+  // The types included in the get updates client to server requests.
   const ModelTypeSet get_updates_request_types() const;
   void set_get_updates_request_types(ModelTypeSet value);
-  const ModelTypeSet commit_request_types() const;
-  void set_commit_request_types(ModelTypeSet value);
 
   // Various conflict counters.
   int num_encryption_conflicts() const;
@@ -81,7 +79,6 @@
   // Commit counters.
   void increment_num_successful_commits();
   void increment_num_successful_bookmark_commits();
-  void set_num_successful_bookmark_commits(int value);
 
   // Server communication status tracking.
   void set_last_get_key_result(const SyncerError result);
diff --git a/components/sync/engine_impl/cycle/sync_cycle_context.cc b/components/sync/engine_impl/cycle/sync_cycle_context.cc
index 230aa9d0..d7b0c58 100644
--- a/components/sync/engine_impl/cycle/sync_cycle_context.cc
+++ b/components/sync/engine_impl/cycle/sync_cycle_context.cc
@@ -16,7 +16,6 @@
     const std::vector<SyncEngineEventListener*>& listeners,
     DebugInfoGetter* debug_info_getter,
     ModelTypeRegistry* model_type_registry,
-    bool keystore_encryption_enabled,
     const std::string& invalidator_client_id,
     const std::string& birthday,
     const std::string& bag_of_chips,
@@ -30,7 +29,6 @@
       max_commit_batch_size_(kDefaultMaxCommitBatchSize),
       debug_info_getter_(debug_info_getter),
       model_type_registry_(model_type_registry),
-      keystore_encryption_enabled_(keystore_encryption_enabled),
       invalidator_client_id_(invalidator_client_id),
       cookie_jar_mismatch_(false),
       cookie_jar_empty_(false),
diff --git a/components/sync/engine_impl/cycle/sync_cycle_context.h b/components/sync/engine_impl/cycle/sync_cycle_context.h
index fbd75b51..91f44d0 100644
--- a/components/sync/engine_impl/cycle/sync_cycle_context.h
+++ b/components/sync/engine_impl/cycle/sync_cycle_context.h
@@ -47,7 +47,6 @@
                    const std::vector<SyncEngineEventListener*>& listeners,
                    DebugInfoGetter* debug_info_getter,
                    ModelTypeRegistry* model_type_registry,
-                   bool keystore_encryption_enabled,
                    const std::string& invalidator_client_id,
                    const std::string& birthday,
                    const std::string& bag_of_chips,
@@ -90,10 +89,6 @@
     return &listeners_;
   }
 
-  bool keystore_encryption_enabled() const {
-    return keystore_encryption_enabled_;
-  }
-
   void set_hierarchy_conflict_detected(bool value) {
     client_status_.set_hierarchy_conflict_detected(value);
   }
@@ -163,11 +158,6 @@
   // Satus information to be sent up to the server.
   sync_pb::ClientStatus client_status_;
 
-  // Temporary variable while keystore encryption is behind a flag. True if
-  // we should attempt performing keystore encryption related work, false if
-  // the experiment is not enabled.
-  bool keystore_encryption_enabled_;
-
   // This is a copy of the identifier the that the invalidations client used to
   // register itself with the invalidations server during startup.  We need to
   // provide this to the sync server when we make changes to enable it to
diff --git a/components/sync/engine_impl/sync_manager_impl_unittest.cc b/components/sync/engine_impl/sync_manager_impl_unittest.cc
index 49b8ec3..38e9f83f 100644
--- a/components/sync/engine_impl/sync_manager_impl_unittest.cc
+++ b/components/sync/engine_impl/sync_manager_impl_unittest.cc
@@ -928,7 +928,6 @@
   SyncManagerTest()
       : sync_manager_("Test sync manager",
                       network::TestNetworkConnectionTracker::GetInstance()) {
-    switches_.encryption_method = EngineComponentsFactory::ENCRYPTION_KEYSTORE;
   }
 
   ~SyncManagerTest() override {}
@@ -1096,8 +1095,7 @@
 
   virtual EngineComponentsFactory* GetFactory() {
     return new TestEngineComponentsFactory(
-        GetSwitches(), EngineComponentsFactory::STORAGE_IN_MEMORY,
-        &storage_used_);
+        EngineComponentsFactory::STORAGE_IN_MEMORY, &storage_used_);
   }
 
   // Returns true if we are currently encrypting all sync data.  May
@@ -1145,8 +1143,6 @@
     }
   }
 
-  EngineComponentsFactory::Switches GetSwitches() const { return switches_; }
-
   void ExpectPassphraseAcceptance() {
     EXPECT_CALL(*encryption_observer_, OnPassphraseAccepted());
     EXPECT_CALL(*encryption_observer_, OnEncryptionComplete());
@@ -1189,7 +1185,6 @@
   StrictMock<SyncManagerObserverMock> manager_observer_;
   // Owned by |sync_manager_|.
   StrictMock<SyncEncryptionHandlerObserverMock>* encryption_observer_;
-  EngineComponentsFactory::Switches switches_;
   EngineComponentsFactory::StorageOption storage_used_;
   MockUnrecoverableErrorHandler mock_unrecoverable_error_handler_;
 };
@@ -2504,12 +2499,10 @@
 
 class ComponentsFactory : public TestEngineComponentsFactory {
  public:
-  ComponentsFactory(const Switches& switches,
-                    SyncScheduler* scheduler_to_use,
+  ComponentsFactory(SyncScheduler* scheduler_to_use,
                     SyncCycleContext** cycle_context,
                     EngineComponentsFactory::StorageOption* storage_used)
-      : TestEngineComponentsFactory(switches,
-                                    EngineComponentsFactory::STORAGE_IN_MEMORY,
+      : TestEngineComponentsFactory(EngineComponentsFactory::STORAGE_IN_MEMORY,
                                     storage_used),
         scheduler_to_use_(scheduler_to_use),
         cycle_context_(cycle_context) {}
@@ -2534,8 +2527,7 @@
   SyncManagerTestWithMockScheduler() : scheduler_(nullptr) {}
   EngineComponentsFactory* GetFactory() override {
     scheduler_ = new MockSyncScheduler();
-    return new ComponentsFactory(GetSwitches(), scheduler_, &cycle_context_,
-                                 &storage_used_);
+    return new ComponentsFactory(scheduler_, &cycle_context_, &storage_used_);
   }
 
   MockSyncScheduler* scheduler() { return scheduler_; }
@@ -3180,8 +3172,7 @@
 
   EngineComponentsFactory* GetFactory() override {
     return new TestEngineComponentsFactory(
-        GetSwitches(), EngineComponentsFactory::STORAGE_INVALID,
-        &storage_used_);
+        EngineComponentsFactory::STORAGE_INVALID, &storage_used_);
   }
 };
 
diff --git a/components/sync/engine_impl/sync_scheduler_impl_unittest.cc b/components/sync/engine_impl/sync_scheduler_impl_unittest.cc
index f6cf843..fdefc0e 100644
--- a/components/sync/engine_impl/sync_scheduler_impl_unittest.cc
+++ b/components/sync/engine_impl/sync_scheduler_impl_unittest.cc
@@ -138,9 +138,8 @@
     context_ = std::make_unique<SyncCycleContext>(
         connection_.get(), directory(), extensions_activity_.get(),
         std::vector<SyncEngineEventListener*>(), nullptr,
-        model_type_registry_.get(),
-        true,  // enable keystore encryption
-        "fake_invalidator_client_id", "fake_birthday", "fake_bag_of_chips",
+        model_type_registry_.get(), "fake_invalidator_client_id",
+        "fake_birthday", "fake_bag_of_chips",
         /*poll_interval=*/base::TimeDelta::FromMinutes(30));
     context_->set_notifications_enabled(true);
     context_->set_account_name("Test");
diff --git a/components/sync/engine_impl/syncer_proto_util_unittest.cc b/components/sync/engine_impl/syncer_proto_util_unittest.cc
index 98aa230..fd640e0 100644
--- a/components/sync/engine_impl/syncer_proto_util_unittest.cc
+++ b/components/sync/engine_impl/syncer_proto_util_unittest.cc
@@ -120,7 +120,6 @@
         /*listeners=*/std::vector<SyncEngineEventListener*>(),
         /*debug_info_getter=*/nullptr,
         /*model_type_registry=*/nullptr,
-        /*keystore_encryption_enabled=*/false,
         /*invalidator_client_id=*/"",
         /*birthday=*/"",
         /*bag_of_chips=*/"",
diff --git a/components/sync/engine_impl/syncer_unittest.cc b/components/sync/engine_impl/syncer_unittest.cc
index 9129af5..fbf16c7f 100644
--- a/components/sync/engine_impl/syncer_unittest.cc
+++ b/components/sync/engine_impl/syncer_unittest.cc
@@ -279,7 +279,6 @@
     context_ = std::make_unique<SyncCycleContext>(
         mock_server_.get(), directory(), extensions_activity_.get(), listeners,
         debug_info_getter_.get(), model_type_registry_.get(),
-        true,  // enable keystore encryption
         "fake_invalidator_client_id", mock_server_->store_birthday(),
         "fake_bag_of_chips",
         /*poll_interval=*/base::TimeDelta::FromMinutes(30));
diff --git a/components/sync/model_impl/client_tag_based_model_type_processor.cc b/components/sync/model_impl/client_tag_based_model_type_processor.cc
index 60e2e06d..0c24ca9 100644
--- a/components/sync/model_impl/client_tag_based_model_type_processor.cc
+++ b/components/sync/model_impl/client_tag_based_model_type_processor.cc
@@ -724,7 +724,6 @@
     error = OnFullUpdateReceived(model_type_state, std::move(updates));
   } else {
     error = OnIncrementalUpdateReceived(model_type_state, std::move(updates));
-    ExpireEntriesIfNeeded(model_type_state.progress_marker());
   }
 
   if (error) {
@@ -1342,49 +1341,6 @@
   return model_ready_to_sync_;
 }
 
-void ClientTagBasedModelTypeProcessor::ExpireEntriesIfNeeded(
-    const sync_pb::DataTypeProgressMarker& progress_marker) {
-  if (!progress_marker.has_gc_directive())
-    return;
-
-  const sync_pb::GarbageCollectionDirective& new_gc_directive =
-      progress_marker.gc_directive();
-  std::unique_ptr<MetadataChangeList> metadata_changes =
-      bridge_->CreateMetadataChangeList();
-  bool has_expired_changes = false;
-
-  if (new_gc_directive.has_age_watermark_in_days()) {
-    DCHECK(new_gc_directive.age_watermark_in_days());
-    // For saving resource purpose(ex. cpu, battery), We round up garbage
-    // collection age to day, so we only run GC once a day if server did not
-    // change the |age_watermark_in_days|.
-    base::Time to_be_expired =
-        base::Time::Now().LocalMidnight() -
-        base::TimeDelta::FromDays(new_gc_directive.age_watermark_in_days());
-    if (cached_gc_directive_aged_out_day_ != to_be_expired) {
-      ExpireEntriesByAge(new_gc_directive.age_watermark_in_days(),
-                         metadata_changes.get());
-      cached_gc_directive_aged_out_day_ = to_be_expired;
-      has_expired_changes = true;
-    }
-  }
-
-  if (has_expired_changes)
-    bridge_->ApplySyncChanges(std::move(metadata_changes), EntityChangeList());
-}
-
-void ClientTagBasedModelTypeProcessor::ClearMetadataForEntries(
-    const std::vector<std::string>& storage_key_to_be_deleted,
-    MetadataChangeList* metadata_changes) {
-  for (const std::string& key : storage_key_to_be_deleted) {
-    metadata_changes->ClearMetadata(key);
-    auto iter = storage_key_to_tag_hash_.find(key);
-    DCHECK(iter != storage_key_to_tag_hash_.end());
-    entities_.erase(iter->second);
-    storage_key_to_tag_hash_.erase(key);
-  }
-}
-
 void ClientTagBasedModelTypeProcessor::ExpireAllEntries(
     MetadataChangeList* metadata_changes) {
   DCHECK(metadata_changes);
@@ -1397,27 +1353,14 @@
     }
   }
 
-  ClearMetadataForEntries(storage_key_to_be_deleted, metadata_changes);
-}
-
-void ClientTagBasedModelTypeProcessor::ExpireEntriesByAge(
-    int32_t age_watermark_in_days,
-    MetadataChangeList* metadata_changes) {
-  DCHECK(metadata_changes);
-
-  base::Time to_be_expired =
-      base::Time::Now() - base::TimeDelta::FromDays(age_watermark_in_days);
-  std::vector<std::string> storage_key_to_be_deleted;
-  for (const auto& kv : entities_) {
-    ProcessorEntity* entity = kv.second.get();
-    if (!entity->IsUnsynced() &&
-        ProtoTimeToTime(entity->metadata().modification_time()) <=
-            to_be_expired) {
-      storage_key_to_be_deleted.push_back(entity->storage_key());
-    }
+  // Delete selected keys while not iterating over |entities_|.
+  for (const std::string& key : storage_key_to_be_deleted) {
+    metadata_changes->ClearMetadata(key);
+    auto iter = storage_key_to_tag_hash_.find(key);
+    DCHECK(iter != storage_key_to_tag_hash_.end());
+    entities_.erase(iter->second);
+    storage_key_to_tag_hash_.erase(iter);
   }
-
-  ClearMetadataForEntries(storage_key_to_be_deleted, metadata_changes);
 }
 
 void ClientTagBasedModelTypeProcessor::RemoveEntity(
@@ -1432,7 +1375,6 @@
     SyncStopMetadataFate metadata_fate) {
   // This should reset all mutable fields (except for |bridge_|).
   worker_.reset();
-  cached_gc_directive_aged_out_day_ = base::Time::FromDoubleT(0);
 
   switch (metadata_fate) {
     case KEEP_METADATA:
diff --git a/components/sync/model_impl/client_tag_based_model_type_processor.h b/components/sync/model_impl/client_tag_based_model_type_processor.h
index 41b35d6..67842cf 100644
--- a/components/sync/model_impl/client_tag_based_model_type_processor.h
+++ b/components/sync/model_impl/client_tag_based_model_type_processor.h
@@ -215,27 +215,11 @@
   // Returns true if all processor entities have non-empty storage keys.
   bool AllStorageKeysPopulated() const;
 
-  // Expires entries according to garbage collection directives.
-  void ExpireEntriesIfNeeded(
-      const sync_pb::DataTypeProgressMarker& progress_marker);
-
-  // Clear metadata for the entries in |storage_key_to_be_deleted|.
-  void ClearMetadataForEntries(
-      const std::vector<std::string>& storage_key_to_be_deleted,
-      MetadataChangeList* metadata_changes);
-
   // Removes metadata for all entries unless they are unsynced.
   // This is used to limit the amount of data stored in sync, and this does not
   // tell the bridge to delete the actual data.
   void ExpireAllEntries(MetadataChangeList* metadata_changes);
 
-  // Removes metadata for all entries whose ages are older than
-  // |age_watermark_in_days| unless they are unsynced.
-  // This is used to limit the amount of data stored in sync, and this does not
-  // tell the bridge to delete the actual data.
-  void ExpireEntriesByAge(int32_t age_watermark_in_days,
-                          MetadataChangeList* metadata_changes);
-
   // Removes |entity| and clears metadata for |entity| from
   // |metadata_change_list|.
   void RemoveEntity(ProcessorEntity* entity,
@@ -326,12 +310,6 @@
   // intends to read it. This includes both data and metadata.
   const bool commit_only_;
 
-  // The day which processor already ran garbage collection against on.
-  // Cache this value is for saving resource purpose(ex. cpu, battery), we round
-  // up garbage collection age to day, so we only run GC once a day if server
-  // did not change the age out days.
-  base::Time cached_gc_directive_aged_out_day_;
-
   SEQUENCE_CHECKER(sequence_checker_);
 
   // WeakPtrFactory for this processor for ModelTypeController (only gets
diff --git a/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc b/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc
index a75e70b..41cbe307 100644
--- a/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc
+++ b/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc
@@ -2184,7 +2184,7 @@
 // Tests that the processor reports an error for updates with a version GC
 // directive that are received for types that support incremental updates.
 TEST_F(ClientTagBasedModelTypeProcessorTest,
-       ShouldApplyGarbageCollectionByVersion) {
+       ShouldNotApplyGarbageCollectionByVersion) {
   InitializeToReadyState();
 
   ExpectError();
@@ -2193,41 +2193,6 @@
   worker()->UpdateWithGarbageCollection(garbage_collection_directive);
 }
 
-// Tests that ClientTagBasedModelTypeProcessor can do garbage collection by age.
-// Create 2 entries, one is 15-days-old, another is 5-days-old. Check if sync
-// will delete 15-days-old entry when server set expired age is 10 days.
-TEST_F(ClientTagBasedModelTypeProcessorTest,
-       ShouldApplyGarbageCollectionByAge) {
-  InitializeToReadyState();
-
-  // Create 2 entries, one is 15-days-old, another is 5-days-old.
-  std::unique_ptr<EntityData> entity_data =
-      bridge()->GenerateEntityData(kKey1, kValue1);
-  entity_data->modification_time =
-      base::Time::Now() - base::TimeDelta::FromDays(15);
-  WriteItemAndAck(kKey1, std::move(entity_data));
-  entity_data = bridge()->GenerateEntityData(kKey2, kValue2);
-  entity_data->modification_time =
-      base::Time::Now() - base::TimeDelta::FromDays(5);
-  WriteItemAndAck(kKey2, std::move(entity_data));
-
-  // Verify entries are created correctly.
-  EXPECT_EQ(2U, ProcessorEntityCount());
-  EXPECT_EQ(2U, db()->metadata_count());
-  EXPECT_EQ(2U, db()->data_count());
-  EXPECT_EQ(0U, worker()->GetNumPendingCommits());
-
-  // Expired the entries which are older than 10 days.
-  sync_pb::GarbageCollectionDirective garbage_collection_directive;
-  garbage_collection_directive.set_age_watermark_in_days(10);
-  worker()->UpdateWithGarbageCollection(garbage_collection_directive);
-
-  EXPECT_EQ(1U, ProcessorEntityCount());
-  EXPECT_EQ(1U, db()->metadata_count());
-  EXPECT_EQ(2U, db()->data_count());
-  EXPECT_EQ(0U, worker()->GetNumPendingCommits());
-}
-
 TEST_F(ClientTagBasedModelTypeProcessorTest,
        ShouldDeleteMetadataWhenCacheGuidMismatch) {
   // Commit item.
diff --git a/components/sync/nigori/cryptographer_impl.cc b/components/sync/nigori/cryptographer_impl.cc
new file mode 100644
index 0000000..d051aeb
--- /dev/null
+++ b/components/sync/nigori/cryptographer_impl.cc
@@ -0,0 +1,128 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/sync/nigori/cryptographer_impl.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+
+namespace syncer {
+
+// static
+std::unique_ptr<CryptographerImpl> CryptographerImpl::CreateEmpty() {
+  return base::WrapUnique(
+      new CryptographerImpl(NigoriKeyBag::CreateEmpty(),
+                            /*default_encryption_key_name=*/std::string()));
+}
+
+// static
+std::unique_ptr<CryptographerImpl> CryptographerImpl::FromSingleKeyForTesting(
+    const std::string& passphrase,
+    const KeyDerivationParams& derivation_params) {
+  std::unique_ptr<CryptographerImpl> cryptographer = CreateEmpty();
+  std::string key_name =
+      cryptographer->EmplaceKey(passphrase, derivation_params);
+  cryptographer->SelectDefaultEncryptionKey(key_name);
+  return cryptographer;
+}
+
+// static
+std::unique_ptr<CryptographerImpl> CryptographerImpl::FromProto(
+    const sync_pb::CryptographerData& proto) {
+  NigoriKeyBag key_bag = NigoriKeyBag::CreateFromProto(proto.key_bag());
+  std::string default_encryption_key_name = proto.default_key_name();
+  if (!default_encryption_key_name.empty() &&
+      !key_bag.HasKey(default_encryption_key_name)) {
+    // A default key name was specified but not present among keys.
+    return nullptr;
+  }
+
+  return base::WrapUnique(new CryptographerImpl(
+      std::move(key_bag), std::move(default_encryption_key_name)));
+}
+
+CryptographerImpl::CryptographerImpl(NigoriKeyBag key_bag,
+                                     std::string default_encryption_key_name)
+    : key_bag_(std::move(key_bag)),
+      default_encryption_key_name_(std::move(default_encryption_key_name)) {
+  DCHECK(default_encryption_key_name_.empty() ||
+         key_bag_.HasKey(default_encryption_key_name_));
+}
+
+CryptographerImpl::~CryptographerImpl() = default;
+
+sync_pb::CryptographerData CryptographerImpl::ToProto() const {
+  sync_pb::CryptographerData proto;
+  *proto.mutable_key_bag() = key_bag_.ToProto();
+  proto.set_default_key_name(default_encryption_key_name_);
+  return proto;
+}
+
+std::string CryptographerImpl::EmplaceKey(
+    const std::string& passphrase,
+    const KeyDerivationParams& derivation_params) {
+  return key_bag_.AddKey(
+      Nigori::CreateByDerivation(derivation_params, passphrase));
+}
+
+void CryptographerImpl::EmplaceKeysFrom(const NigoriKeyBag& key_bag) {
+  key_bag_.AddAllUnknownKeysFrom(key_bag);
+}
+
+void CryptographerImpl::SelectDefaultEncryptionKey(
+    const std::string& key_name) {
+  DCHECK(!key_name.empty());
+  DCHECK(key_bag_.HasKey(key_name));
+  default_encryption_key_name_ = key_name;
+}
+
+void CryptographerImpl::ClearDefaultEncryptionKey() {
+  default_encryption_key_name_.clear();
+}
+
+std::unique_ptr<Cryptographer> CryptographerImpl::Clone() const {
+  return base::WrapUnique(
+      new CryptographerImpl(key_bag_.Clone(), default_encryption_key_name_));
+}
+
+bool CryptographerImpl::CanEncrypt() const {
+  return !default_encryption_key_name_.empty();
+}
+
+bool CryptographerImpl::CanDecrypt(
+    const sync_pb::EncryptedData& encrypted) const {
+  return key_bag_.HasKey(encrypted.key_name());
+}
+
+std::string CryptographerImpl::GetDefaultEncryptionKeyName() const {
+  return default_encryption_key_name_;
+}
+
+bool CryptographerImpl::EncryptString(const std::string& decrypted,
+                                      sync_pb::EncryptedData* encrypted) const {
+  DCHECK(encrypted);
+  encrypted->Clear();
+
+  if (!CanEncrypt()) {
+    return false;
+  }
+
+  return key_bag_.EncryptWithKey(default_encryption_key_name_, decrypted,
+                                 encrypted);
+}
+
+bool CryptographerImpl::DecryptToString(const sync_pb::EncryptedData& encrypted,
+                                        std::string* decrypted) const {
+  DCHECK(decrypted);
+  return key_bag_.Decrypt(encrypted, decrypted);
+}
+
+bool CryptographerImpl::has_pending_keys() const {
+  // TODO(crbug.com/967417): Move this hack away.
+  return !CanEncrypt() && key_bag_.size() != 0;
+}
+
+}  // namespace syncer
diff --git a/components/sync/nigori/cryptographer_impl.h b/components/sync/nigori/cryptographer_impl.h
new file mode 100644
index 0000000..94c2e46
--- /dev/null
+++ b/components/sync/nigori/cryptographer_impl.h
@@ -0,0 +1,96 @@
+// 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 COMPONENTS_SYNC_NIGORI_CRYPTOGRAPHER_IMPL_H_
+#define COMPONENTS_SYNC_NIGORI_CRYPTOGRAPHER_IMPL_H_
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "components/sync/nigori/cryptographer.h"
+#include "components/sync/nigori/nigori.h"
+#include "components/sync/nigori/nigori_key_bag.h"
+#include "components/sync/protocol/nigori_local_data.pb.h"
+
+namespace sync_pb {
+class CryptographerData;
+}  // namespace sync_pb
+
+namespace syncer {
+
+// This class manages the Nigori objects used to encrypt and decrypt sensitive
+// sync data (eg. passwords). Each Nigori object knows how to handle data
+// protected with a particular encryption key.
+//
+// The implementation consists of a keybag representing all known keys and
+// optionally the notion of a default encryption key which, if it exists, is
+// present in the keybag.
+class CryptographerImpl : public Cryptographer {
+ public:
+  // Factory methods.
+  static std::unique_ptr<CryptographerImpl> CreateEmpty();
+  static std::unique_ptr<CryptographerImpl> FromSingleKeyForTesting(
+      const std::string& passphrase,
+      const KeyDerivationParams& derivation_params =
+          KeyDerivationParams::CreateForPbkdf2());
+  // Returns null in case of error (e.g. default key not present in keybag).
+  static std::unique_ptr<CryptographerImpl> FromProto(
+      const sync_pb::CryptographerData& proto);
+
+  ~CryptographerImpl() override;
+
+  // Serialization.
+  sync_pb::CryptographerData ToProto() const;
+
+  // Creates and registers a new key after deriving Nigori keys. Returns the
+  // name of the key, or an empty string in case of error. Note that emplacing
+  // an already-known key is not considered an error (just a no-op).
+  //
+  // Does NOT set or change the default encryption key.
+  std::string EmplaceKey(const std::string& passphrase,
+                         const KeyDerivationParams& derivation_params);
+
+  // Adds all keys from |key_bag| that weren't previously known.
+  //
+  // Does NOT set or change the default encryption key.
+  void EmplaceKeysFrom(const NigoriKeyBag& key_bag);
+
+  // Sets or changes the default encryption key, which causes CanEncrypt() to
+  // return true. |key_name| must not be empty and must represent a known key.
+  void SelectDefaultEncryptionKey(const std::string& key_name);
+
+  // Clears the default encryption key, which causes CanEncrypt() to return
+  // false.
+  void ClearDefaultEncryptionKey();
+
+  // Cryptographer overrides.
+  std::unique_ptr<Cryptographer> Clone() const override;
+  bool CanEncrypt() const override;
+  bool CanDecrypt(const sync_pb::EncryptedData& encrypted) const override;
+  std::string GetDefaultEncryptionKeyName() const override;
+  bool EncryptString(const std::string& decrypted,
+                     sync_pb::EncryptedData* encrypted) const override;
+  bool DecryptToString(const sync_pb::EncryptedData& encrypted,
+                       std::string* decrypted) const override;
+  bool has_pending_keys() const override;
+
+ private:
+  CryptographerImpl(NigoriKeyBag key_bag,
+                    std::string default_encryption_key_name);
+
+  // The actual keys we know about.
+  NigoriKeyBag key_bag_;
+
+  // The key name associated with the default encryption key. If non-empty, it
+  // must correspond to a key within |key_bag_|. May be empty even if |key_bag_|
+  // is not.
+  std::string default_encryption_key_name_;
+
+  DISALLOW_ASSIGN(CryptographerImpl);
+};
+
+}  // namespace syncer
+
+#endif  // COMPONENTS_SYNC_NIGORI_CRYPTOGRAPHER_IMPL_H_
diff --git a/components/sync/nigori/cryptographer_impl_unittest.cc b/components/sync/nigori/cryptographer_impl_unittest.cc
new file mode 100644
index 0000000..76b6491
--- /dev/null
+++ b/components/sync/nigori/cryptographer_impl_unittest.cc
@@ -0,0 +1,135 @@
+// 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 "components/sync/nigori/cryptographer_impl.h"
+
+#include "components/sync/protocol/nigori_local_data.pb.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace syncer {
+namespace {
+
+using testing::Eq;
+using testing::Ne;
+using testing::NotNull;
+
+}  // namespace
+
+TEST(CryptographerImplTest, ShouldCreateEmpty) {
+  std::unique_ptr<CryptographerImpl> cryptographer =
+      CryptographerImpl::CreateEmpty();
+  ASSERT_THAT(cryptographer, NotNull());
+
+  EXPECT_FALSE(cryptographer->CanEncrypt());
+
+  sync_pb::EncryptedData encrypted;
+  encrypted.set_key_name("foo");
+  encrypted.set_blob("bar");
+
+  EXPECT_FALSE(cryptographer->CanDecrypt(encrypted));
+
+  std::string output;
+  EXPECT_FALSE(cryptographer->DecryptToString(encrypted, &output));
+}
+
+TEST(CryptographerImplTest, ShouldEmplaceKey) {
+  std::unique_ptr<CryptographerImpl> cryptographer =
+      CryptographerImpl::CreateEmpty();
+  ASSERT_THAT(cryptographer, NotNull());
+  ASSERT_FALSE(cryptographer->CanEncrypt());
+
+  const std::string key_name = cryptographer->EmplaceKey(
+      "password1", KeyDerivationParams::CreateForPbkdf2());
+  EXPECT_THAT(key_name, Ne(std::string()));
+
+  sync_pb::EncryptedData encrypted;
+  encrypted.set_key_name(key_name);
+  encrypted.set_blob("fakeblob");
+
+  EXPECT_TRUE(cryptographer->CanDecrypt(encrypted));
+  EXPECT_FALSE(cryptographer->CanEncrypt());
+}
+
+TEST(CryptographerImplTest, ShouldEmplaceExistingKey) {
+  std::unique_ptr<CryptographerImpl> cryptographer =
+      CryptographerImpl::CreateEmpty();
+  ASSERT_THAT(cryptographer, NotNull());
+
+  const std::string key_name = cryptographer->EmplaceKey(
+      "password1", KeyDerivationParams::CreateForPbkdf2());
+  ASSERT_THAT(key_name, Ne(std::string()));
+  EXPECT_THAT(cryptographer->EmplaceKey("password1",
+                                        KeyDerivationParams::CreateForPbkdf2()),
+              Eq(key_name));
+}
+
+TEST(CryptographerImplTest, ShouldEmplaceSecondKey) {
+  std::unique_ptr<CryptographerImpl> cryptographer =
+      CryptographerImpl::CreateEmpty();
+  ASSERT_THAT(cryptographer, NotNull());
+
+  const std::string key_name1 = cryptographer->EmplaceKey(
+      "password1", KeyDerivationParams::CreateForPbkdf2());
+  const std::string key_name2 = cryptographer->EmplaceKey(
+      "password2", KeyDerivationParams::CreateForPbkdf2());
+
+  EXPECT_THAT(key_name1, Ne(std::string()));
+  EXPECT_THAT(key_name2, Ne(std::string()));
+  EXPECT_THAT(key_name1, Ne(key_name2));
+}
+
+TEST(CryptographerImplTest, ShouldSelectDefaultEncryptionKey) {
+  std::unique_ptr<CryptographerImpl> cryptographer =
+      CryptographerImpl::CreateEmpty();
+  ASSERT_THAT(cryptographer, NotNull());
+  ASSERT_FALSE(cryptographer->CanEncrypt());
+
+  const std::string key_name = cryptographer->EmplaceKey(
+      "password1", KeyDerivationParams::CreateForPbkdf2());
+  ASSERT_THAT(key_name, Ne(std::string()));
+
+  cryptographer->SelectDefaultEncryptionKey(key_name);
+  ASSERT_TRUE(cryptographer->CanEncrypt());
+
+  sync_pb::EncryptedData encrypted;
+  EXPECT_TRUE(cryptographer->EncryptString("foo", &encrypted));
+  EXPECT_THAT(encrypted.key_name(), Eq(key_name));
+}
+
+TEST(CryptographerImplTest, ShouldSerializeToAndFromProto) {
+  const std::string kText1 = "foo";
+  const std::string kText2 = "bar";
+
+  std::unique_ptr<CryptographerImpl> original_cryptographer =
+      CryptographerImpl::CreateEmpty();
+  ASSERT_THAT(original_cryptographer, NotNull());
+
+  const std::string key_name1 = original_cryptographer->EmplaceKey(
+      "password1", KeyDerivationParams::CreateForPbkdf2());
+  const std::string key_name2 = original_cryptographer->EmplaceKey(
+      "password2", KeyDerivationParams::CreateForPbkdf2());
+
+  original_cryptographer->SelectDefaultEncryptionKey(key_name1);
+  sync_pb::EncryptedData encrypted1;
+  EXPECT_TRUE(original_cryptographer->EncryptString(kText1, &encrypted1));
+
+  original_cryptographer->SelectDefaultEncryptionKey(key_name2);
+  sync_pb::EncryptedData encrypted2;
+  EXPECT_TRUE(original_cryptographer->EncryptString(kText2, &encrypted2));
+
+  // Restore a new cryptographer from proto.
+  std::unique_ptr<CryptographerImpl> restored_cryptographer =
+      CryptographerImpl::FromProto(original_cryptographer->ToProto());
+  ASSERT_THAT(restored_cryptographer, NotNull());
+  EXPECT_TRUE(restored_cryptographer->CanEncrypt());
+
+  std::string decrypted;
+  EXPECT_TRUE(restored_cryptographer->DecryptToString(encrypted1, &decrypted));
+  EXPECT_THAT(decrypted, Eq(kText1));
+  EXPECT_TRUE(restored_cryptographer->DecryptToString(encrypted2, &decrypted));
+  EXPECT_THAT(decrypted, Eq(kText2));
+}
+
+}  // namespace syncer
diff --git a/components/sync/nigori/nigori.cc b/components/sync/nigori/nigori.cc
index f43d7fb..89651fd 100644
--- a/components/sync/nigori/nigori.cc
+++ b/components/sync/nigori/nigori.cc
@@ -202,6 +202,9 @@
   // |user_key| is not used anymore so we tolerate a failed import.
   user_key = SymmetricKey::Import(SymmetricKey::AES, user_key_str);
 
+  if (encryption_key_str.empty() || mac_key_str.empty())
+    return false;
+
   encryption_key = SymmetricKey::Import(SymmetricKey::AES, encryption_key_str);
   if (!encryption_key)
     return false;
diff --git a/components/sync/nigori/nigori_key_bag.cc b/components/sync/nigori/nigori_key_bag.cc
index f5f56e6..11072a2 100644
--- a/components/sync/nigori/nigori_key_bag.cc
+++ b/components/sync/nigori/nigori_key_bag.cc
@@ -55,17 +55,11 @@
 NigoriKeyBag NigoriKeyBag::CreateFromProto(const sync_pb::NigoriKeyBag& proto) {
   NigoriKeyBag output;
   for (const sync_pb::NigoriKey& key : proto.key()) {
-    std::unique_ptr<Nigori> nigori = Nigori::CreateByImport(
-        key.user_key(), key.encryption_key(), key.mac_key());
-    if (!nigori) {
+    if (output.AddKeyFromProto(key).empty()) {
       // TODO(crbug.com/922900): Consider propagating this error to callers such
       // that they can do smarter handling.
       DLOG(ERROR) << "Invalid NigoriKey protocol buffer message.";
-      continue;
     }
-    // TODO(crbug.com/967417): We shouldn't trust the name in the proto and
-    // instead should compute ComputeNigoriName(*nigori).
-    output.nigori_map_[key.name()] = std::move(nigori);
   }
   return output;
 }
@@ -118,6 +112,22 @@
   return key_name;
 }
 
+std::string NigoriKeyBag::AddKeyFromProto(const sync_pb::NigoriKey& key) {
+  std::unique_ptr<Nigori> nigori = Nigori::CreateByImport(
+      key.user_key(), key.encryption_key(), key.mac_key());
+  if (!nigori) {
+    return std::string();
+  }
+
+  const std::string key_name = ComputeNigoriName(*nigori);
+  if (key_name.empty()) {
+    return std::string();
+  }
+
+  nigori_map_[key_name] = std::move(nigori);
+  return key_name;
+}
+
 void NigoriKeyBag::AddAllUnknownKeysFrom(const NigoriKeyBag& other) {
   for (const auto& key_name_and_nigori : other.nigori_map_) {
     // Only use this key if we don't already know about it.
@@ -145,6 +155,11 @@
   return true;
 }
 
+bool NigoriKeyBag::CanDecrypt(
+    const sync_pb::EncryptedData& encrypted_input) const {
+  return HasKey(encrypted_input.key_name());
+}
+
 bool NigoriKeyBag::Decrypt(const sync_pb::EncryptedData& encrypted_input,
                            std::string* decrypted_output) const {
   DCHECK(decrypted_output);
@@ -155,7 +170,6 @@
   if (it == nigori_map_.end()) {
     // The key used to encrypt the blob is not part of the set of installed
     // nigoris.
-    DLOG(ERROR) << "Cannot decrypt message";
     return false;
   }
 
diff --git a/components/sync/nigori/nigori_key_bag.h b/components/sync/nigori/nigori_key_bag.h
index 820fcbb8..c11991d 100644
--- a/components/sync/nigori/nigori_key_bag.h
+++ b/components/sync/nigori/nigori_key_bag.h
@@ -48,6 +48,10 @@
   // string in case of failure.
   std::string AddKey(std::unique_ptr<Nigori> nigori);
 
+  // Similar to AddKey(), but reads the key material from a proto. The |name|
+  // field is ignored since it's redundant.
+  std::string AddKeyFromProto(const sync_pb::NigoriKey& key);
+
   // Merges all keys from another keybag, which means adding all keys that we
   // don't know about.
   void AddAllUnknownKeysFrom(const NigoriKeyBag& other);
@@ -58,6 +62,9 @@
                       const std::string& input,
                       sync_pb::EncryptedData* encrypted_output) const;
 
+  // Returns whether the key required to decrypt |encrypted_input| is known.
+  bool CanDecrypt(const sync_pb::EncryptedData& encrypted_input) const;
+
   // Decryption of strings (possibly binary). Returns true if success.
   // |decrypted_output| must not be null.
   bool Decrypt(const sync_pb::EncryptedData& encrypted_input,
diff --git a/components/sync/nigori/nigori_key_bag_unittest.cc b/components/sync/nigori/nigori_key_bag_unittest.cc
index fb8231ed..f337216 100644
--- a/components/sync/nigori/nigori_key_bag_unittest.cc
+++ b/components/sync/nigori/nigori_key_bag_unittest.cc
@@ -114,5 +114,24 @@
   EXPECT_TRUE(cloned_key_bag.HasKey(key_name2));
 }
 
+TEST(NigoriKeyBagTest, ShouldIgnoreKeyNameProtoField) {
+  NigoriKeyBag original_key_bag = NigoriKeyBag::CreateEmpty();
+  const std::string real_key_name =
+      original_key_bag.AddKey(CreateTestNigori("password1"));
+  ASSERT_THAT(original_key_bag, SizeIs(1));
+
+  const std::string actual_key_name_in_proto =
+      NigoriKeyBag::CreateEmpty().AddKey(CreateTestNigori("password2"));
+
+  sync_pb::NigoriKeyBag proto = original_key_bag.ToProto();
+  proto.mutable_key(0)->set_name(actual_key_name_in_proto);
+
+  NigoriKeyBag restored_key_bag = NigoriKeyBag::CreateFromProto(proto);
+
+  ASSERT_THAT(restored_key_bag, SizeIs(1));
+  EXPECT_TRUE(restored_key_bag.HasKey(real_key_name));
+  EXPECT_FALSE(restored_key_bag.HasKey(actual_key_name_in_proto));
+}
+
 }  // namespace
 }  // namespace syncer
diff --git a/components/sync/nigori/nigori_sync_bridge_impl.cc b/components/sync/nigori/nigori_sync_bridge_impl.cc
index 4ee5f636..63aadc59 100644
--- a/components/sync/nigori/nigori_sync_bridge_impl.cc
+++ b/components/sync/nigori/nigori_sync_bridge_impl.cc
@@ -29,35 +29,56 @@
 
 const char kNigoriNonUniqueName[] = "Nigori";
 
-// Attempts to decrypt |keystore_decryptor_token| with |keystore_keys|. Returns
-// serialized Nigori key if successful and base::nullopt otherwise.
-base::Optional<std::string> DecryptKeystoreDecryptor(
-    const std::vector<std::string>& keystore_keys,
-    const sync_pb::EncryptedData& keystore_decryptor_token) {
-  if (keystore_decryptor_token.blob().empty()) {
-    return base::nullopt;
-  }
-
-  DirectoryCryptographer cryptographer;
+std::unique_ptr<DirectoryCryptographer> CreateCryptographerFromKeystoreKeys(
+    const std::vector<std::string>& keystore_keys) {
+  auto cryptographer = std::make_unique<DirectoryCryptographer>();
   for (const std::string& key : keystore_keys) {
     KeyParams key_params = {KeyDerivationParams::CreateForPbkdf2(), key};
     // TODO(crbug.com/922900): possible behavioral change. Old implementation
     // fails only if we failed to add current keystore key. Failing to add any
     // of these keys doesn't seem valid. This line seems to be a good candidate
     // for UMA, as it's not a normal situation, if we fail to add any key.
-    if (!cryptographer.AddKey(key_params)) {
-      return base::nullopt;
+    if (!cryptographer->AddKey(key_params)) {
+      return nullptr;
     }
   }
+  return cryptographer;
+}
 
-  std::string serialized_nigori_key;
-  // This check should never fail as long as we don't receive invalid data.
-  if (!cryptographer.CanDecrypt(keystore_decryptor_token) ||
-      !cryptographer.DecryptToString(keystore_decryptor_token,
-                                     &serialized_nigori_key)) {
-    return base::nullopt;
+// TODO(crbug.com/922900): This should be revisited because the encryption key
+// should be determined by keystore keys, which does not always match the
+// default encryption key.
+bool EncryptKeystoreDecryptorToken(
+    const DirectoryCryptographer& cryptographer,
+    sync_pb::EncryptedData* keystore_decryptor_token) {
+  DCHECK(keystore_decryptor_token);
+
+  return cryptographer.EncryptString(cryptographer.GetDefaultNigoriKeyData(),
+                                     keystore_decryptor_token);
+}
+
+// Attempts to decrypt |keystore_decryptor_token| with |keystore_keys|. Returns
+// a keybag with one key in case of success or an empty one in case of error.
+NigoriKeyBag DecryptKeystoreDecryptorToken(
+    const std::vector<std::string>& keystore_keys,
+    const sync_pb::EncryptedData& keystore_decryptor_token) {
+  if (keystore_decryptor_token.blob().empty()) {
+    return NigoriKeyBag::CreateEmpty();
   }
-  return serialized_nigori_key;
+
+  std::unique_ptr<Cryptographer> cryptographer =
+      CreateCryptographerFromKeystoreKeys(keystore_keys);
+
+  sync_pb::NigoriKey key;
+  // This check should never fail as long as we don't receive invalid data.
+  if (!cryptographer || !cryptographer->CanDecrypt(keystore_decryptor_token) ||
+      !cryptographer->Decrypt(keystore_decryptor_token, &key)) {
+    return NigoriKeyBag::CreateEmpty();
+  }
+
+  NigoriKeyBag key_bag = NigoriKeyBag::CreateEmpty();
+  key_bag.AddKeyFromProto(key);
+  return key_bag;
 }
 
 // Creates keystore Nigori specifics given |keystore_keys|.
@@ -75,24 +96,19 @@
     const std::vector<std::string>& keystore_keys) {
   DCHECK(!keystore_keys.empty());
 
-  DirectoryCryptographer cryptographer;
-  // The last keystore key will become default.
-  for (const std::string& key : keystore_keys) {
-    // This check and checks below theoretically should never fail, but in case
-    // of failure they should be handled.
-    if (!cryptographer.AddKey({KeyDerivationParams::CreateForPbkdf2(), key})) {
-      DLOG(ERROR) << "Failed to add keystore key to cryptographer.";
-      return base::nullopt;
-    }
+  std::unique_ptr<DirectoryCryptographer> cryptographer =
+      CreateCryptographerFromKeystoreKeys(keystore_keys);
+  if (!cryptographer) {
+    return base::nullopt;
   }
+
   NigoriSpecifics specifics;
-  if (!cryptographer.EncryptString(
-          cryptographer.GetDefaultNigoriKeyData(),
-          specifics.mutable_keystore_decryptor_token())) {
+  if (!EncryptKeystoreDecryptorToken(
+          *cryptographer, specifics.mutable_keystore_decryptor_token())) {
     DLOG(ERROR) << "Failed to encrypt default key as keystore_decryptor_token.";
     return base::nullopt;
   }
-  if (!cryptographer.GetKeys(specifics.mutable_encryption_keybag())) {
+  if (!cryptographer->GetKeys(specifics.mutable_encryption_keybag())) {
     DLOG(ERROR) << "Failed to encrypt keystore keys into encryption_keybag.";
     return base::nullopt;
   }
@@ -411,39 +427,32 @@
   return encoded_key;
 }
 
-// Unpacks explicit passphrase keys. Returns serialized sync_pb::NigoriKey if
-// successful. If |packed_key| is empty or decoding/decryption errors occur.
+// Unpacks explicit passphrase keys. Returns a populated sync_pb::NigoriKey if
+// successful, or an empty instance (i.e. default value) if |packed_key| is
+// empty or decoding/decryption errors occur.
 // Should be aligned with Directory implementation (
 // Cryptographer::UnpackBootstrapToken()) unless it is removed.
-std::string UnpackExplicitPassphraseKey(const Encryptor& encryptor,
-                                        const std::string& packed_key) {
+sync_pb::NigoriKey UnpackExplicitPassphraseKey(const Encryptor& encryptor,
+                                               const std::string& packed_key) {
   if (packed_key.empty()) {
-    return std::string();
+    return sync_pb::NigoriKey();
   }
 
   std::string decoded_key;
   if (!base::Base64Decode(packed_key, &decoded_key)) {
     DLOG(ERROR) << "Failed to decode explicit passphrase key.";
-    return std::string();
+    return sync_pb::NigoriKey();
   }
 
   std::string decrypted_key;
   if (!encryptor.DecryptString(decoded_key, &decrypted_key)) {
     DLOG(ERROR) << "Failed to decrypt expliciti passphrase key.";
-    return std::string();
+    return sync_pb::NigoriKey();
   }
-  return decrypted_key;
-}
 
-bool CanDecryptWithSerializedNigoriKey(
-    const std::string& serialized_key,
-    const sync_pb::EncryptedData& encrypted_data) {
-  if (serialized_key.empty()) {
-    return false;
-  }
-  DirectoryCryptographer cryptographer;
-  cryptographer.ImportNigoriKey(serialized_key);
-  return cryptographer.CanDecrypt(encrypted_data);
+  sync_pb::NigoriKey key;
+  key.ParseFromString(decrypted_key);
+  return key;
 }
 
 std::string ComputePbkdf2KeyName(const std::string& password) {
@@ -498,7 +507,7 @@
       processor_(std::move(processor)),
       storage_(std::move(storage)),
       random_salt_generator_(random_salt_generator),
-      serialized_explicit_passphrase_key_(
+      explicit_passphrase_key_(
           UnpackExplicitPassphraseKey(*encryptor,
                                       packed_explicit_passphrase_key)),
       passphrase_type_(NigoriSpecifics::UNKNOWN),
@@ -929,24 +938,19 @@
     const sync_pb::EncryptedData& keystore_decryptor_token) {
   DCHECK(!encryption_keybag.blob().empty());
   DCHECK(!keystore_decryptor_token.blob().empty());
-  if (cryptographer_.CanDecrypt(encryption_keybag)) {
-    cryptographer_.InstallKeys(encryption_keybag);
-    return base::nullopt;
+
+  cryptographer_.AddAllUnknownKeysFrom(
+      DecryptKeystoreDecryptorToken(keystore_keys_, keystore_decryptor_token));
+
+  sync_pb::NigoriKeyBag key_bag;
+  if (!cryptographer_.Decrypt(encryption_keybag, &key_bag)) {
+    return ModelError(FROM_HERE, "Failed to decrypt incoming keystore nigori.");
   }
-  // We weren't able to decrypt the keybag with current |cryptographer_|
-  // state, but we still can decrypt it with |keystore_keys_|. Note: it's a
-  // normal situation, once we perform initial sync or key rotation was
-  // performed by another client.
-  cryptographer_.SetPendingKeys(encryption_keybag);
-  base::Optional<std::string> serialized_keystore_decryptor =
-      DecryptKeystoreDecryptor(keystore_keys_, keystore_decryptor_token);
-  if (!serialized_keystore_decryptor ||
-      !cryptographer_.ImportNigoriKey(*serialized_keystore_decryptor) ||
-      !cryptographer_.CanEncrypt()) {
-    return ModelError(FROM_HERE,
-                      "Failed to decrypt pending keys using the keystore "
-                      "decryptor token.");
-  }
+
+  cryptographer_.AddAllUnknownKeysFrom(NigoriKeyBag::CreateFromProto(key_bag));
+  cryptographer_.ClearPendingKeys();
+  cryptographer_.SelectDefaultEncryptionKey(encryption_keybag.key_name());
+
   return base::nullopt;
 }
 
@@ -958,11 +962,13 @@
   if (!cryptographer_.CanDecrypt(encryption_keybag)) {
     // Historically, prior to USS, key derived from explicit passphrase was
     // stored in prefs and effectively we do migration here.
-    if (CanDecryptWithSerializedNigoriKey(serialized_explicit_passphrase_key_,
-                                          encryption_keybag)) {
-      // ImportNigoriKey() will set default key from
-      // |serialized_explicit_passphrase_key_|.
-      cryptographer_.ImportNigoriKey(serialized_explicit_passphrase_key_);
+    NigoriKeyBag key_bag = NigoriKeyBag::CreateEmpty();
+    const std::string key_name =
+        key_bag.AddKeyFromProto(explicit_passphrase_key_);
+    if (key_bag.CanDecrypt(encryption_keybag)) {
+      cryptographer_.AddAllUnknownKeysFrom(key_bag);
+      DCHECK(cryptographer_.CanDecrypt(encryption_keybag));
+      cryptographer_.SelectDefaultEncryptionKey(key_name);
     } else {
       // This will lead to OnPassphraseRequired() call later.
       cryptographer_.SetPendingKeys(encryption_keybag);
@@ -977,7 +983,9 @@
   // corresponding to the sentence above.
   // TODO(crbug.com/922900): we may also need to rewrite Nigori with keys
   // currently stored in cryptographer, in case it doesn't have them already.
-  cryptographer_.InstallKeys(encryption_keybag);
+  sync_pb::NigoriKeyBag key_bag;
+  cryptographer_.Decrypt(encryption_keybag, &key_bag);
+  cryptographer_.AddAllUnknownKeysFrom(NigoriKeyBag::CreateFromProto(key_bag));
 }
 
 std::unique_ptr<EntityData> NigoriSyncBridgeImpl::GetData() {
@@ -999,8 +1007,8 @@
         *custom_passphrase_key_derivation_params_, &specifics);
   }
   if (passphrase_type_ == NigoriSpecifics::KEYSTORE_PASSPHRASE) {
-    cryptographer_.EncryptString(cryptographer_.GetDefaultNigoriKeyData(),
-                                 specifics.mutable_keystore_decryptor_token());
+    EncryptKeystoreDecryptorToken(cryptographer_,
+                                  specifics.mutable_keystore_decryptor_token());
   }
   if (!keystore_migration_time_.is_null()) {
     specifics.set_keystore_migration_time(
@@ -1029,16 +1037,15 @@
 
 void NigoriSyncBridgeImpl::ApplyDisableSyncChanges() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  // The user intended to disable sync, so we need to clear all the data,
-  // except |serialized_explicit_passphrase_key_| in memory, because this
-  // function can be called due to BackendMigrator. It's safe even if this
-  // function called due to actual disabling sync, since we remove the
-  // persisted key by clearing sync prefs explicitly, and don't reuse current
-  // instance of the bridge after that.
+  // The user intended to disable sync, so we need to clear all the data, except
+  // |explicit_passphrase_key_| in memory, because this function can be called
+  // due to BackendMigrator. It's safe even if this function called due to
+  // actual disabling sync, since we remove the persisted key by clearing sync
+  // prefs explicitly, and don't reuse current instance of the bridge after
+  // that.
   // TODO(crbug.com/922900): idea with keeping
-  // |serialized_explicit_passphrase_key_| will become not working, once we
-  // clean up storing explicit passphrase key in prefs, we need to find better
-  // solution.
+  // |explicit_passphrase_key_| will become not working, once we clean up
+  // storing explicit passphrase key in prefs, we need to find better solution.
   storage_->ClearData();
   keystore_keys_.clear();
   cryptographer_.CopyFrom(DirectoryCryptographer());
diff --git a/components/sync/nigori/nigori_sync_bridge_impl.h b/components/sync/nigori/nigori_sync_bridge_impl.h
index 06003023..7f193ecb 100644
--- a/components/sync/nigori/nigori_sync_bridge_impl.h
+++ b/components/sync/nigori/nigori_sync_bridge_impl.h
@@ -124,10 +124,10 @@
   // passphrase if SCRYPT is enabled.
   const base::RepeatingCallback<std::string()> random_salt_generator_;
 
-  // Stores serialized sync_pb::NigoriKey derived from explicit passphrase and
-  // loaded from the prefs. Empty if prefs doesn't contain this key or in case
-  // of decryption/decoding errors.
-  std::string serialized_explicit_passphrase_key_;
+  // Stores a key derived from explicit passphrase and loaded from the prefs.
+  // Empty (i.e. default value) if prefs doesn't contain this key or in case of
+  // decryption/decoding errors.
+  const sync_pb::NigoriKey explicit_passphrase_key_;
 
   // Base64 encoded keystore keys. The last element is the current keystore
   // key. These keys are not a part of Nigori node and are persisted
diff --git a/components/sync/syncable/directory_cryptographer.cc b/components/sync/syncable/directory_cryptographer.cc
index 61982e0..e659f4b 100644
--- a/components/sync/syncable/directory_cryptographer.cc
+++ b/components/sync/syncable/directory_cryptographer.cc
@@ -164,6 +164,21 @@
       /*set_as_default=*/false);
 }
 
+void DirectoryCryptographer::AddAllUnknownKeysFrom(const NigoriKeyBag& other) {
+  key_bag_.AddAllUnknownKeysFrom(other);
+}
+
+void DirectoryCryptographer::SelectDefaultEncryptionKey(
+    const std::string& key_name) {
+  DCHECK(!key_name.empty());
+  DCHECK(key_bag_.HasKey(key_name));
+  default_nigori_name_ = key_name;
+}
+
+void DirectoryCryptographer::ClearPendingKeys() {
+  pending_keys_.reset();
+}
+
 bool DirectoryCryptographer::AddKeyFromBootstrapToken(
     const Encryptor& encryptor,
     const std::string& restored_bootstrap_token) {
diff --git a/components/sync/syncable/directory_cryptographer.h b/components/sync/syncable/directory_cryptographer.h
index 9f9c058b..751bf67 100644
--- a/components/sync/syncable/directory_cryptographer.h
+++ b/components/sync/syncable/directory_cryptographer.h
@@ -123,6 +123,12 @@
   // will become the new default).
   bool AddNonDefaultKey(const KeyParams& params);
 
+  // TODO(crbug.com/967417): Remove when transition of NigoriSyncBridgeImpl is
+  // finished.
+  void AddAllUnknownKeysFrom(const NigoriKeyBag& other);
+  void SelectDefaultEncryptionKey(const std::string& key_name);
+  void ClearPendingKeys();
+
   // Decrypts |encrypted| and uses its contents to initialize Nigori instances.
   // Returns true unless decryption of |encrypted| fails. The caller is
   // responsible for checking that CanDecrypt(encrypted) == true.
diff --git a/components/sync_device_info/device_info_sync_bridge.cc b/components/sync_device_info/device_info_sync_bridge.cc
index 9719083..e8b16a9 100644
--- a/components/sync_device_info/device_info_sync_bridge.cc
+++ b/components/sync_device_info/device_info_sync_bridge.cc
@@ -43,6 +43,8 @@
 
 namespace {
 
+constexpr base::TimeDelta kExpirationThreshold = base::TimeDelta::FromDays(56);
+
 // Find the timestamp for the last time this |device_info| was edited.
 Time GetLastUpdateTime(const DeviceInfoSpecifics& specifics) {
   if (specifics.has_last_updated_timestamp()) {
@@ -209,6 +211,7 @@
     }
 
     if (change->type() == EntityChange::ACTION_DELETE) {
+      // This should never get exercised as no client issues tombstones.
       has_changes |= DeleteSpecifics(guid, batch.get());
     } else {
       const DeviceInfoSpecifics& specifics =
@@ -444,6 +447,7 @@
   // This probably isn't strictly needed, but in case the cache_guid has changed
   // we save the new one to prefs.
   device_info_prefs_->AddLocalCacheGuid(local_cache_guid_);
+  ExpireOldEntries();
   ReconcileLocalAndStored();
 }
 
@@ -556,4 +560,31 @@
   return max_overlapping_sum;
 }
 
+void DeviceInfoSyncBridge::ExpireOldEntries() {
+  const base::Time expiration_threshold =
+      base::Time::Now() - kExpirationThreshold;
+  std::unordered_set<std::string> cache_guids_to_expire;
+  // Just collecting cache guids to expire to avoid modifying |all_data_| via
+  // DeleteSpecifics() while iterating over it.
+  for (const auto& pair : all_data_) {
+    const std::string& cache_guid = pair.first;
+    if (cache_guid != local_cache_guid_ &&
+        GetLastUpdateTime(*pair.second) < expiration_threshold) {
+      cache_guids_to_expire.insert(cache_guid);
+    }
+  }
+
+  if (cache_guids_to_expire.empty()) {
+    return;
+  }
+
+  std::unique_ptr<WriteBatch> batch = store_->CreateWriteBatch();
+  for (const std::string& cache_guid : cache_guids_to_expire) {
+    DeleteSpecifics(cache_guid, batch.get());
+    batch->GetMetadataChangeList()->ClearMetadata(cache_guid);
+    change_processor()->UntrackEntityForStorageKey(cache_guid);
+  }
+  CommitAndNotify(std::move(batch), /*should_notify=*/true);
+}
+
 }  // namespace syncer
diff --git a/components/sync_device_info/device_info_sync_bridge.h b/components/sync_device_info/device_info_sync_bridge.h
index 8d0640e..fd3d963 100644
--- a/components/sync_device_info/device_info_sync_bridge.h
+++ b/components/sync_device_info/device_info_sync_bridge.h
@@ -127,6 +127,9 @@
   // allow unit tests to control expected results.
   int CountActiveDevices(const base::Time now) const;
 
+  // Deletes locally old data and metadata entries without issuing tombstones.
+  void ExpireOldEntries();
+
   const std::unique_ptr<MutableLocalDeviceInfoProvider>
       local_device_info_provider_;
 
diff --git a/components/sync_device_info/device_info_sync_bridge_unittest.cc b/components/sync_device_info/device_info_sync_bridge_unittest.cc
index 67c741b2..25242578 100644
--- a/components/sync_device_info/device_info_sync_bridge_unittest.cc
+++ b/components/sync_device_info/device_info_sync_bridge_unittest.cc
@@ -950,6 +950,35 @@
   EXPECT_TRUE(bridge()->IsPulseTimerRunningForTest());
 }
 
+TEST_F(DeviceInfoSyncBridgeTest, ExpireOldEntriesUponStartup) {
+  InitializeAndMergeInitialData();
+  ASSERT_EQ(1u, bridge()->GetAllDeviceInfo().size());
+  ASSERT_EQ(1, change_count());
+  ASSERT_FALSE(ReadAllFromStore().empty());
+
+  const DeviceInfoSpecifics specifics_old =
+      CreateSpecifics(1, base::Time::Now() - base::TimeDelta::FromDays(57));
+  const DeviceInfoSpecifics specifics_fresh =
+      CreateSpecifics(1, base::Time::Now() - base::TimeDelta::FromDays(55));
+  auto error = bridge()->ApplySyncChanges(
+      bridge()->CreateMetadataChangeList(),
+      EntityAddList({specifics_old, specifics_fresh}));
+
+  ASSERT_FALSE(error);
+  ASSERT_EQ(2u, bridge()->GetAllDeviceInfo().size());
+  ASSERT_EQ(2, change_count());
+
+  // Reloading from storage should expire the old remote entity (but keep the
+  // fresh one).
+  RestartBridge();
+  EXPECT_EQ(2u, bridge()->GetAllDeviceInfo().size());
+  // Make sure this is well persisted to the DB store.
+  EXPECT_THAT(ReadAllFromStore(),
+              UnorderedElementsAre(
+                  Pair(local_device()->GetLocalDeviceInfo()->guid(), _),
+                  Pair(specifics_fresh.cache_guid(), _)));
+}
+
 }  // namespace
 
 }  // namespace syncer
diff --git a/components/translate/content/browser/content_translate_driver.cc b/components/translate/content/browser/content_translate_driver.cc
index ef00ef6342..80bb0d6 100644
--- a/components/translate/content/browser/content_translate_driver.cc
+++ b/components/translate/content/browser/content_translate_driver.cc
@@ -296,7 +296,7 @@
 }
 
 void ContentTranslateDriver::RegisterPage(
-    translate::mojom::PagePtr page,
+    mojo::PendingRemote<translate::mojom::Page> page,
     const translate::LanguageDetectionDetails& details,
     const bool page_needs_translation) {
   // If we have a language histogram (i.e. we're not in incognito), update it
@@ -304,8 +304,8 @@
   if (language_histogram_ && details.is_cld_reliable)
     language_histogram_->OnPageVisited(details.cld_language);
 
-  pages_[++next_page_seq_no_] = std::move(page);
-  pages_[next_page_seq_no_].set_connection_error_handler(
+  pages_[++next_page_seq_no_].Bind(std::move(page));
+  pages_[next_page_seq_no_].set_disconnect_handler(
       base::BindOnce(&ContentTranslateDriver::OnPageAway,
                      base::Unretained(this), next_page_seq_no_));
   translate_manager_->set_current_seq_no(next_page_seq_no_);
diff --git a/components/translate/content/browser/content_translate_driver.h b/components/translate/content/browser/content_translate_driver.h
index 704f538..ad90a92 100644
--- a/components/translate/content/browser/content_translate_driver.h
+++ b/components/translate/content/browser/content_translate_driver.h
@@ -16,6 +16,8 @@
 #include "components/translate/core/common/translate_errors.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
 
@@ -114,7 +116,7 @@
   // Adds a binding in |bindings_| for the passed |request|.
   void AddBinding(translate::mojom::ContentTranslateDriverRequest request);
   // Called when a page has been loaded and can be potentially translated.
-  void RegisterPage(translate::mojom::PagePtr page,
+  void RegisterPage(mojo::PendingRemote<translate::mojom::Page> page,
                     const translate::LanguageDetectionDetails& details,
                     bool page_needs_translation) override;
 
@@ -140,10 +142,10 @@
 
   // Records mojo connections with all current alive pages.
   int next_page_seq_no_;
-  // PagePtr is the connection between this driver and a TranslateHelper (which
-  // are per RenderFrame). Each TranslateHelper has a |binding_| member,
-  // representing the other end of this pipe.
-  std::map<int, mojom::PagePtr> pages_;
+  // mojo::Remote<Page> is the connection between this driver and a
+  // TranslateHelper (which are per RenderFrame). Each TranslateHelper has a
+  // |binding_| member, representing the other end of this pipe.
+  std::map<int, mojo::Remote<mojom::Page>> pages_;
 
   // Histogram to be notified about detected language of every page visited. Not
   // owned here.
diff --git a/components/translate/content/common/translate.mojom b/components/translate/content/common/translate.mojom
index 0893def..bc4a9f0 100644
--- a/components/translate/content/common/translate.mojom
+++ b/components/translate/content/common/translate.mojom
@@ -71,6 +71,6 @@
 interface ContentTranslateDriver {
   // Notification that a new page is ready to translate,
   // and the language for it has been determined.
-  RegisterPage(Page page, LanguageDetectionDetails details,
+  RegisterPage(pending_remote<Page> page, LanguageDetectionDetails details,
                bool page_needs_translation);
 };
diff --git a/components/translate/content/renderer/translate_helper.cc b/components/translate/content/renderer/translate_helper.cc
index 2974dcf..8bb0f4f 100644
--- a/components/translate/content/renderer/translate_helper.cc
+++ b/components/translate/content/renderer/translate_helper.cc
@@ -74,8 +74,7 @@
                                  const std::string& extension_scheme)
     : content::RenderFrameObserver(render_frame),
       world_id_(world_id),
-      extension_scheme_(extension_scheme),
-      binding_(this) {
+      extension_scheme_(extension_scheme) {
   translate_task_runner_ = this->render_frame()->GetTaskRunner(
       blink::TaskType::kInternalTranslation);
 }
@@ -134,12 +133,10 @@
   // For the same render frame with the same url, each time when its texts are
   // captured, it should be treated as a new page to do translation.
   ResetPage();
-  mojom::PagePtr page;
-  binding_.Bind(
-      mojo::MakeRequest(&page),
-      main_frame->GetTaskRunner(blink::TaskType::kInternalTranslation));
   GetTranslateHandler()->RegisterPage(
-      std::move(page), details, !details.has_notranslate && !language.empty());
+      receiver_.BindNewPipeAndPassRemote(
+          main_frame->GetTaskRunner(blink::TaskType::kInternalTranslation)),
+      details, !details.has_notranslate && !language.empty());
 }
 
 void TranslateHelper::CancelPendingTranslation() {
@@ -467,7 +464,7 @@
 }
 
 void TranslateHelper::ResetPage() {
-  binding_.Close();
+  receiver_.reset();
   translate_callback_pending_.Reset();
   CancelPendingTranslation();
 }
diff --git a/components/translate/content/renderer/translate_helper.h b/components/translate/content/renderer/translate_helper.h
index 5c6f382..15fae9d 100644
--- a/components/translate/content/renderer/translate_helper.h
+++ b/components/translate/content/renderer/translate_helper.h
@@ -16,7 +16,7 @@
 #include "components/translate/content/common/translate.mojom.h"
 #include "components/translate/core/common/translate_errors.h"
 #include "content/public/renderer/render_frame_observer.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
 #include "url/gurl.h"
 
@@ -176,7 +176,7 @@
   // Mojo interface).
   mojom::ContentTranslateDriverPtr translate_handler_;
 
-  mojo::Binding<mojom::Page> binding_;
+  mojo::Receiver<mojom::Page> receiver_{this};
 
   // Method factory used to make calls to TranslatePageImpl.
   base::WeakPtrFactory<TranslateHelper> weak_method_factory_{this};
diff --git a/content/browser/accessibility/ax_platform_node_textprovider_win_browsertest.cc b/content/browser/accessibility/ax_platform_node_textprovider_win_browsertest.cc
index 33b5ff0..2488119 100644
--- a/content/browser/accessibility/ax_platform_node_textprovider_win_browsertest.cc
+++ b/content/browser/accessibility/ax_platform_node_textprovider_win_browsertest.cc
@@ -54,7 +54,7 @@
     AccessibilityNotificationWaiter waiter(shell()->web_contents(),
                                            accessibility_mode,
                                            ax::mojom::Event::kLoadComplete);
-    NavigateToURL(shell(), url);
+    EXPECT_TRUE(NavigateToURL(shell(), url));
     waiter.WaitForNotification();
   }
 
diff --git a/content/browser/accessibility/cross_platform_accessibility_browsertest.cc b/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
index 7f07190..63938e3 100644
--- a/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
+++ b/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
@@ -725,7 +725,7 @@
       "<time></time>"
       "<div role='contentinfo' aria-label='contentinfo'></div>");
 
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
   waiter.WaitForNotification();
 
   BrowserAccessibility* root = GetManager()->GetRoot();
diff --git a/content/browser/back_forward_cache_browsertest.cc b/content/browser/back_forward_cache_browsertest.cc
index 963249c..9e26cd0e 100644
--- a/content/browser/back_forward_cache_browsertest.cc
+++ b/content/browser/back_forward_cache_browsertest.cc
@@ -1083,13 +1083,13 @@
       BackForwardCacheImpl::TEST_ASSUMES_NO_CACHING);
 
   // Navigate to a page that would normally be cacheable.
-  NavigateToURL(shell(),
-                embedded_test_server()->GetURL("a.com", "/title1.html"));
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
   RenderFrameDeletedObserver delete_observer_rfh_a(current_frame_host());
 
   // Navigate away.
-  NavigateToURL(shell(),
-                embedded_test_server()->GetURL("b.com", "/title1.html"));
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
 
   // The page should be deleted (not cached).
   delete_observer_rfh_a.WaitUntilDeleted();
diff --git a/content/browser/blob_storage/blob_url_browsertest.cc b/content/browser/blob_storage/blob_url_browsertest.cc
index 8547cd2..6e913b2 100644
--- a/content/browser/blob_storage/blob_url_browsertest.cc
+++ b/content/browser/blob_storage/blob_url_browsertest.cc
@@ -40,7 +40,7 @@
 IN_PROC_BROWSER_TEST_F(BlobUrlBrowserTest, LinkToUniqueOriginBlob) {
   // Use a data URL to obtain a test page in a unique origin. The page
   // contains a link to a "blob:null/SOME-GUID-STRING" URL.
-  NavigateToURL(
+  EXPECT_TRUE(NavigateToURL(
       shell(),
       GURL("data:text/html,<body><script>"
            "var link = document.body.appendChild(document.createElement('a'));"
@@ -48,7 +48,7 @@
            "link.href = URL.createObjectURL(new Blob(['potato']));"
            "link.target = '_blank';"
            "link.id = 'click_me';"
-           "</script></body>"));
+           "</script></body>")));
 
   // Click the link.
   ShellAddedObserver new_shell_observer;
@@ -75,7 +75,7 @@
   // Using an http page, click a link that opens a popup to a same-origin blob.
   GURL url = embedded_test_server()->GetURL("chromium.org", "/title1.html");
   url::Origin origin = url::Origin::Create(url);
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
 
   ShellAddedObserver new_shell_observer;
   EXPECT_TRUE(ExecuteScript(
@@ -108,7 +108,7 @@
   // that has a spoofy authority section applied. This should be blocked.
   GURL url = embedded_test_server()->GetURL("chromium.org", "/title1.html");
   url::Origin origin = url::Origin::Create(url);
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
 
   ShellAddedObserver new_shell_observer;
   EXPECT_TRUE(ExecuteScript(
@@ -146,7 +146,7 @@
   // an authority to the inner URL, which would be spoofy.
   GURL url = embedded_test_server()->GetURL("chromium.org", "/title1.html");
   url::Origin origin = url::Origin::Create(url);
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
 
   ShellAddedObserver new_shell_observer;
   EXPECT_TRUE(ExecuteScript(
diff --git a/content/browser/browser_interface_binders.cc b/content/browser/browser_interface_binders.cc
index 1d69315..6445fc7c 100644
--- a/content/browser/browser_interface_binders.cc
+++ b/content/browser/browser_interface_binders.cc
@@ -82,6 +82,9 @@
 
   map->Add<blink::mojom::WebBluetoothService>(base::BindRepeating(
       &RenderFrameHostImpl::CreateWebBluetoothService, base::Unretained(host)));
+
+  map->Add<blink::mojom::PushMessaging>(base::BindRepeating(
+      &RenderFrameHostImpl::GetPushMessaging, base::Unretained(host)));
 }
 
 void PopulateBinderMapWithContext(
diff --git a/content/browser/browser_main_loop_unittest.cc b/content/browser/browser_main_loop_unittest.cc
index b26e641..b7a7960 100644
--- a/content/browser/browser_main_loop_unittest.cc
+++ b/content/browser/browser_main_loop_unittest.cc
@@ -75,6 +75,7 @@
                     {base::ThreadPool(), base::TaskPriority::USER_VISIBLE}),
             base::SysInfo::NumberOfProcessors() - 1);
   browser_main_loop.ShutdownThreadsAndCleanUp();
+  BrowserTaskExecutor::ResetForTesting();
 }
 
 TEST_F(BrowserMainLoopTest,
@@ -104,6 +105,7 @@
   content::RunAllPendingInMessageLoop(BrowserThread::IO);
 
   browser_main_loop.ShutdownThreadsAndCleanUp();
+  BrowserTaskExecutor::ResetForTesting();
 }
 
 }  // namespace content
diff --git a/content/browser/browser_thread_unittest.cc b/content/browser/browser_thread_unittest.cc
index 4ec26451..06eb14cf 100644
--- a/content/browser/browser_thread_unittest.cc
+++ b/content/browser/browser_thread_unittest.cc
@@ -57,7 +57,9 @@
 
     BrowserTaskExecutor::CreateForTesting(
         std::move(browser_ui_thread_scheduler),
-        std::make_unique<BrowserIOThreadDelegate>());
+        std::make_unique<BrowserIOThreadDelegate>(
+            BrowserIOThreadDelegate::BrowserTaskExecutorPresent::
+                kNoForTesting));
     BrowserTaskExecutor::EnableAllQueues();
   }
 
@@ -116,6 +118,7 @@
 
     BrowserThreadImpl::ResetGlobalsForTesting(BrowserThread::UI);
     BrowserThreadImpl::ResetGlobalsForTesting(BrowserThread::IO);
+    BrowserTaskExecutor::ResetForTesting();
   }
 
   // Prepares this BrowserThreadTest for Release() to be invoked. |on_release|
@@ -284,7 +287,7 @@
   run_loop.Run();
 }
 
-TEST_F(BrowserThreadTest, RunsTasksInCurrentSequencedDuringShutdown) {
+TEST_F(BrowserThreadTest, RunsTasksInCurrentSequenceDuringShutdown) {
   bool did_shutdown = false;
   base::RunLoop loop;
   UIThreadDestructionObserver observer(&did_shutdown, loop.QuitClosure());
@@ -311,7 +314,9 @@
               QueueType::kDefault));
       BrowserTaskExecutor::CreateForTesting(
           std::move(browser_ui_thread_scheduler),
-          std::make_unique<BrowserIOThreadDelegate>());
+          std::make_unique<BrowserIOThreadDelegate>(
+              BrowserIOThreadDelegate::BrowserTaskExecutorPresent::
+                  kNoForTesting));
 
       ui_thread_ = BrowserTaskExecutor::CreateIOThread();
       BrowserTaskExecutor::InitializeIOThread();
diff --git a/content/browser/browsing_data/clear_site_data_handler_browsertest.cc b/content/browser/browsing_data/clear_site_data_handler_browsertest.cc
index f6156fa..2c27389 100644
--- a/content/browser/browsing_data/clear_site_data_handler_browsertest.cc
+++ b/content/browser/browsing_data/clear_site_data_handler_browsertest.cc
@@ -368,7 +368,8 @@
     AddQuery(&urls[0], "redirect", urls[1].spec());
 
     // Navigate to the first url of the redirect chain.
-    NavigateToURL(shell(), urls[0]);
+    EXPECT_TRUE(
+        NavigateToURL(shell(), urls[0], urls[2] /* expected_commit_url */));
 
     // We reached the end of the redirect chain.
     EXPECT_EQ(urls[2], shell()->web_contents()->GetURL());
@@ -425,7 +426,7 @@
         "\" />"
         "</body></html>";
     AddQuery(&page_with_image, "html", content_with_image);
-    NavigateToURL(shell(), page_with_image);
+    EXPECT_TRUE(NavigateToURL(shell(), page_with_image));
 
     delegate()->VerifyAndClearExpectations();
   }
@@ -438,7 +439,7 @@
   AddQuery(&url, "header", kClearCookiesHeader);
   ASSERT_FALSE(url.SchemeIsCryptographic());
 
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
 
   // We do not expect any calls to have been made.
   delegate()->VerifyAndClearExpectations();
@@ -493,10 +494,10 @@
   AddQuery(&secure_page, "html", content_with_insecure_image);
 
   // Insecure resource on an insecure page does not execute Clear-Site-Data.
-  NavigateToURL(shell(), insecure_page);
+  EXPECT_TRUE(NavigateToURL(shell(), insecure_page));
 
   // Insecure resource on a secure page does not execute Clear-Site-Data.
-  NavigateToURL(shell(), secure_page);
+  EXPECT_TRUE(NavigateToURL(shell(), secure_page));
 
   // We do not expect any calls to have been made.
   delegate()->VerifyAndClearExpectations();
@@ -511,13 +512,13 @@
   // Secure resource on an insecure page does execute Clear-Site-Data.
   delegate()->ExpectClearSiteDataCookiesCall(url::Origin::Create(secure_image));
 
-  NavigateToURL(shell(), secure_page);
+  EXPECT_TRUE(NavigateToURL(shell(), secure_page));
   delegate()->VerifyAndClearExpectations();
 
   // Secure resource on a secure page does execute Clear-Site-Data.
   delegate()->ExpectClearSiteDataCookiesCall(url::Origin::Create(secure_image));
 
-  NavigateToURL(shell(), secure_page);
+  EXPECT_TRUE(NavigateToURL(shell(), secure_page));
   delegate()->VerifyAndClearExpectations();
 }
 
@@ -534,7 +535,7 @@
   // the page title.
   GURL url = origin1;
   AddQuery(&url, "file", "worker_setup.html");
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
   WaitForTitle(shell(), "service worker is ready");
 
   // The service worker will now serve a page containing several images, which
@@ -567,7 +568,7 @@
   AddQuery(&url, "origin2", origin2.spec());
   AddQuery(&url, "origin3", origin3.spec());
   AddQuery(&url, "origin4", origin4.spec());
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
   WaitForTitle(shell(), "done");
   delegate()->VerifyAndClearExpectations();
 }
@@ -632,7 +633,7 @@
     if (test_case.should_run)
       delegate()->ExpectClearSiteDataCookiesCall(url::Origin::Create(resource));
 
-    NavigateToURL(shell(), page);
+    EXPECT_TRUE(NavigateToURL(shell(), page));
     WaitForTitle(shell(), "done");
     delegate()->VerifyAndClearExpectations();
   }
@@ -675,7 +676,7 @@
   GURL page = https_server()->GetURL("origin1.com", "/");
   AddQuery(&page, "html", content);
 
-  NavigateToURL(shell(), page);
+  EXPECT_TRUE(NavigateToURL(shell(), page));
   WaitForTitle(shell(), "done");
   delegate()->VerifyAndClearExpectations();
 }
@@ -707,7 +708,7 @@
         url::Origin::Create(url), test_case.remove_cookies,
         test_case.remove_storage, test_case.remove_cache);
 
-    NavigateToURL(shell(), url);
+    EXPECT_TRUE(NavigateToURL(shell(), url));
 
     delegate()->VerifyAndClearExpectations();
   }
@@ -728,7 +729,7 @@
   // Let Clear-Site-Data delete the "cookies" of "origin1.com".
   GURL url = https_server()->GetURL("origin1.com", "/clear-site-data");
   AddQuery(&url, "header", kClearCookiesHeader);
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
 
   // Only the "origin2.com" eTLD now has cookies.
   cookies = GetCookies();
@@ -759,7 +760,7 @@
   // of the scope.
   GURL url = server->GetURL("origin1.com", "/anything-in-the-scope");
   AddQuery(&url, "header", "\"storage\"");
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
   service_workers =
       browsing_data_browsertest_utils::GetServiceWorkers(partition);
   EXPECT_EQ(2u, service_workers.size());
@@ -770,7 +771,7 @@
   // The header will be respected and the worker deleted.
   url = server->GetURL("origin1.com", "/resource");
   AddQuery(&url, "header", "\"storage\"");
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
 
   // Only "origin2.com" now has a service worker.
   service_workers =
@@ -810,7 +811,7 @@
   // Let Clear-Site-Data delete the "cache" of HTTPS host 2.
   GURL url = GetURLForHTTPSHost2("/clear-site-data");
   AddQuery(&url, "header", "\"cache\"");
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
 
   // Only HTTPS host 1 now has cache entries.
   EXPECT_TRUE(TestCacheEntry(url1));
@@ -834,7 +835,7 @@
                        ClearSiteDataDuringServiceWorkerInstall) {
   GURL url = embedded_test_server()->GetURL("127.0.0.1", "/");
   AddQuery(&url, "file", "worker_test.html");
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
   delegate()->ExpectClearSiteDataCall(url::Origin::Create(url), false, true,
                                       false);
   SetClearSiteDataHeader("\"storage\"");
@@ -849,7 +850,7 @@
                        ClearSiteDataDuringServiceWorkerUpdate) {
   GURL url = embedded_test_server()->GetURL("127.0.0.1", "/");
   AddQuery(&url, "file", "worker_test.html");
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
   // Install a service worker.
   EXPECT_TRUE(RunScriptAndGetBool("installServiceWorker()"));
   delegate()->VerifyAndClearExpectations();
diff --git a/content/browser/child_process_security_policy_browsertest.cc b/content/browser/child_process_security_policy_browsertest.cc
index 810e975..93f0f92 100644
--- a/content/browser/child_process_security_policy_browsertest.cc
+++ b/content/browser/child_process_security_policy_browsertest.cc
@@ -50,7 +50,7 @@
   GURL url = GetTestUrl("", "simple_page.html");
   auto* policy = ChildProcessSecurityPolicyImpl::GetInstance();
 
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
   {
     base::AutoLock lock(policy->lock_);
     EXPECT_EQ(RenderProcessHostImpl::IsSpareProcessKeptAtAllTimes() ? 2u : 1u,
diff --git a/content/browser/database_browsertest.cc b/content/browser/database_browsertest.cc
index 688dc19..c29c1e8e 100644
--- a/content/browser/database_browsertest.cc
+++ b/content/browser/database_browsertest.cc
@@ -31,7 +31,7 @@
   }
 
   void Navigate(Shell* shell) {
-    NavigateToURL(shell, GetTestUrl("", "simple_database.html"));
+    EXPECT_TRUE(NavigateToURL(shell, GetTestUrl("", "simple_database.html")));
   }
 
   void CreateTable(Shell* shell) {
diff --git a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
index ba450b5..15a5fd0d 100644
--- a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
+++ b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
@@ -2408,9 +2408,9 @@
 
   // Allow the first request to finish.
   std::unique_ptr<DownloadTestObserver> observer2(CreateWaiter(shell(), 1));
-  NavigateToURL(shell(),
-                embedded_test_server()->GetURL(
-                    content::SlowDownloadHttpResponse::kFinishDownloadUrl));
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL(
+                   content::SlowDownloadHttpResponse::kFinishDownloadUrl)));
   observer2->WaitForFinished();  // Wait for the third request.
   EXPECT_EQ(
       1u, observer2->NumDownloadsSeenInState(download::DownloadItem::COMPLETE));
diff --git a/content/browser/devtools/site_per_process_devtools_browsertest.cc b/content/browser/devtools/site_per_process_devtools_browsertest.cc
index c40de12..353f2e16 100644
--- a/content/browser/devtools/site_per_process_devtools_browsertest.cc
+++ b/content/browser/devtools/site_per_process_devtools_browsertest.cc
@@ -69,7 +69,7 @@
                        MAYBE_CrossSiteIframeAgentHost) {
   DevToolsAgentHost::List list;
   GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
-  NavigateToURL(shell(), main_url);
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
 
   // It is safe to obtain the root frame tree node here, as it doesn't change.
   FrameTreeNode* root =
@@ -140,7 +140,7 @@
 
 IN_PROC_BROWSER_TEST_F(SitePerProcessDevToolsBrowserTest, AgentHostForFrames) {
   GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
-  NavigateToURL(shell(), main_url);
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
 
   scoped_refptr<DevToolsAgentHost> page_agent =
       DevToolsAgentHost::GetOrCreateFor(shell()->web_contents());
@@ -179,7 +179,7 @@
 IN_PROC_BROWSER_TEST_F(SitePerProcessDevToolsBrowserTest,
     AgentHostForPageEqualsOneForMainFrame) {
   GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
-  NavigateToURL(shell(), main_url);
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
 
   // It is safe to obtain the root frame tree node here, as it doesn't change.
   FrameTreeNode* root =
diff --git a/content/browser/do_not_track_browsertest.cc b/content/browser/do_not_track_browsertest.cc
index 4177c35c..1372c63f 100644
--- a/content/browser/do_not_track_browsertest.cc
+++ b/content/browser/do_not_track_browsertest.cc
@@ -150,7 +150,7 @@
     return;
   // We don't check the result NavigateToURL as it returns true only if the
   // final URL is equal to the passed URL.
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url, final_url /* expected_commit_url */));
   ExpectPageTextEq("1");
 }
 
@@ -175,8 +175,8 @@
   ASSERT_TRUE(embedded_test_server()->Start());
   if (!EnableDoNotTrack())
     return;
-  NavigateToURL(shell(),
-                GetURL("/workers/create_worker.html?worker_url=/capture"));
+  EXPECT_TRUE(NavigateToURL(
+      shell(), GetURL("/workers/create_worker.html?worker_url=/capture")));
   loop.Run();
 
   EXPECT_TRUE(header_map.find("DNT") != header_map.end());
@@ -206,9 +206,9 @@
   ASSERT_TRUE(embedded_test_server()->Start());
   if (!EnableDoNotTrack())
     return;
-  NavigateToURL(
+  EXPECT_TRUE(NavigateToURL(
       shell(),
-      GetURL("/workers/create_shared_worker.html?worker_url=/capture"));
+      GetURL("/workers/create_shared_worker.html?worker_url=/capture")));
   loop.Run();
 
   EXPECT_TRUE(header_map.find("DNT") != header_map.end());
@@ -231,7 +231,8 @@
   ASSERT_TRUE(embedded_test_server()->Start());
   if (!EnableDoNotTrack())
     return;
-  NavigateToURL(shell(), GetURL("/service_worker/create_service_worker.html"));
+  EXPECT_TRUE(NavigateToURL(
+      shell(), GetURL("/service_worker/create_service_worker.html")));
 
   EXPECT_EQ("DONE", EvalJs(shell(), "register('/capture');"));
   loop.Run();
@@ -260,7 +261,8 @@
 
   // Register a service worker, trigger update, then wait until the handler sees
   // the second request.
-  NavigateToURL(shell(), GetURL("/service_worker/create_service_worker.html"));
+  EXPECT_TRUE(NavigateToURL(
+      shell(), GetURL("/service_worker/create_service_worker.html")));
   EXPECT_EQ("DONE", EvalJs(shell(), "register('/capture');"));
   EXPECT_EQ("DONE", EvalJs(shell(), "update();"));
   loop.Run();
@@ -279,7 +281,8 @@
   ASSERT_TRUE(embedded_test_server()->Start());
   if (!EnableDoNotTrack())
     return;
-  NavigateToURL(shell(), GetURL("/workers/fetch_from_worker.html"));
+  EXPECT_TRUE(
+      NavigateToURL(shell(), GetURL("/workers/fetch_from_worker.html")));
   EXPECT_EQ("1", EvalJs(shell(), "fetch_from_worker('/echoheader?DNT');"));
 }
 
@@ -296,7 +299,8 @@
   ASSERT_TRUE(embedded_test_server()->Start());
   if (!EnableDoNotTrack())
     return;
-  NavigateToURL(shell(), GetURL("/workers/fetch_from_shared_worker.html"));
+  EXPECT_TRUE(
+      NavigateToURL(shell(), GetURL("/workers/fetch_from_shared_worker.html")));
 
   EXPECT_EQ("1",
             EvalJs(shell(), "fetch_from_shared_worker('/echoheader?DNT');"));
@@ -307,8 +311,8 @@
   ASSERT_TRUE(embedded_test_server()->Start());
   if (!EnableDoNotTrack())
     return;
-  NavigateToURL(shell(),
-                GetURL("/service_worker/fetch_from_service_worker.html"));
+  EXPECT_TRUE(NavigateToURL(
+      shell(), GetURL("/service_worker/fetch_from_service_worker.html")));
 
   EXPECT_EQ("ready", EvalJs(shell(), "setup();"));
   EXPECT_EQ("1",
diff --git a/content/browser/fileapi/fileapi_browsertest.cc b/content/browser/fileapi/fileapi_browsertest.cc
index 43faade..25d5e5c 100644
--- a/content/browser/fileapi/fileapi_browsertest.cc
+++ b/content/browser/fileapi/fileapi_browsertest.cc
@@ -23,7 +23,7 @@
   EXPECT_TRUE(base::PathService::Get(base::DIR_TEMP, &file));
   file = file.AppendASCII("bar");
 
-  NavigateToURL(shell(), GetTestUrl(".", "file_input.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), GetTestUrl(".", "file_input.html")));
 
   // Click on the <input type=file> element to launch the file upload picker.
   {
diff --git a/content/browser/find_request_manager_browsertest.cc b/content/browser/find_request_manager_browsertest.cc
index b8f22c30..a0190132 100644
--- a/content/browser/find_request_manager_browsertest.cc
+++ b/content/browser/find_request_manager_browsertest.cc
@@ -60,7 +60,8 @@
   // Navigates to |url| and waits for it to finish loading.
   void LoadAndWait(const std::string& url) {
     TestNavigationObserver navigation_observer(contents());
-    NavigateToURL(shell(), embedded_test_server()->GetURL("a.com", url));
+    EXPECT_TRUE(
+        NavigateToURL(shell(), embedded_test_server()->GetURL("a.com", url)));
     ASSERT_TRUE(navigation_observer.last_navigation_succeeded());
   }
 
@@ -429,7 +430,7 @@
 // matches.
 IN_PROC_BROWSER_TEST_F(FindRequestManagerTest, MAYBE(AddFrameAfterNoMatches)) {
   TestNavigationObserver navigation_observer(contents());
-  NavigateToURL(shell(), GURL("about:blank"));
+  EXPECT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
   EXPECT_TRUE(navigation_observer.last_navigation_succeeded());
 
   auto default_options = blink::mojom::FindOptions::New();
@@ -622,7 +623,7 @@
 
 IN_PROC_BROWSER_TEST_F(FindRequestManagerTest, MAYBE(FindInPage_Issue644448)) {
   TestNavigationObserver navigation_observer(contents());
-  NavigateToURL(shell(), GURL("about:blank"));
+  EXPECT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
   EXPECT_TRUE(navigation_observer.last_navigation_succeeded());
 
   auto default_options = blink::mojom::FindOptions::New();
diff --git a/content/browser/font_unique_name_lookup/font_unique_name_browsertest.cc b/content/browser/font_unique_name_lookup/font_unique_name_browsertest.cc
index 18e63dfa..4433a860 100644
--- a/content/browser/font_unique_name_lookup/font_unique_name_browsertest.cc
+++ b/content/browser/font_unique_name_lookup/font_unique_name_browsertest.cc
@@ -150,7 +150,8 @@
     ASSERT_TRUE(embedded_test_server()->Start());
     TestNavigationObserver navigation_observer(
         static_cast<WebContentsImpl*>(shell()->web_contents()));
-    NavigateToURL(shell(), embedded_test_server()->GetURL("a.com", url));
+    EXPECT_TRUE(
+        NavigateToURL(shell(), embedded_test_server()->GetURL("a.com", url)));
     ASSERT_TRUE(navigation_observer.last_navigation_succeeded());
   }
 
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 520fe5a..2c9374b 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -1083,6 +1083,9 @@
   void CreateWebBluetoothService(
       mojo::PendingReceiver<blink::mojom::WebBluetoothService> receiver);
 
+  void GetPushMessaging(
+      mojo::PendingReceiver<blink::mojom::PushMessaging> receiver);
+
   // https://mikewest.github.io/corpp/#initialize-embedder-policy-for-global
   network::mojom::CrossOriginEmbedderPolicy cross_origin_embedder_policy()
       const {
@@ -1597,8 +1600,6 @@
       mojo::PendingReceiver<blink::mojom::CredentialManager> receiver) override;
   void GetAuthenticator(
       mojo::PendingReceiver<blink::mojom::Authenticator> receiver) override;
-  void GetPushMessaging(
-      mojo::PendingReceiver<blink::mojom::PushMessaging> receiver) override;
   void GetVirtualAuthenticatorManager(
       mojo::PendingReceiver<blink::test::mojom::VirtualAuthenticatorManager>
           receiver) override;
diff --git a/content/browser/frame_host/render_frame_message_filter_browsertest.cc b/content/browser/frame_host/render_frame_message_filter_browsertest.cc
index b06c83b..b48ff007 100644
--- a/content/browser/frame_host/render_frame_message_filter_browsertest.cc
+++ b/content/browser/frame_host/render_frame_message_filter_browsertest.cc
@@ -252,9 +252,9 @@
   std::string a_hostname = "localhost";
   std::string b_hostname = "127.0.0.1";
   GURL url = a_server.GetURL(a_hostname, cookies_to_set);
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
   url = b_server.GetURL(b_hostname, cookies_to_set);
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
   // TODO(crbug.com/984685): Make it less painful to set up https cross-site
   // iframe tests.
   std::string a_hostname_and_port =
diff --git a/content/browser/hid/hid_browsertest.cc b/content/browser/hid/hid_browsertest.cc
index 2196794..4988d61ab 100644
--- a/content/browser/hid/hid_browsertest.cc
+++ b/content/browser/hid/hid_browsertest.cc
@@ -65,7 +65,7 @@
 }  // namespace
 
 IN_PROC_BROWSER_TEST_F(HidTest, GetDevices) {
-  NavigateToURL(shell(), GetTestUrl(nullptr, "simple_page.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), GetTestUrl(nullptr, "simple_page.html")));
 
   // Three devices are added but only two will have permission granted.
   for (int i = 0; i < 3; i++) {
@@ -86,7 +86,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(HidTest, RequestDevice) {
-  NavigateToURL(shell(), GetTestUrl(nullptr, "simple_page.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), GetTestUrl(nullptr, "simple_page.html")));
 
   EXPECT_CALL(delegate(), CanRequestDevicePermission(_, _))
       .WillOnce(Return(true));
@@ -104,7 +104,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(HidTest, DisallowRequestDevice) {
-  NavigateToURL(shell(), GetTestUrl(nullptr, "simple_page.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), GetTestUrl(nullptr, "simple_page.html")));
 
   EXPECT_CALL(delegate(), CanRequestDevicePermission(_, _))
       .WillOnce(Return(false));
diff --git a/content/browser/idle/idle_browsertest.cc b/content/browser/idle/idle_browsertest.cc
index d4ede6c2..31c351d9 100644
--- a/content/browser/idle/idle_browsertest.cc
+++ b/content/browser/idle/idle_browsertest.cc
@@ -45,7 +45,7 @@
 }  // namespace
 
 IN_PROC_BROWSER_TEST_F(IdleTest, Start) {
-  NavigateToURL(shell(), GetTestUrl(nullptr, "simple_page.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), GetTestUrl(nullptr, "simple_page.html")));
 
   auto mock_time_provider = std::make_unique<NiceMock<MockIdleTimeProvider>>();
   auto* rph = static_cast<RenderProcessHostImpl*>(
diff --git a/content/browser/indexed_db/indexed_db_browsertest.cc b/content/browser/indexed_db/indexed_db_browsertest.cc
index 460ec5d..ec085e9 100644
--- a/content/browser/indexed_db/indexed_db_browsertest.cc
+++ b/content/browser/indexed_db/indexed_db_browsertest.cc
@@ -133,7 +133,7 @@
 
     base::string16 expected_title16(ASCIIToUTF16(expected_string));
     TitleWatcher title_watcher(shell->web_contents(), expected_title16);
-    NavigateToURL(shell, url);
+    EXPECT_TRUE(NavigateToURL(shell, url));
     EXPECT_EQ(expected_title16, title_watcher.WaitAndGetTitle());
   }
 
@@ -1021,7 +1021,7 @@
 
   // Start on a different URL to force a new renderer process.
   Shell* new_shell = CreateBrowser();
-  NavigateToURL(new_shell, GURL(url::kAboutBlankURL));
+  EXPECT_TRUE(NavigateToURL(new_shell, GURL(url::kAboutBlankURL)));
   NavigateAndWaitForTitle(new_shell, "version_change_blocked.html", "#tab2",
                           "setVersion(3) blocked");
 
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index 6d0d316..a3a266e 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -1059,7 +1059,7 @@
                       if (host) {
                         host->SetControllerRegistration(
                             nullptr, false /* notify_controllerchange */);
-                        host->UpdateUrls(GURL(), GURL());
+                        host->UpdateUrls(GURL(), GURL(), base::nullopt);
                       }
                     },
                     // Unretained() is safe because the handle owns the core,
diff --git a/content/browser/media/session/media_session_impl_browsertest.cc b/content/browser/media/session/media_session_impl_browsertest.cc
index df1c6e8..ce1c367 100644
--- a/content/browser/media/session/media_session_impl_browsertest.cc
+++ b/content/browser/media/session/media_session_impl_browsertest.cc
@@ -2712,8 +2712,9 @@
 #endif
 IN_PROC_BROWSER_TEST_F(MediaSessionImplBrowserTest,
                        MAYBE_PositionStateRouteWithOnePlayer) {
-  NavigateToURL(shell(), embedded_test_server()->GetURL(
-                             "example.com", "/media/session/position.html"));
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("example.com",
+                                              "/media/session/position.html")));
 
   auto* main_frame = shell()->web_contents()->GetMainFrame();
   const base::TimeDelta duration = base::TimeDelta::FromMilliseconds(6060);
diff --git a/content/browser/navigation_browsertest.cc b/content/browser/navigation_browsertest.cc
index 5f9b3be..025b88712 100644
--- a/content/browser/navigation_browsertest.cc
+++ b/content/browser/navigation_browsertest.cc
@@ -354,7 +354,7 @@
   {
     TestNavigationObserver observer(shell()->web_contents());
     GURL url(embedded_test_server()->GetURL("/title1.html"));
-    NavigateToURL(shell(), url);
+    EXPECT_TRUE(NavigateToURL(shell(), url));
     EXPECT_EQ(url, observer.last_navigation_url());
     EXPECT_TRUE(observer.last_navigation_succeeded());
     EXPECT_FALSE(observer.last_initiator_origin().has_value());
@@ -370,7 +370,7 @@
   {
     TestNavigationObserver observer(shell()->web_contents());
     GURL url(embedded_test_server()->GetURL("/title2.html"));
-    NavigateToURL(shell(), url);
+    EXPECT_TRUE(NavigateToURL(shell(), url));
     EXPECT_EQ(url, observer.last_navigation_url());
     EXPECT_TRUE(observer.last_navigation_succeeded());
     EXPECT_FALSE(observer.last_initiator_origin().has_value());
@@ -386,7 +386,7 @@
   {
     TestNavigationObserver observer(shell()->web_contents());
     GURL url = embedded_test_server()->GetURL("foo.com", "/title3.html");
-    NavigateToURL(shell(), url);
+    EXPECT_TRUE(NavigateToURL(shell(), url));
     EXPECT_EQ(url, observer.last_navigation_url());
     EXPECT_TRUE(observer.last_navigation_succeeded());
     EXPECT_FALSE(observer.last_initiator_origin().has_value());
@@ -406,7 +406,7 @@
   {
     TestNavigationObserver observer(shell()->web_contents());
     GURL url(embedded_test_server()->GetURL("/simple_links.html"));
-    NavigateToURL(shell(), url);
+    EXPECT_TRUE(NavigateToURL(shell(), url));
     EXPECT_EQ(url, observer.last_navigation_url());
     EXPECT_TRUE(observer.last_navigation_succeeded());
     EXPECT_FALSE(observer.last_initiator_origin().has_value());
@@ -448,7 +448,7 @@
   {
     TestNavigationObserver observer(shell()->web_contents());
     GURL url(embedded_test_server()->GetURL("/simple_links.html"));
-    NavigateToURL(shell(), url);
+    EXPECT_TRUE(NavigateToURL(shell(), url));
     EXPECT_EQ(url, observer.last_navigation_url());
     EXPECT_TRUE(observer.last_navigation_succeeded());
   }
@@ -506,7 +506,7 @@
   {
     TestNavigationObserver observer(shell()->web_contents());
     GURL url(embedded_test_server()->GetURL("/title1.html"));
-    NavigateToURL(shell(), url);
+    EXPECT_TRUE(NavigateToURL(shell(), url));
     EXPECT_EQ(url, observer.last_navigation_url());
     EXPECT_TRUE(observer.last_navigation_succeeded());
   }
@@ -517,7 +517,7 @@
     GURL error_url(embedded_test_server()->GetURL("/close-socket"));
     base::PostTask(FROM_HERE, {BrowserThread::IO},
                    base::BindOnce(&net::URLRequestFailedJob::AddUrlHandler));
-    NavigateToURL(shell(), error_url);
+    EXPECT_FALSE(NavigateToURL(shell(), error_url));
     EXPECT_EQ(error_url, observer.last_navigation_url());
     NavigationEntry* entry =
         shell()->web_contents()->GetController().GetLastCommittedEntry();
@@ -532,7 +532,7 @@
   GURL url(embedded_test_server()->GetURL("/title1.html"));
   GURL view_source_url(content::kViewSourceScheme + std::string(":") +
                        url.spec());
-  NavigateToURL(shell(), view_source_url);
+  EXPECT_TRUE(NavigateToURL(shell(), view_source_url));
   EXPECT_EQ(url, observer.last_navigation_url());
   EXPECT_TRUE(observer.last_navigation_succeeded());
 }
@@ -542,7 +542,7 @@
                        ViewSourceNavigation_RendererInitiated) {
   TestNavigationObserver observer(shell()->web_contents());
   GURL kUrl(embedded_test_server()->GetURL("/simple_links.html"));
-  NavigateToURL(shell(), kUrl);
+  EXPECT_TRUE(NavigateToURL(shell(), kUrl));
   EXPECT_EQ(kUrl, observer.last_navigation_url());
   EXPECT_TRUE(observer.last_navigation_succeeded());
 
@@ -572,7 +572,7 @@
                        GoogleChromeNavigation_RendererInitiated) {
   TestNavigationObserver observer(shell()->web_contents());
   GURL kUrl(embedded_test_server()->GetURL("/simple_links.html"));
-  NavigateToURL(shell(), kUrl);
+  EXPECT_TRUE(NavigateToURL(shell(), kUrl));
   EXPECT_EQ(kUrl, observer.last_navigation_url());
   EXPECT_TRUE(observer.last_navigation_succeeded());
 
@@ -898,8 +898,8 @@
   // First, make two history entries.
   GURL url1(embedded_test_server()->GetURL("/title1.html"));
   GURL url2(embedded_test_server()->GetURL("/title2.html"));
-  NavigateToURL(shell(), url1);
-  NavigateToURL(shell(), url2);
+  EXPECT_TRUE(NavigateToURL(shell(), url1));
+  EXPECT_TRUE(NavigateToURL(shell(), url2));
 
   // Then execute a back navigation in Javascript followed by a reload.
   TestNavigationObserver navigation_observer(shell()->web_contents());
@@ -1084,7 +1084,7 @@
   url::Origin starting_page_origin;
   starting_page_origin = starting_page_origin.Create(starting_page);
 
-  NavigateToURL(shell(), starting_page);
+  EXPECT_TRUE(NavigateToURL(shell(), starting_page));
 
   GURL url(embedded_test_server()->GetURL("/title2.html"));
 
@@ -1101,7 +1101,7 @@
 // navigated by Javascript from some starting page to another page.
 IN_PROC_BROWSER_TEST_P(NavigationBrowserTest, SubFrameJsNavigationInitiator) {
   GURL starting_page(embedded_test_server()->GetURL("/frame_tree/top.html"));
-  NavigateToURL(shell(), starting_page);
+  EXPECT_TRUE(NavigateToURL(shell(), starting_page));
 
   // It is safe to obtain the root frame tree node here, as it doesn't change.
   FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
@@ -1142,7 +1142,7 @@
   // Go to a page on a.com with an iframe that is on b.com
   GURL starting_page(embedded_test_server()->GetURL(
       "a.com", "/cross_site_iframe_factory.html?a(b)"));
-  NavigateToURL(shell(), starting_page);
+  EXPECT_TRUE(NavigateToURL(shell(), starting_page));
 
   // It is safe to obtain the root frame tree node here, as it doesn't change.
   FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
@@ -1254,7 +1254,7 @@
   EXPECT_TRUE(embedded_test_server()->Start());
 
   GURL url(embedded_test_server()->GetURL("/title1.html"));
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
 
   DOMMessageQueue dom_message_queue(WebContents::FromRenderFrameHost(
       shell()->web_contents()->GetMainFrame()));
@@ -1729,7 +1729,8 @@
               ->GetBrowserContext()
               ->GetDownloadManagerDelegate());
   delegate->SetDownloadBehaviorForTesting(download_dir.GetPath());
-  NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
+  EXPECT_TRUE(
+      NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
   WebContents* opener = shell()->web_contents();
 
   // Open a popup.
@@ -1771,8 +1772,8 @@
               ->GetBrowserContext()
               ->GetDownloadManagerDelegate());
   delegate->SetDownloadBehaviorForTesting(download_dir.GetPath());
-  NavigateToURL(shell(),
-                embedded_test_server()->GetURL("a.com", "/title1.html"));
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
   WebContents* opener = shell()->web_contents();
 
   // Open a popup.
@@ -1814,7 +1815,7 @@
   ASSERT_TRUE(embedded_test_server()->Start());
 
   GURL url(embedded_test_server()->GetURL("/title1.html"));
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
 
   // Block every iframe in WillProcessResponse.
   content::TestNavigationThrottleInserter throttle_inserter(
@@ -2141,7 +2142,7 @@
 // browser process. It means RenderFrameHostImpl::BeginNavigation() is called.
 IN_PROC_BROWSER_TEST_P(NavigationBrowserTest, AboutSrcDocUsesBeginNavigation) {
   GURL url(embedded_test_server()->GetURL("/title1.html"));
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
 
   // If DidStartNavigation is called before DidCommitProvisionalLoad, then it
   // means the navigation was driven by the browser process, otherwise by the
diff --git a/content/browser/net/accept_header_browsertest.cc b/content/browser/net/accept_header_browsertest.cc
index c4ab85a..3d67c7b5 100644
--- a/content/browser/net/accept_header_browsertest.cc
+++ b/content/browser/net/accept_header_browsertest.cc
@@ -91,7 +91,8 @@
 };
 
 IN_PROC_BROWSER_TEST_F(AcceptHeaderTest, Check) {
-  NavigateToURL(shell(), embedded_test_server()->GetURL("/accept-header.html"));
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("/accept-header.html")));
 
   // ResourceType::kMainFrame
   EXPECT_EQ(
diff --git a/content/browser/net_info_browsertest.cc b/content/browser/net_info_browsertest.cc
index 64bb6f4b..1674d61 100644
--- a/content/browser/net_info_browsertest.cc
+++ b/content/browser/net_info_browsertest.cc
@@ -177,7 +177,7 @@
   net::NetworkChangeNotifier::DisableForTest disable_for_test;
   MockNetworkChangeNotifierWifi mock_notifier;
 
-  NavigateToURL(shell(), content::GetTestUrl("", "net_info.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), content::GetTestUrl("", "net_info.html")));
   EXPECT_TRUE(RunScriptExtractBool("getOnLine()"));
   EXPECT_EQ("wifi", RunScriptExtractString("getType()"));
   EXPECT_EQ(net::NetworkChangeNotifier::GetMaxBandwidthMbpsForConnectionSubtype(
@@ -188,7 +188,7 @@
 // Make sure that type changes in the browser make their way to
 // navigator.connection.type.
 IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest, NetworkChangePlumbsToNavigator) {
-  NavigateToURL(shell(), content::GetTestUrl("", "net_info.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), content::GetTestUrl("", "net_info.html")));
   SetConnectionType(net::NetworkChangeNotifier::CONNECTION_WIFI,
                     net::NetworkChangeNotifier::SUBTYPE_WIFI_N);
   EXPECT_EQ("wifi", RunScriptExtractString("getType()"));
@@ -207,7 +207,7 @@
 // Make sure that type changes in the browser make their way to
 // navigator.isOnline.
 IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest, IsOnline) {
-  NavigateToURL(shell(), content::GetTestUrl("", "net_info.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), content::GetTestUrl("", "net_info.html")));
   SetConnectionType(net::NetworkChangeNotifier::CONNECTION_ETHERNET,
                     net::NetworkChangeNotifier::SUBTYPE_GIGABIT_ETHERNET);
   EXPECT_TRUE(RunScriptExtractBool("getOnLine()"));
@@ -224,7 +224,7 @@
 IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest, TwoRenderViewsInOneProcess) {
   SetConnectionType(net::NetworkChangeNotifier::CONNECTION_ETHERNET,
                     net::NetworkChangeNotifier::SUBTYPE_GIGABIT_ETHERNET);
-  NavigateToURL(shell(), content::GetTestUrl("", "net_info.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), content::GetTestUrl("", "net_info.html")));
   EXPECT_TRUE(RunScriptExtractBool("getOnLine()"));
 
   SetConnectionType(net::NetworkChangeNotifier::CONNECTION_NONE,
diff --git a/content/browser/origin_trials/origin_trials_browsertest.cc b/content/browser/origin_trials/origin_trials_browsertest.cc
index df382c0d..c618de3 100644
--- a/content/browser/origin_trials/origin_trials_browsertest.cc
+++ b/content/browser/origin_trials/origin_trials_browsertest.cc
@@ -71,7 +71,7 @@
 };
 
 IN_PROC_BROWSER_TEST_F(OriginTrialsBrowserTest, Basic) {
-  NavigateToURL(shell(), GURL("https://example.test/basic.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), GURL("https://example.test/basic.html")));
   // Ensure we can invoke normalMethod(), which is only available when the
   // Frobulate OT is enabled.
   EXPECT_TRUE(content::ExecJs(shell()->web_contents()->GetMainFrame(),
@@ -80,7 +80,7 @@
 
 IN_PROC_BROWSER_TEST_F(OriginTrialsBrowserTest,
                        NonNavigationTrialNotActivatedAcrossNavigations) {
-  NavigateToURL(shell(), GURL("https://example.test/basic.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), GURL("https://example.test/basic.html")));
   EXPECT_TRUE(content::ExecJs(shell()->web_contents()->GetMainFrame(),
                               "internals.originTrialsTest().normalMethod();"));
   NavigateViaRenderer(shell()->web_contents(),
@@ -92,7 +92,8 @@
 }
 
 IN_PROC_BROWSER_TEST_F(OriginTrialsBrowserTest, Navigation) {
-  NavigateToURL(shell(), GURL("https://example.test/navigation.html"));
+  EXPECT_TRUE(
+      NavigateToURL(shell(), GURL("https://example.test/navigation.html")));
   // Ensure we can invoke navigationMethod(), which is only available when the
   // FrobulateNavigation OT is enabled.
   EXPECT_TRUE(
@@ -102,7 +103,8 @@
 
 IN_PROC_BROWSER_TEST_F(OriginTrialsBrowserTest,
                        NavigationTrialActivatedAcrossNavigations) {
-  NavigateToURL(shell(), GURL("https://example.test/navigation.html"));
+  EXPECT_TRUE(
+      NavigateToURL(shell(), GURL("https://example.test/navigation.html")));
   EXPECT_TRUE(
       content::ExecJs(shell()->web_contents()->GetMainFrame(),
                       "internals.originTrialsTest().navigationMethod();"));
diff --git a/content/browser/renderer_host/accessibility_tree_linkage_win_browsertest.cc b/content/browser/renderer_host/accessibility_tree_linkage_win_browsertest.cc
index 6800517..bdfa4f9 100644
--- a/content/browser/renderer_host/accessibility_tree_linkage_win_browsertest.cc
+++ b/content/browser/renderer_host/accessibility_tree_linkage_win_browsertest.cc
@@ -67,7 +67,7 @@
 };
 
 IN_PROC_BROWSER_TEST_P(AccessibilityTreeLinkageWinBrowserTest, Linkage) {
-  NavigateToURL(shell(), GURL(url::kAboutBlankURL));
+  EXPECT_TRUE(NavigateToURL(shell(), GURL(url::kAboutBlankURL)));
 
   GetParentWindow()->SetProperty(
       aura::client::kParentNativeViewAccessibleKey,
diff --git a/content/browser/renderer_host/direct_manipulation_win_browsertest.cc b/content/browser/renderer_host/direct_manipulation_win_browsertest.cc
index 1f10e20..5382995c 100644
--- a/content/browser/renderer_host/direct_manipulation_win_browsertest.cc
+++ b/content/browser/renderer_host/direct_manipulation_win_browsertest.cc
@@ -85,7 +85,7 @@
   if (base::win::GetVersion() < base::win::Version::WIN10)
     return;
 
-  NavigateToURL(shell(), GURL(url::kAboutBlankURL));
+  EXPECT_TRUE(NavigateToURL(shell(), GURL(url::kAboutBlankURL)));
 
   LegacyRenderWidgetHostHWND* lrwhh = GetLegacyRenderWidgetHostHWND();
   ASSERT_TRUE(lrwhh);
@@ -137,7 +137,7 @@
   if (base::win::GetVersion() < base::win::Version::WIN10)
     return;
 
-  NavigateToURL(shell(), GURL(url::kAboutBlankURL));
+  EXPECT_TRUE(NavigateToURL(shell(), GURL(url::kAboutBlankURL)));
 
   LegacyRenderWidgetHostHWND* lrwhh = GetLegacyRenderWidgetHostHWND();
   ASSERT_TRUE(lrwhh);
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_browsertest.cc b/content/browser/renderer_host/render_widget_host_view_aura_browsertest.cc
index c2fec194..2c044cc0 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura_browsertest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura_browsertest.cc
@@ -80,7 +80,7 @@
 #if defined(OS_CHROMEOS)
 IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewAuraBrowserTest,
                        StaleFrameContentOnEvictionNormal) {
-  NavigateToURL(shell(), GURL(kMinimalPageDataURL));
+  EXPECT_TRUE(NavigateToURL(shell(), GURL(kMinimalPageDataURL)));
 
   // Make sure the renderer submits at least one frame before hiding it.
   RenderFrameSubmissionObserver submission_observer(shell()->web_contents());
@@ -121,7 +121,7 @@
 
 IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewAuraBrowserTest,
                        StaleFrameContentOnEvictionRejected) {
-  NavigateToURL(shell(), GURL(kMinimalPageDataURL));
+  EXPECT_TRUE(NavigateToURL(shell(), GURL(kMinimalPageDataURL)));
 
   // Wait for first frame activation when a surface is embedded.
   while (!GetDelegatedFrameHost()->HasSavedFrame())
@@ -161,7 +161,7 @@
 
 IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewAuraBrowserTest,
                        StaleFrameContentOnEvictionNone) {
-  NavigateToURL(shell(), GURL(kMinimalPageDataURL));
+  EXPECT_TRUE(NavigateToURL(shell(), GURL(kMinimalPageDataURL)));
 
   // Wait for first frame activation when a surface is embedded.
   while (!GetDelegatedFrameHost()->HasSavedFrame())
diff --git a/content/browser/scheduler/browser_io_thread_delegate.cc b/content/browser/scheduler/browser_io_thread_delegate.cc
index cb4233c..8959a52 100644
--- a/content/browser/scheduler/browser_io_thread_delegate.cc
+++ b/content/browser/scheduler/browser_io_thread_delegate.cc
@@ -8,6 +8,8 @@
 #include "base/message_loop/message_pump_type.h"
 #include "base/task/sequence_manager/sequence_manager.h"
 #include "base/task/sequence_manager/task_queue.h"
+#include "base/task/task_executor.h"
+#include "content/browser/scheduler/browser_task_executor.h"
 #include "content/public/browser/browser_thread.h"
 
 namespace content {
@@ -16,17 +18,20 @@
 using ::base::sequence_manager::SequenceManager;
 using ::base::sequence_manager::TaskQueue;
 
-BrowserIOThreadDelegate::BrowserIOThreadDelegate()
+BrowserIOThreadDelegate::BrowserIOThreadDelegate(
+    BrowserTaskExecutorPresent browser_task_executor_present)
     : sequence_manager_(CreateUnboundSequenceManager(
           SequenceManager::Settings::Builder()
               .SetMessagePumpType(base::MessagePumpType::IO)
-              .Build())) {
+              .Build())),
+      browser_task_executor_present_(browser_task_executor_present) {
   Init(sequence_manager_.get());
 }
 
 BrowserIOThreadDelegate::BrowserIOThreadDelegate(
     SequenceManager* sequence_manager)
-    : sequence_manager_(nullptr) {
+    : sequence_manager_(nullptr),
+      browser_task_executor_present_(BrowserTaskExecutorPresent::kYes) {
   Init(sequence_manager);
 }
 
@@ -43,7 +48,11 @@
   return default_task_runner_;
 }
 
-BrowserIOThreadDelegate::~BrowserIOThreadDelegate() = default;
+BrowserIOThreadDelegate::~BrowserIOThreadDelegate() {
+  if (browser_task_executor_present_ == BrowserTaskExecutorPresent::kYes) {
+    base::SetTaskExecutorForCurrentThread(nullptr);
+  }
+}
 
 void BrowserIOThreadDelegate::BindToCurrentThread(
     base::TimerSlack timer_slack) {
@@ -52,6 +61,10 @@
       base::MessagePump::Create(base::MessagePumpType::IO));
   sequence_manager_->SetTimerSlack(timer_slack);
   sequence_manager_->SetDefaultTaskRunner(GetDefaultTaskRunner());
+
+  if (browser_task_executor_present_ == BrowserTaskExecutorPresent::kYes) {
+    base::SetTaskExecutorForCurrentThread(BrowserTaskExecutor::Get());
+  }
 }
 
 }  // namespace content
diff --git a/content/browser/scheduler/browser_io_thread_delegate.h b/content/browser/scheduler/browser_io_thread_delegate.h
index 49c337d..703e7c5 100644
--- a/content/browser/scheduler/browser_io_thread_delegate.h
+++ b/content/browser/scheduler/browser_io_thread_delegate.h
@@ -28,12 +28,20 @@
  public:
   using Handle = BrowserTaskQueues::Handle;
 
+  // Normally, creating a BrowserIOThreadDelegate relies on a
+  // BrowserTaskExecutor already existing to register it as the executor for the
+  // current (IO) thread. However, some tests create it in isolation, so we need
+  // to disable registering the executor to pass checks.
+  enum class BrowserTaskExecutorPresent { kYes, kNoForTesting };
+
   static std::unique_ptr<BrowserIOThreadDelegate> CreateForTesting(
       base::sequence_manager::SequenceManager* sequence_manager) {
     return base::WrapUnique(new BrowserIOThreadDelegate(sequence_manager));
   }
 
-  BrowserIOThreadDelegate();
+  explicit BrowserIOThreadDelegate(
+      BrowserTaskExecutorPresent browser_task_executor_present =
+          BrowserTaskExecutorPresent::kYes);
   ~BrowserIOThreadDelegate() override;
 
   scoped_refptr<base::SingleThreadTaskRunner> GetDefaultTaskRunner() override;
@@ -47,6 +55,10 @@
   // tests.
   void SetAllowBlockingForTesting() { allow_blocking_for_testing_ = true; }
 
+  bool browser_task_executor_present() const {
+    return browser_task_executor_present_ == BrowserTaskExecutorPresent::kYes;
+  }
+
   scoped_refptr<Handle> CreateHandle() { return task_queues_->GetHandle(); }
 
  private:
@@ -64,6 +76,8 @@
 
   std::unique_ptr<BrowserTaskQueues> task_queues_;
   scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_;
+
+  const BrowserTaskExecutorPresent browser_task_executor_present_;
 };
 
 }  // namespace content
diff --git a/content/browser/scheduler/browser_io_thread_delegate_unittest.cc b/content/browser/scheduler/browser_io_thread_delegate_unittest.cc
index 2be9c02..f7378f0 100644
--- a/content/browser/scheduler/browser_io_thread_delegate_unittest.cc
+++ b/content/browser/scheduler/browser_io_thread_delegate_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread.h"
+#include "content/browser/scheduler/browser_task_executor.h"
 #include "content/browser/scheduler/browser_task_queues.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -19,7 +20,8 @@
 TEST(BrowserIOThreadDelegateTest, CanPostTasksToThread) {
   base::Thread thread("my_thread");
 
-  auto delegate = std::make_unique<BrowserIOThreadDelegate>();
+  auto delegate = std::make_unique<BrowserIOThreadDelegate>(
+      BrowserIOThreadDelegate::BrowserTaskExecutorPresent::kNoForTesting);
   auto handle = delegate->CreateHandle();
   handle->EnableAllQueues();
 
@@ -36,10 +38,11 @@
   event.Wait();
 }
 
-TEST(BrowserIOThreadDelegateTest, DefaultTaskRunnerIsAllwaysActive) {
+TEST(BrowserIOThreadDelegateTest, DefaultTaskRunnerIsAlwaysActive) {
   base::Thread thread("my_thread");
 
-  auto delegate = std::make_unique<BrowserIOThreadDelegate>();
+  auto delegate = std::make_unique<BrowserIOThreadDelegate>(
+      BrowserIOThreadDelegate::BrowserTaskExecutorPresent::kNoForTesting);
   auto task_runner = delegate->GetDefaultTaskRunner();
 
   base::Thread::Options options;
diff --git a/content/browser/scheduler/browser_task_executor.cc b/content/browser/scheduler/browser_task_executor.cc
index f2ddb98..37ba248 100644
--- a/content/browser/scheduler/browser_task_executor.cc
+++ b/content/browser/scheduler/browser_task_executor.cc
@@ -74,7 +74,9 @@
       browser_io_thread_delegate_(std::move(browser_io_thread_delegate)),
       browser_io_thread_handle_(browser_io_thread_delegate_->CreateHandle()) {}
 
-BrowserTaskExecutor::~BrowserTaskExecutor() = default;
+BrowserTaskExecutor::~BrowserTaskExecutor() {
+  base::SetTaskExecutorForCurrentThread(nullptr);
+}
 
 // static
 void BrowserTaskExecutor::Create() {
@@ -104,23 +106,35 @@
   g_browser_task_executor->browser_ui_thread_handle_
       ->EnableAllExceptBestEffortQueues();
 
+  // Here we register the BrowserTaskExecutor for the UI thread; registration
+  // for the IO thread happens in BrowserIOThreadDelegate::BindToCurrentThread.
+  base::SetTaskExecutorForCurrentThread(g_browser_task_executor);
+
 #if defined(OS_ANDROID)
   base::PostTaskAndroid::SignalNativeSchedulerReady();
 #endif
 }
 
 // static
+BrowserTaskExecutor* BrowserTaskExecutor::Get() {
+  DCHECK(g_browser_task_executor);
+  return g_browser_task_executor;
+}
+
+// static
 void BrowserTaskExecutor::ResetForTesting() {
 #if defined(OS_ANDROID)
   base::PostTaskAndroid::SignalNativeSchedulerShutdown();
 #endif
-
   if (g_browser_task_executor) {
+    RunAllPendingTasksOnThreadForTesting(BrowserThread::UI);
+    RunAllPendingTasksOnThreadForTesting(BrowserThread::IO);
     base::UnregisterTaskExecutorForTesting(
         BrowserTaskTraitsExtension::kExtensionId);
     delete g_browser_task_executor;
     g_browser_task_executor = nullptr;
   }
+  base::SetTaskExecutorForCurrentThread(nullptr);
 }
 
 // static
@@ -164,6 +178,12 @@
           ->ScheduleRunAllPendingTasksForTesting(run_loop.QuitClosure());
       break;
     case BrowserThread::IO: {
+      // In tests there may not be a functional IO thread.
+      if (!g_browser_task_executor->browser_io_thread_delegate_ ||
+          !g_browser_task_executor->browser_io_thread_delegate_
+               ->browser_task_executor_present()) {
+        return;
+      }
       g_browser_task_executor->browser_io_thread_handle_
           ->ScheduleRunAllPendingTasksForTesting(run_loop.QuitClosure());
       break;
diff --git a/content/browser/scheduler/browser_task_executor.h b/content/browser/scheduler/browser_task_executor.h
index c873e97..720d6d7 100644
--- a/content/browser/scheduler/browser_task_executor.h
+++ b/content/browser/scheduler/browser_task_executor.h
@@ -148,6 +148,7 @@
 #endif  // DCHECK_IS_ON()
 
  private:
+  friend class BrowserIOThreadDelegate;
   friend class BrowserTaskExecutorTest;
 
   static void CreateInternal(
@@ -162,6 +163,10 @@
   FRIEND_TEST_ALL_PREFIXES(BrowserTaskExecutorTest,
                            BestEffortTasksRunAfterStartup);
 
+  // For Get();
+  FRIEND_TEST_ALL_PREFIXES(BrowserTaskExecutorTest,
+                           RegisterExecutorForBothThreads);
+
   explicit BrowserTaskExecutor(
       std::unique_ptr<BrowserUIThreadScheduler> browser_ui_thread_scheduler,
       std::unique_ptr<BrowserIOThreadDelegate> browser_io_thread_delegate);
@@ -170,6 +175,8 @@
   scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner(
       const base::TaskTraits& traits) const;
 
+  static BrowserTaskExecutor* Get();
+
   std::unique_ptr<BrowserUIThreadScheduler> browser_ui_thread_scheduler_;
   scoped_refptr<BrowserUIThreadScheduler::Handle> browser_ui_thread_handle_;
 
diff --git a/content/browser/scheduler/browser_task_executor_unittest.cc b/content/browser/scheduler/browser_task_executor_unittest.cc
index 3bae309..7d3701b 100644
--- a/content/browser/scheduler/browser_task_executor_unittest.cc
+++ b/content/browser/scheduler/browser_task_executor_unittest.cc
@@ -47,6 +47,21 @@
 using StrictMockTask =
     testing::StrictMock<base::MockCallback<base::RepeatingCallback<void()>>>;
 
+TEST_F(BrowserTaskExecutorTest, RegisterExecutorForBothThreads) {
+  base::PostTask(FROM_HERE, {BrowserThread::UI}, base::BindOnce([]() {
+                   EXPECT_EQ(BrowserTaskExecutor::Get(),
+                             base::GetTaskExecutorForCurrentThread());
+                 }));
+
+  base::PostTask(FROM_HERE, {BrowserThread::IO}, base::BindOnce([]() {
+                   EXPECT_EQ(BrowserTaskExecutor::Get(),
+                             base::GetTaskExecutorForCurrentThread());
+                 }));
+
+  BrowserTaskExecutor::RunAllPendingTasksOnThreadForTesting(BrowserThread::UI);
+  BrowserTaskExecutor::RunAllPendingTasksOnThreadForTesting(BrowserThread::IO);
+}
+
 TEST_F(BrowserTaskExecutorTest, RunAllPendingTasksForTestingOnUI) {
   StrictMockTask task_1;
   StrictMockTask task_2;
@@ -179,7 +194,9 @@
               QueueType::kDefault));
       BrowserTaskExecutor::CreateForTesting(
           std::move(browser_ui_thread_scheduler),
-          std::make_unique<BrowserIOThreadDelegate>());
+          std::make_unique<BrowserIOThreadDelegate>(
+              BrowserIOThreadDelegate::BrowserTaskExecutorPresent::
+                  kNoForTesting));
     }
   };
 
diff --git a/content/browser/serial/serial_browsertest.cc b/content/browser/serial/serial_browsertest.cc
index e59042d..d574c64 100644
--- a/content/browser/serial/serial_browsertest.cc
+++ b/content/browser/serial/serial_browsertest.cc
@@ -64,7 +64,7 @@
 }  // namespace
 
 IN_PROC_BROWSER_TEST_F(SerialTest, GetPorts) {
-  NavigateToURL(shell(), GetTestUrl(nullptr, "simple_page.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), GetTestUrl(nullptr, "simple_page.html")));
 
   // Three ports are added but only two will have permission granted.
   for (size_t i = 0; i < 3; i++) {
@@ -84,7 +84,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(SerialTest, RequestPort) {
-  NavigateToURL(shell(), GetTestUrl(nullptr, "simple_page.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), GetTestUrl(nullptr, "simple_page.html")));
 
   EXPECT_CALL(delegate(), CanRequestPortPermission).WillOnce(Return(true));
 
@@ -101,7 +101,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(SerialTest, DisallowRequestPort) {
-  NavigateToURL(shell(), GetTestUrl(nullptr, "simple_page.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), GetTestUrl(nullptr, "simple_page.html")));
 
   EXPECT_CALL(delegate(), CanRequestPortPermission(_)).WillOnce(Return(false));
   EXPECT_CALL(delegate(), RunChooserInternal).Times(Exactly(0));
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc
index ad45cb1..40a44c2 100644
--- a/content/browser/service_worker/service_worker_browsertest.cc
+++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -747,7 +747,7 @@
         33 /* dummy render process id */, true /* is_parent_frame_secure */,
         wrapper()->context()->AsWeakPtr(), &remote_endpoints_.back());
     const GURL url = embedded_test_server()->GetURL("/service_worker/host");
-    host->UpdateUrls(url, url);
+    host->UpdateUrls(url, url, url::Origin::Create(url));
     host->SetControllerRegistration(registration_,
                                     false /* notify_controllerchange */);
   }
diff --git a/content/browser/service_worker/service_worker_context_unittest.cc b/content/browser/service_worker/service_worker_context_unittest.cc
index 091f793..f8fb56e 100644
--- a/content/browser/service_worker/service_worker_context_unittest.cc
+++ b/content/browser/service_worker/service_worker_context_unittest.cc
@@ -944,21 +944,21 @@
   base::WeakPtr<ServiceWorkerProviderHost> host1 = CreateProviderHostForWindow(
       kRenderProcessId1, true /* is_parent_frame_secure */,
       context()->AsWeakPtr(), &remote_endpoints.back());
-  host1->UpdateUrls(kOrigin1, kOrigin1);
+  host1->UpdateUrls(kOrigin1, kOrigin1, url::Origin::Create(kOrigin1));
 
   // Host2 : process_id=2, origin2.
   remote_endpoints.emplace_back();
   base::WeakPtr<ServiceWorkerProviderHost> host2 = CreateProviderHostForWindow(
       kRenderProcessId2, true /* is_parent_frame_secure */,
       context()->AsWeakPtr(), &remote_endpoints.back());
-  host2->UpdateUrls(kOrigin2, kOrigin2);
+  host2->UpdateUrls(kOrigin2, kOrigin2, url::Origin::Create(kOrigin2));
 
   // Host3 : process_id=2, origin1.
   remote_endpoints.emplace_back();
   base::WeakPtr<ServiceWorkerProviderHost> host3 = CreateProviderHostForWindow(
       kRenderProcessId2, true /* is_parent_frame_secure */,
       context()->AsWeakPtr(), &remote_endpoints.back());
-  host3->UpdateUrls(kOrigin1, kOrigin1);
+  host3->UpdateUrls(kOrigin1, kOrigin1, url::Origin::Create(kOrigin1));
 
   // Host4 : process_id=2, origin2, for ServiceWorker.
   blink::mojom::ServiceWorkerRegistrationOptions registration_opt;
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler.cc b/content/browser/service_worker/service_worker_controllee_request_handler.cc
index 4407c0d..8c152e3c 100644
--- a/content/browser/service_worker/service_worker_controllee_request_handler.cc
+++ b/content/browser/service_worker/service_worker_controllee_request_handler.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/optional.h"
 #include "base/trace_event/trace_event.h"
 #include "components/offline_pages/buildflags/buildflags.h"
 #include "content/browser/loader/navigation_url_loader_impl.h"
@@ -213,8 +214,12 @@
   provider_host_->SetControllerRegistration(nullptr,
                                             /*notify_controllerchange=*/false);
   stripped_url_ = net::SimplifyUrlForRequest(tentative_resource_request.url);
-  provider_host_->UpdateUrls(stripped_url_,
-                             tentative_resource_request.site_for_cookies);
+  provider_host_->UpdateUrls(
+      stripped_url_, tentative_resource_request.site_for_cookies,
+      tentative_resource_request.trusted_params
+          ? tentative_resource_request.trusted_params->network_isolation_key
+                .GetTopFrameOrigin()
+          : base::nullopt);
   return true;
 }
 
@@ -257,12 +262,14 @@
   if (ServiceWorkerContext::IsServiceWorkerOnUIEnabled()) {
     allow_service_worker =
         GetContentClient()->browser()->AllowServiceWorkerOnUI(
-            registration->scope(), provider_host_->site_for_cookies(), GURL(),
+            registration->scope(), provider_host_->site_for_cookies(),
+            provider_host_->top_frame_origin(), /*script_url=*/GURL(),
             browser_context_, provider_host_->web_contents_getter());
   } else {
     allow_service_worker =
         GetContentClient()->browser()->AllowServiceWorkerOnIO(
-            registration->scope(), provider_host_->site_for_cookies(), GURL(),
+            registration->scope(), provider_host_->site_for_cookies(),
+            provider_host_->top_frame_origin(), /*script_url=*/GURL(),
             resource_context_, provider_host_->web_contents_getter());
   }
 
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc b/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
index b9bcfa6..40566cd 100644
--- a/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
+++ b/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
@@ -154,7 +154,8 @@
   ServiceWorkerTestContentBrowserClient() {}
   bool AllowServiceWorkerOnIO(
       const GURL& scope,
-      const GURL& first_party,
+      const GURL& site_for_cookies,
+      const base::Optional<url::Origin>& top_frame_origin,
       const GURL& script_url,
       content::ResourceContext* context,
       base::RepeatingCallback<WebContents*()> wc_getter) override {
@@ -163,7 +164,8 @@
 
   bool AllowServiceWorkerOnUI(
       const GURL& scope,
-      const GURL& first_party,
+      const GURL& site_for_cookies,
+      const base::Optional<url::Origin>& top_frame_origin,
       const GURL& script_url,
       content::BrowserContext* context,
       base::RepeatingCallback<WebContents*()> wc_getter) override {
diff --git a/content/browser/service_worker/service_worker_job_unittest.cc b/content/browser/service_worker/service_worker_job_unittest.cc
index 06eb349..1a7d60c 100644
--- a/content/browser/service_worker/service_worker_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_job_unittest.cc
@@ -1005,7 +1005,7 @@
 
   // Make an in-scope client.
   ServiceWorkerProviderHost* client = CreateControllee();
-  client->UpdateUrls(in_scope, in_scope);
+  client->UpdateUrls(in_scope, in_scope, url::Origin::Create(in_scope));
 
   // Make an in-scope reserved client.
   std::unique_ptr<ServiceWorkerProviderHostAndInfo> host_and_info =
@@ -1013,11 +1013,13 @@
                                          /*are_ancestors_secure=*/true);
   base::WeakPtr<ServiceWorkerProviderHost> reserved_client =
       std::move(host_and_info->host);
-  reserved_client->UpdateUrls(in_scope, in_scope);
+  reserved_client->UpdateUrls(in_scope, in_scope,
+                              url::Origin::Create(in_scope));
 
   // Make an out-scope client.
   ServiceWorkerProviderHost* out_scope_client = CreateControllee();
-  out_scope_client->UpdateUrls(out_scope, out_scope);
+  out_scope_client->UpdateUrls(out_scope, out_scope,
+                               url::Origin::Create(out_scope));
 
   // Make a new registration.
   GURL script("https://www.example.com/service_worker.js");
diff --git a/content/browser/service_worker/service_worker_navigation_loader_unittest.cc b/content/browser/service_worker/service_worker_navigation_loader_unittest.cc
index c64d936..561ae54d 100644
--- a/content/browser/service_worker/service_worker_navigation_loader_unittest.cc
+++ b/content/browser/service_worker/service_worker_navigation_loader_unittest.cc
@@ -393,7 +393,8 @@
       provider_host_ = CreateProviderHostForWindow(
           helper_->mock_render_process_id(), /*is_parent_frame_secure=*/true,
           helper_->context()->AsWeakPtr(), &provider_endpoints_);
-      provider_host_->UpdateUrls(request->url, request->url);
+      provider_host_->UpdateUrls(request->url, request->url,
+                                 url::Origin::Create(request->url));
       provider_host_->AddMatchingRegistration(registration_.get());
       provider_host_->SetControllerRegistration(
           registration_, /*notify_controllerchange=*/false);
@@ -516,7 +517,8 @@
       helper_->mock_render_process_id(), /*is_parent_frame_secure=*/true,
       helper_->context()->AsWeakPtr(), &provider_endpoints_);
   provider_host_->UpdateUrls(GURL("https://example.com/"),
-                             GURL("https://example.com/"));
+                             GURL("https://example.com/"),
+                             url::Origin::Create(GURL("https://example.com/")));
 
   // Perform the request.
   StartRequest(CreateRequest());
diff --git a/content/browser/service_worker/service_worker_object_host_unittest.cc b/content/browser/service_worker/service_worker_object_host_unittest.cc
index de01a6a..c1651e1 100644
--- a/content/browser/service_worker/service_worker_object_host_unittest.cc
+++ b/content/browser/service_worker/service_worker_object_host_unittest.cc
@@ -219,7 +219,7 @@
       CreateProviderHostForWindow(
           helper_->mock_render_process_id(), true /* is_parent_frame_secure */,
           helper_->context()->AsWeakPtr(), &remote_endpoint);
-  provider_host->UpdateUrls(scope, scope);
+  provider_host->UpdateUrls(scope, scope, url::Origin::Create(scope));
   blink::mojom::ServiceWorkerRegistrationObjectInfoPtr registration_info =
       GetRegistrationFromRemote(remote_endpoint.host_remote()->get(), scope);
   // |version_| is the installing version of |registration_| now.
@@ -332,7 +332,7 @@
           frame_host->GetProcess()->GetID(), true /* is_parent_frame_secure */,
           helper_->context()->AsWeakPtr(), &remote_endpoint);
   SetProviderHostRenderFrameId(provider_host.get(), frame_host->GetRoutingID());
-  provider_host->UpdateUrls(scope, scope);
+  provider_host->UpdateUrls(scope, scope, url::Origin::Create(scope));
 
   // Prepare a ServiceWorkerObjectHost for the worker.
   blink::mojom::ServiceWorkerObjectInfoPtr info =
diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc
index 0de4c111..234e700 100644
--- a/content/browser/service_worker/service_worker_provider_host.cc
+++ b/content/browser/service_worker/service_worker_provider_host.cc
@@ -403,8 +403,10 @@
   return remote_controller;
 }
 
-void ServiceWorkerProviderHost::UpdateUrls(const GURL& url,
-                                           const GURL& site_for_cookies) {
+void ServiceWorkerProviderHost::UpdateUrls(
+    const GURL& url,
+    const GURL& site_for_cookies,
+    const base::Optional<url::Origin>& top_frame_origin) {
   DCHECK(IsProviderForClient());
   DCHECK(!url.has_ref());
   DCHECK(!controller());
@@ -412,6 +414,8 @@
   GURL previous_url = url_;
   url_ = url;
   site_for_cookies_ = site_for_cookies;
+  top_frame_origin_ = top_frame_origin;
+
   if (previous_url != url) {
     // Revoke the token on URL change since any service worker holding the token
     // may no longer be the potential controller of this frame and shouldn't
@@ -465,6 +469,13 @@
   return running_hosted_version_->script_url();
 }
 
+base::Optional<url::Origin> ServiceWorkerProviderHost::top_frame_origin()
+    const {
+  if (IsProviderForClient())
+    return top_frame_origin_;
+  return url::Origin::Create(running_hosted_version_->script_url());
+}
+
 void ServiceWorkerProviderHost::UpdateController(bool notify_controllerchange) {
   ServiceWorkerVersion* version =
       controller_registration_ ? controller_registration_->active_version()
@@ -599,13 +610,13 @@
   DCHECK(IsContextAlive());
   if (ServiceWorkerContext::IsServiceWorkerOnUIEnabled()) {
     return GetContentClient()->browser()->AllowServiceWorkerOnUI(
-        scope, site_for_cookies(), script_url,
+        scope, site_for_cookies(), top_frame_origin(), script_url,
         context_->wrapper()->browser_context(),
         base::BindRepeating(&WebContentsImpl::FromRenderFrameHostID,
                             render_process_id_, frame_id()));
   } else {
     return GetContentClient()->browser()->AllowServiceWorkerOnIO(
-        scope, site_for_cookies(), script_url,
+        scope, site_for_cookies(), top_frame_origin(), script_url,
         context_->wrapper()->resource_context(),
         base::BindRepeating(&WebContentsImpl::FromRenderFrameHostID,
                             render_process_id_, frame_id()));
diff --git a/content/browser/service_worker/service_worker_provider_host.h b/content/browser/service_worker/service_worker_provider_host.h
index b5c40976..df3f161 100644
--- a/content/browser/service_worker/service_worker_provider_host.h
+++ b/content/browser/service_worker/service_worker_provider_host.h
@@ -42,6 +42,7 @@
 #include "third_party/blink/public/mojom/service_worker/service_worker_provider_type.mojom.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
 #include "third_party/blink/public/mojom/web_feature/web_feature.mojom.h"
+#include "url/origin.h"
 
 namespace service_worker_object_host_unittest {
 class ServiceWorkerObjectHostTest;
@@ -244,9 +245,12 @@
   mojo::Remote<blink::mojom::ControllerServiceWorker>
   GetRemoteControllerServiceWorker();
 
-  // For service worker clients. Sets |url_| and |site_for_cookies_| and updates
-  // the client uuid if it's a cross-origin transition.
-  void UpdateUrls(const GURL& url, const GURL& site_for_cookies);
+  // For service worker clients. Sets |url_|, |site_for_cookies_| and
+  // |top_frame_origin_| and updates the client uuid if it's a cross-origin
+  // transition.
+  void UpdateUrls(const GURL& url,
+                  const GURL& site_for_cookies,
+                  const base::Optional<url::Origin>& top_frame_origin);
 
   // The URL of this context. For service worker clients, this is the document
   // URL (for documents) or script URL (for workers). For service worker
@@ -261,12 +265,20 @@
   // is_response_committed() is true, the URL should no longer change.
   const GURL& url() const;
 
-  // The URL representing the first-party site for this context. See
-  // |network::ResourceRequest::site_for_cookies| for details.
+  // The URL representing the site_for_cookies for this context. See
+  // |URLRequest::site_for_cookies()| for details.
   // For service worker execution contexts, site_for_cookies() always
   // returns the service worker script URL.
   const GURL& site_for_cookies() const;
 
+  // The URL representing the first-party site for this context.
+  // For service worker execution contexts, top_frame_origin() always
+  // returns the origin of the service worker script URL.
+  // For shared worker it is the origin of the document that created the worker.
+  // For dedicated worker it is the top-frame origin of the document that owns
+  // the worker.
+  base::Optional<url::Origin> top_frame_origin() const;
+
   blink::mojom::ServiceWorkerProviderType provider_type() const {
     return type_;
   }
@@ -637,6 +649,7 @@
   // For service worker clients. See comments for the getter functions.
   GURL url_;
   GURL site_for_cookies_;
+  base::Optional<url::Origin> top_frame_origin_;
 
   // Keyed by registration scope URL length.
   using ServiceWorkerRegistrationMap =
diff --git a/content/browser/service_worker/service_worker_provider_host_unittest.cc b/content/browser/service_worker/service_worker_provider_host_unittest.cc
index b80f4e1..84dea27 100644
--- a/content/browser/service_worker/service_worker_provider_host_unittest.cc
+++ b/content/browser/service_worker/service_worker_provider_host_unittest.cc
@@ -50,12 +50,18 @@
 class ServiceWorkerTestContentBrowserClient : public TestContentBrowserClient {
  public:
   struct AllowServiceWorkerCallLog {
-    AllowServiceWorkerCallLog(const GURL& scope,
-                              const GURL& first_party,
-                              const GURL& script_url)
-        : scope(scope), first_party(first_party), script_url(script_url) {}
+    AllowServiceWorkerCallLog(
+        const GURL& scope,
+        const GURL& site_for_cookies,
+        const base::Optional<url::Origin>& top_frame_origin,
+        const GURL& script_url)
+        : scope(scope),
+          site_for_cookies(site_for_cookies),
+          top_frame_origin(top_frame_origin),
+          script_url(script_url) {}
     const GURL scope;
-    const GURL first_party;
+    const GURL site_for_cookies;
+    const base::Optional<url::Origin> top_frame_origin;
     const GURL script_url;
   };
 
@@ -63,21 +69,23 @@
 
   bool AllowServiceWorkerOnIO(
       const GURL& scope,
-      const GURL& first_party,
+      const GURL& site_for_cookies,
+      const base::Optional<url::Origin>& top_frame_origin,
       const GURL& script_url,
       content::ResourceContext* context,
       base::RepeatingCallback<WebContents*()> wc_getter) override {
-    logs_.emplace_back(scope, first_party, script_url);
+    logs_.emplace_back(scope, site_for_cookies, top_frame_origin, script_url);
     return false;
   }
 
   bool AllowServiceWorkerOnUI(
       const GURL& scope,
-      const GURL& first_party,
+      const GURL& site_for_cookies,
+      const base::Optional<url::Origin>& top_frame_origin,
       const GURL& script_url,
       content::BrowserContext* context,
       base::RepeatingCallback<WebContents*()> wc_getter) override {
-    logs_.emplace_back(scope, first_party, script_url);
+    logs_.emplace_back(scope, site_for_cookies, top_frame_origin, script_url);
     return false;
   }
 
@@ -140,7 +148,8 @@
       const GURL& document_url) {
     ServiceWorkerRemoteProviderEndpoint remote_endpoint;
     GURL site_for_cookies = document_url;
-    CreateProviderHostInternal(document_url, site_for_cookies,
+    url::Origin top_frame_origin = url::Origin::Create(document_url);
+    CreateProviderHostInternal(document_url, site_for_cookies, top_frame_origin,
                                &remote_endpoint);
     return remote_endpoint;
   }
@@ -148,17 +157,20 @@
   ServiceWorkerRemoteProviderEndpoint
   PrepareServiceWorkerProviderHostWithSiteForCookies(
       const GURL& document_url,
-      const GURL& site_for_cookies) {
+      const GURL& site_for_cookies,
+      const base::Optional<url::Origin>& top_frame_origin) {
     ServiceWorkerRemoteProviderEndpoint remote_endpoint;
-    CreateProviderHostInternal(document_url, site_for_cookies,
+    CreateProviderHostInternal(document_url, site_for_cookies, top_frame_origin,
                                &remote_endpoint);
     return remote_endpoint;
   }
 
   ServiceWorkerProviderHost* CreateProviderHost(const GURL& document_url) {
     GURL site_for_cookies = document_url;
+    url::Origin top_frame_origin = url::Origin::Create(document_url);
     remote_endpoints_.emplace_back();
     return CreateProviderHostInternal(document_url, site_for_cookies,
+                                      top_frame_origin,
                                       &remote_endpoints_.back());
   }
 
@@ -169,14 +181,15 @@
         helper_->mock_render_process_id(), false /* is_parent_frame_secure */,
         helper_->context()->AsWeakPtr(), &remote_endpoints_.back());
     ServiceWorkerProviderHost* host_raw = host.get();
-    host->UpdateUrls(document_url, document_url);
+    host->UpdateUrls(document_url, document_url,
+                     url::Origin::Create(document_url));
     return host_raw;
   }
 
   void FinishNavigation(ServiceWorkerProviderHost* host) {
     // In production code, the loader/request handler does this.
     const GURL url("https://www.example.com/page");
-    host->UpdateUrls(url, url);
+    host->UpdateUrls(url, url, url::Origin::Create(url));
 
     // In production code this is called from NavigationRequest in the browser
     // process right before navigation commit.
@@ -298,11 +311,12 @@
   ServiceWorkerProviderHost* CreateProviderHostInternal(
       const GURL& document_url,
       const GURL& site_for_cookies,
+      const base::Optional<url::Origin>& top_frame_origin,
       ServiceWorkerRemoteProviderEndpoint* remote_endpoint) {
     base::WeakPtr<ServiceWorkerProviderHost> host = CreateProviderHostForWindow(
         helper_->mock_render_process_id(), true /* is_parent_frame_secure */,
         helper_->context()->AsWeakPtr(), remote_endpoint);
-    host->UpdateUrls(document_url, site_for_cookies);
+    host->UpdateUrls(document_url, site_for_cookies, top_frame_origin);
     return host.get();
   }
 
@@ -340,15 +354,19 @@
   ASSERT_EQ(nullptr, provider_host1->MatchRegistration());
 
   // SetDocumentUrl sets all of matching registrations
-  provider_host1->UpdateUrls(GURL("https://www.example.com/example1"),
-                             GURL("https://www.example.com/example1"));
+  provider_host1->UpdateUrls(
+      GURL("https://www.example.com/example1"),
+      GURL("https://www.example.com/example1"),
+      url::Origin::Create(GURL("https://www.example.com/example1")));
   ASSERT_EQ(registration2_, provider_host1->MatchRegistration());
   provider_host1->RemoveMatchingRegistration(registration2_.get());
   ASSERT_EQ(registration1_, provider_host1->MatchRegistration());
 
   // SetDocumentUrl with another origin also updates matching registrations
-  provider_host1->UpdateUrls(GURL("https://other.example.com/example"),
-                             GURL("https://other.example.com/example"));
+  provider_host1->UpdateUrls(
+      GURL("https://other.example.com/example"),
+      GURL("https://other.example.com/example"),
+      url::Origin::Create(GURL("https://other.example.com/example")));
   ASSERT_EQ(registration3_, provider_host1->MatchRegistration());
   provider_host1->RemoveMatchingRegistration(registration3_.get());
   ASSERT_EQ(nullptr, provider_host1->MatchRegistration());
@@ -362,31 +380,35 @@
           GURL("https://www.example.com/example1.html"));
 
   // Insecure document URL.
-  provider_host_secure_parent->UpdateUrls(GURL("http://host"),
-                                          GURL("http://host"));
+  provider_host_secure_parent->UpdateUrls(
+      GURL("http://host"), GURL("http://host"),
+      url::Origin::Create(GURL("http://host")));
   EXPECT_FALSE(provider_host_secure_parent->IsContextSecureForServiceWorker());
 
   // Insecure parent frame.
-  provider_host_insecure_parent->UpdateUrls(GURL("https://host"),
-                                            GURL("https://host"));
+  provider_host_insecure_parent->UpdateUrls(
+      GURL("https://host"), GURL("https://host"),
+      url::Origin::Create(GURL("https://host")));
   EXPECT_FALSE(
       provider_host_insecure_parent->IsContextSecureForServiceWorker());
 
   // Secure URL and parent frame.
-  provider_host_secure_parent->UpdateUrls(GURL("https://host"),
-                                          GURL("https://host"));
+  provider_host_secure_parent->UpdateUrls(
+      GURL("https://host"), GURL("https://host"),
+      url::Origin::Create(GURL("https://host")));
   EXPECT_TRUE(provider_host_secure_parent->IsContextSecureForServiceWorker());
 
   // Exceptional service worker scheme.
   GURL url(std::string(kServiceWorkerScheme) + "://host");
+  url::Origin origin = url::Origin::Create(url);
   EXPECT_TRUE(url.is_valid());
   EXPECT_FALSE(IsOriginSecure(url));
   EXPECT_TRUE(OriginCanAccessServiceWorkers(url));
-  provider_host_secure_parent->UpdateUrls(url, url);
+  provider_host_secure_parent->UpdateUrls(url, url, origin);
   EXPECT_TRUE(provider_host_secure_parent->IsContextSecureForServiceWorker());
 
   // Exceptional service worker scheme with insecure parent frame.
-  provider_host_insecure_parent->UpdateUrls(url, url);
+  provider_host_insecure_parent->UpdateUrls(url, url, origin);
   EXPECT_FALSE(
       provider_host_insecure_parent->IsContextSecureForServiceWorker());
 }
@@ -400,7 +422,7 @@
   EXPECT_EQ(url1, host->url());
   EXPECT_EQ(url1, host->site_for_cookies());
 
-  host->UpdateUrls(url2, url2);
+  host->UpdateUrls(url2, url2, url::Origin::Create(url2));
   EXPECT_EQ(url2, host->url());
   EXPECT_EQ(url2, host->site_for_cookies());
   EXPECT_EQ(uuid1, host->client_uuid());
@@ -417,7 +439,7 @@
   EXPECT_EQ(url1, host->url());
   EXPECT_EQ(url1, host->site_for_cookies());
 
-  host->UpdateUrls(url2, url2);
+  host->UpdateUrls(url2, url2, url::Origin::Create(url2));
   EXPECT_EQ(url2, host->url());
   EXPECT_EQ(url2, host->site_for_cookies());
   EXPECT_NE(uuid1, host->client_uuid());
@@ -572,7 +594,8 @@
   ServiceWorkerRemoteProviderEndpoint remote_endpoint =
       PrepareServiceWorkerProviderHostWithSiteForCookies(
           GURL("https://www.example.com/foo"),
-          GURL("https://www.example.com/top"));
+          GURL("https://www.example.com/top"),
+          url::Origin::Create(GURL("https://www.example.com")));
 
   EXPECT_EQ(blink::mojom::ServiceWorkerErrorType::kDisabled,
             Register(remote_endpoint.host_remote()->get(),
@@ -582,7 +605,9 @@
   EXPECT_EQ(GURL("https://www.example.com/scope"),
             test_browser_client.logs()[0].scope);
   EXPECT_EQ(GURL("https://www.example.com/top"),
-            test_browser_client.logs()[0].first_party);
+            test_browser_client.logs()[0].site_for_cookies);
+  EXPECT_EQ(url::Origin::Create(GURL("https://www.example.com")),
+            test_browser_client.logs()[0].top_frame_origin);
   EXPECT_EQ(GURL("https://www.example.com/bar"),
             test_browser_client.logs()[0].script_url);
 
@@ -593,7 +618,9 @@
   EXPECT_EQ(GURL("https://www.example.com/foo"),
             test_browser_client.logs()[1].scope);
   EXPECT_EQ(GURL("https://www.example.com/top"),
-            test_browser_client.logs()[1].first_party);
+            test_browser_client.logs()[1].site_for_cookies);
+  EXPECT_EQ(url::Origin::Create(GURL("https://www.example.com")),
+            test_browser_client.logs()[1].top_frame_origin);
   EXPECT_EQ(GURL(), test_browser_client.logs()[1].script_url);
 
   EXPECT_EQ(blink::mojom::ServiceWorkerErrorType::kDisabled,
@@ -602,7 +629,9 @@
   EXPECT_EQ(GURL("https://www.example.com/foo"),
             test_browser_client.logs()[2].scope);
   EXPECT_EQ(GURL("https://www.example.com/top"),
-            test_browser_client.logs()[2].first_party);
+            test_browser_client.logs()[2].site_for_cookies);
+  EXPECT_EQ(url::Origin::Create(GURL("https://www.example.com")),
+            *test_browser_client.logs()[2].top_frame_origin);
   EXPECT_EQ(GURL(), test_browser_client.logs()[2].script_url);
 
   SetBrowserClientForTesting(old_browser_client);
@@ -634,8 +663,9 @@
   EXPECT_EQ(GURL("https://www.example.com/scope"),
             test_browser_client.logs()[0].scope);
   EXPECT_EQ(GURL("https://www.example.com/sw.js"),
-            test_browser_client.logs()[0].first_party);
-
+            test_browser_client.logs()[0].site_for_cookies);
+  EXPECT_EQ(url::Origin::Create(GURL("https://www.example.com")),
+            test_browser_client.logs()[0].top_frame_origin);
   SetBrowserClientForTesting(old_browser_client);
 }
 
@@ -920,7 +950,7 @@
         ServiceWorkerProviderHost::PreCreateForWebWorker(
             context_->AsWeakPtr(), helper_->mock_render_process_id(),
             provider_type, std::move(host_receiver), std::move(client_remote));
-    host->UpdateUrls(url, url);
+    host->UpdateUrls(url, url, url::Origin::Create(url));
     EXPECT_FALSE(CanFindClientProviderHost(host.get()));
     host->CompleteWebWorkerPreparation();
     EXPECT_TRUE(CanFindClientProviderHost(host.get()));
@@ -1006,7 +1036,7 @@
   EXPECT_FALSE(host->is_response_committed());
   EXPECT_FALSE(host->is_execution_ready());
 
-  host->UpdateUrls(url, url);
+  host->UpdateUrls(url, url, url::Origin::Create(url));
   host->CompleteWebWorkerPreparation();
 
   EXPECT_TRUE(host->is_response_committed());
diff --git a/content/browser/service_worker/service_worker_registration_unittest.cc b/content/browser/service_worker/service_worker_registration_unittest.cc
index 28689f72..3faef02 100644
--- a/content/browser/service_worker/service_worker_registration_unittest.cc
+++ b/content/browser/service_worker/service_worker_registration_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/logging.h"
 #include "base/memory/weak_ptr.h"
+#include "base/optional.h"
 #include "base/run_loop.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/simple_test_tick_clock.h"
@@ -47,6 +48,7 @@
 #include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
 #include "url/gurl.h"
+#include "url/origin.h"
 
 namespace content {
 
@@ -74,7 +76,8 @@
  public:
   bool AllowServiceWorkerOnIO(
       const GURL& scope,
-      const GURL& first_party,
+      const GURL& site_for_cookies,
+      const base::Optional<url::Origin>& top_frame_origin,
       const GURL& script_url,
       content::ResourceContext* context,
       base::RepeatingCallback<WebContents*()> wc_getter) override {
@@ -83,7 +86,8 @@
 
   bool AllowServiceWorkerOnUI(
       const GURL& scope,
-      const GURL& first_party,
+      const GURL& site_for_cookies,
+      const base::Optional<url::Origin>& top_frame_origin,
       const GURL& script_url,
       content::BrowserContext* context,
       base::RepeatingCallback<WebContents*()> wc_getter) override {
@@ -422,7 +426,7 @@
         context()->AsWeakPtr(), &remote_endpoint_);
     DCHECK(remote_endpoint_.client_receiver()->is_valid());
     DCHECK(remote_endpoint_.host_remote()->is_bound());
-    host_->UpdateUrls(kUrl, kUrl);
+    host_->UpdateUrls(kUrl, kUrl, url::Origin::Create(kUrl));
     host_->SetControllerRegistration(registration_,
                                      false /* notify_controllerchange */);
 
@@ -924,7 +928,8 @@
     base::WeakPtr<ServiceWorkerProviderHost> host = CreateProviderHostForWindow(
         helper_->mock_render_process_id(), true /* is_parent_frame_secure */,
         context()->AsWeakPtr(), &remote_endpoint);
-    host->UpdateUrls(document_url, document_url);
+    host->UpdateUrls(document_url, document_url,
+                     url::Origin::Create(document_url));
     if (out_host)
       *out_host = host;
     return remote_endpoint;
@@ -1044,7 +1049,7 @@
 
   ASSERT_TRUE(bad_messages_.empty());
   GURL url("https://does.not.exist/");
-  provider_host->UpdateUrls(url, url);
+  provider_host->UpdateUrls(url, url, url::Origin::Create(url));
   CallUpdate(registration_host.get());
   EXPECT_EQ(1u, bad_messages_.size());
 }
@@ -1146,7 +1151,7 @@
   base::WeakPtr<ServiceWorkerProviderHost> host = CreateProviderHostForWindow(
       helper_->mock_render_process_id(), true /* is_parent_frame_secure */,
       context()->AsWeakPtr(), &remote_endpoint);
-  host->UpdateUrls(kScope, kScope);
+  host->UpdateUrls(kScope, kScope, url::Origin::Create(kScope));
   version->AddControllee(host.get());
 
   // Initially set |self_update_delay| to zero.
@@ -1210,8 +1215,9 @@
   registration_host.Bind(std::move(info->host_remote));
 
   ASSERT_TRUE(bad_messages_.empty());
-  provider_host->UpdateUrls(GURL("https://does.not.exist/"),
-                            GURL("https://does.not.exist/"));
+  provider_host->UpdateUrls(
+      GURL("https://does.not.exist/"), GURL("https://does.not.exist/"),
+      url::Origin::Create(GURL("https://does.not.exist/")));
   CallUnregister(registration_host.get());
   EXPECT_EQ(1u, bad_messages_.size());
 }
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index 09441e2..904729470 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -2060,15 +2060,15 @@
   // tab, pass a null callback as WebContents getter.
   if (ServiceWorkerContext::IsServiceWorkerOnUIEnabled()) {
     if (!GetContentClient()->browser()->AllowServiceWorkerOnUI(
-            scope_, scope_, script_url_, context_->wrapper()->browser_context(),
-            base::NullCallback())) {
+            scope_, scope_, url::Origin::Create(scope_), script_url_,
+            context_->wrapper()->browser_context(), base::NullCallback())) {
       return false;
     }
   } else {
     // resource_context() can return null in unit tests.
     if ((context_->wrapper()->resource_context() &&
          !GetContentClient()->browser()->AllowServiceWorkerOnIO(
-             scope_, scope_, script_url_,
+             scope_, scope_, url::Origin::Create(scope_), script_url_,
              context_->wrapper()->resource_context(), base::NullCallback()))) {
       return false;
     }
diff --git a/content/browser/service_worker/service_worker_version_unittest.cc b/content/browser/service_worker/service_worker_version_unittest.cc
index dda309d..ad160d5d6 100644
--- a/content/browser/service_worker/service_worker_version_unittest.cc
+++ b/content/browser/service_worker/service_worker_version_unittest.cc
@@ -220,7 +220,8 @@
     base::WeakPtr<ServiceWorkerProviderHost> host = CreateProviderHostForWindow(
         controllee_process_id, true /* is_parent_frame_secure */,
         helper_->context()->AsWeakPtr(), &remote_endpoint);
-    host->UpdateUrls(registration_->scope(), registration_->scope());
+    host->UpdateUrls(registration_->scope(), registration_->scope(),
+                     url::Origin::Create(registration_->scope()));
     host->SetControllerRegistration(registration_,
                                     false /* notify_controllerchange */);
     EXPECT_TRUE(version_->HasControllee());
@@ -469,7 +470,8 @@
   base::WeakPtr<ServiceWorkerProviderHost> host = CreateProviderHostForWindow(
       33 /* dummy render process id */, true /* is_parent_frame_secure */,
       helper_->context()->AsWeakPtr(), &remote_endpoint);
-  host->UpdateUrls(registration_->scope(), registration_->scope());
+  host->UpdateUrls(registration_->scope(), registration_->scope(),
+                   url::Origin::Create(registration_->scope()));
   host->SetControllerRegistration(registration_, false);
   EXPECT_TRUE(version_->HasControllee());
   EXPECT_TRUE(host->controller());
@@ -1235,7 +1237,8 @@
   base::WeakPtr<ServiceWorkerProviderHost> host =
       std::move(host_and_info->host);
   remote_endpoint.BindForWindow(std::move(host_and_info->info));
-  host->UpdateUrls(registration_->scope(), registration_->scope());
+  host->UpdateUrls(registration_->scope(), registration_->scope(),
+                   url::Origin::Create(registration_->scope()));
   host->SetControllerRegistration(registration_,
                                   false /* notify_controllerchange */);
   EXPECT_TRUE(version_->HasControllee());
diff --git a/content/browser/shape_detection/shape_detection_browsertest.cc b/content/browser/shape_detection/shape_detection_browsertest.cc
index 05693956..032cb464 100644
--- a/content/browser/shape_detection/shape_detection_browsertest.cc
+++ b/content/browser/shape_detection/shape_detection_browsertest.cc
@@ -64,7 +64,7 @@
     const GURL html_url(
         embedded_test_server()->GetURL(kShapeDetectionTestHtml));
     const GURL image_url(embedded_test_server()->GetURL(image_path));
-    NavigateToURL(shell(), html_url);
+    EXPECT_TRUE(NavigateToURL(shell(), html_url));
     const std::string js_command = "detectShapesOnImageUrl('" + detector_name +
                                    "', '" + image_url.spec() + "')";
     std::string response_string;
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index e13a1c9..a6fda4b 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -2919,7 +2919,7 @@
 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, RemoveFocusFromKilledFrame) {
   GURL main_url(embedded_test_server()->GetURL(
       "foo.com", "/cross_site_iframe_factory.html?foo.com(bar.com)"));
-  NavigateToURL(shell(), main_url);
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
 
   // It is safe to obtain the root frame tree node here, as it doesn't change.
   FrameTreeNode* root = web_contents()->GetFrameTree()->root();
diff --git a/content/browser/site_per_process_unload_browsertest.cc b/content/browser/site_per_process_unload_browsertest.cc
index dfe8ce2..1a51200a 100644
--- a/content/browser/site_per_process_unload_browsertest.cc
+++ b/content/browser/site_per_process_unload_browsertest.cc
@@ -29,6 +29,7 @@
 #include "content/browser/renderer_host/render_widget_host_view_child_frame.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/frame_messages.h"
+#include "content/public/browser/back_forward_cache.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/test/browser_test_utils.h"
@@ -473,6 +474,9 @@
 // Navigate from A(B(A(B)) to C. Check the unload handler are executed, executed
 // in the right order and the processes for A and B are removed.
 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, Unload_ABAB) {
+  web_contents()->GetController().GetBackForwardCache().DisableForTesting(
+      content::BackForwardCache::TEST_USES_UNLOAD_EVENT);
+
   GURL initial_url(embedded_test_server()->GetURL(
       "a.com", "/cross_site_iframe_factory.html?a(b(a(b)))"));
   GURL next_url(embedded_test_server()->GetURL("c.com", "/title1.html"));
@@ -608,6 +612,9 @@
 // If B1 receives FrameHostMsg_OnDetach before A2, it should not destroy itself
 // and its children, but rather wait for A2.
 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, PartialUnloadHandler) {
+  web_contents()->GetController().GetBackForwardCache().DisableForTesting(
+      content::BackForwardCache::TEST_USES_UNLOAD_EVENT);
+
   GURL url_aba(embedded_test_server()->GetURL(
       "a.com", "/cross_site_iframe_factory.html?a(b(a))"));
   GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
diff --git a/content/browser/sms/sms_browsertest.cc b/content/browser/sms/sms_browsertest.cc
index cffc46b..a99c5b1 100644
--- a/content/browser/sms/sms_browsertest.cc
+++ b/content/browser/sms/sms_browsertest.cc
@@ -97,7 +97,7 @@
 
 IN_PROC_BROWSER_TEST_F(SmsBrowserTest, Receive) {
   GURL url = GetTestUrl(nullptr, "simple_page.html");
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
 
   shell()->web_contents()->SetDelegate(&delegate_);
 
@@ -139,7 +139,7 @@
 
 IN_PROC_BROWSER_TEST_F(SmsBrowserTest, AtMostOnePendingSmsRequest) {
   GURL url = GetTestUrl(nullptr, "simple_page.html");
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
 
   shell()->web_contents()->SetDelegate(&delegate_);
 
@@ -194,7 +194,7 @@
 
 IN_PROC_BROWSER_TEST_F(SmsBrowserTest, Reload) {
   GURL url = GetTestUrl(nullptr, "simple_page.html");
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
 
   auto* provider = new NiceMock<MockSmsProvider>();
   BrowserMainLoop::GetInstance()->SetSmsProviderForTesting(
@@ -227,7 +227,7 @@
                                         ukm_loop.QuitClosure());
 
   // Reload the page.
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
 
   ukm_loop.Run();
 
@@ -238,7 +238,7 @@
 
 IN_PROC_BROWSER_TEST_F(SmsBrowserTest, Close) {
   GURL url = GetTestUrl(nullptr, "simple_page.html");
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
 
   auto* provider = new NiceMock<MockSmsProvider>();
   BrowserMainLoop::GetInstance()->SetSmsProviderForTesting(
@@ -278,8 +278,8 @@
 
   GURL url = GetTestUrl(nullptr, "simple_page.html");
 
-  NavigateToURL(tab1, url);
-  NavigateToURL(tab2, url);
+  EXPECT_TRUE(NavigateToURL(tab1, url));
+  EXPECT_TRUE(NavigateToURL(tab2, url));
 
   std::string script = R"(
     navigator.sms.receive().then(({content}) => {
@@ -394,8 +394,8 @@
   GURL url1 = https_server.GetURL("a.com", "/simple_page.html");
   GURL url2 = https_server.GetURL("b.com", "/simple_page.html");
 
-  NavigateToURL(tab1, url1);
-  NavigateToURL(tab2, url2);
+  EXPECT_TRUE(NavigateToURL(tab1, url1));
+  EXPECT_TRUE(NavigateToURL(tab2, url2));
 
   std::string script = R"(
     navigator.sms.receive().then(({content}) => {
@@ -471,7 +471,7 @@
 
 IN_PROC_BROWSER_TEST_F(SmsBrowserTest, SmsReceivedAfterTabIsClosed) {
   GURL url = GetTestUrl(nullptr, "simple_page.html");
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
 
   auto* provider = new NiceMock<MockSmsProvider>();
   BrowserMainLoop::GetInstance()->SetSmsProviderForTesting(
@@ -502,7 +502,7 @@
 
 IN_PROC_BROWSER_TEST_F(SmsBrowserTest, Cancels) {
   GURL url = GetTestUrl(nullptr, "simple_page.html");
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
 
   auto* provider = new NiceMock<MockSmsProvider>();
   BrowserMainLoop::GetInstance()->SetSmsProviderForTesting(
diff --git a/content/browser/snapshot_browsertest.cc b/content/browser/snapshot_browsertest.cc
index 4e2c122..d4288b2 100644
--- a/content/browser/snapshot_browsertest.cc
+++ b/content/browser/snapshot_browsertest.cc
@@ -90,8 +90,8 @@
         &SnapshotBrowserTest::HandleRequest, base::Unretained(this)));
     ASSERT_TRUE(embedded_test_server()->Start());
 
-    ASSERT_NO_FATAL_FAILURE(content::NavigateToURL(
-        shell(), embedded_test_server()->GetURL("/test")));
+    ASSERT_TRUE(
+        NavigateToURL(shell(), embedded_test_server()->GetURL("/test")));
   }
 
   std::unique_ptr<net::test_server::HttpResponse> HandleRequest(
diff --git a/content/browser/tracing/background_tracing_manager_browsertest.cc b/content/browser/tracing/background_tracing_manager_browsertest.cc
index 5b718712..30b0fc3 100644
--- a/content/browser/tracing/background_tracing_manager_browsertest.cc
+++ b/content/browser/tracing/background_tracing_manager_browsertest.cc
@@ -671,7 +671,7 @@
 
   background_tracing_helper.WaitForScenarioActivated();
 
-  NavigateToURL(shell(), GetTestUrl("", "about:blank"));
+  EXPECT_TRUE(NavigateToURL(shell(), GetTestUrl("", "about:blank")));
 
   TestTriggerHelper trigger_helper;
   BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
diff --git a/content/browser/tracing/memory_tracing_browsertest.cc b/content/browser/tracing/memory_tracing_browsertest.cc
index 8409d63f..a2df6b66 100644
--- a/content/browser/tracing/memory_tracing_browsertest.cc
+++ b/content/browser/tracing/memory_tracing_browsertest.cc
@@ -166,7 +166,7 @@
   }
 
   void Navigate(Shell* shell) {
-    NavigateToURL(shell, GetTestUrl("", "title1.html"));
+    EXPECT_TRUE(NavigateToURL(shell, GetTestUrl("", "title1.html")));
   }
 
   MOCK_METHOD2(OnMemoryDumpDone, void(uint32_t request_index, bool successful));
diff --git a/content/browser/tracing/startup_tracing_browsertest.cc b/content/browser/tracing/startup_tracing_browsertest.cc
index a99af71..38861a63 100644
--- a/content/browser/tracing/startup_tracing_browsertest.cc
+++ b/content/browser/tracing/startup_tracing_browsertest.cc
@@ -69,7 +69,7 @@
 };
 
 IN_PROC_BROWSER_TEST_F(CommandlineStartupTracingTest, TestStartupTracing) {
-  NavigateToURL(shell(), GetTestUrl("", "title1.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), GetTestUrl("", "title1.html")));
   WaitForCondition(base::BindRepeating([]() {
                      return !TracingController::GetInstance()->IsTracing();
                    }),
@@ -143,7 +143,7 @@
       config, wait_for_tracing.QuitClosure());
   wait_for_tracing.Run();
 
-  NavigateToURL(shell(), GetTestUrl("", "title1.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), GetTestUrl("", "title1.html")));
 
   base::RunLoop wait_for_stop;
   TracingControllerImpl::GetInstance()->StopTracing(
@@ -183,7 +183,7 @@
 #define MAYBE_TestStartupTracing TestStartupTracing
 #endif
 IN_PROC_BROWSER_TEST_F(BackgroundStartupTracingTest, MAYBE_TestStartupTracing) {
-  NavigateToURL(shell(), GetTestUrl("", "title1.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), GetTestUrl("", "title1.html")));
 
   EXPECT_FALSE(tracing::TraceStartupConfig::GetInstance()->IsEnabled());
   EXPECT_FALSE(TracingController::GetInstance()->IsTracing());
diff --git a/content/browser/web_contents/opened_by_dom_browsertest.cc b/content/browser/web_contents/opened_by_dom_browsertest.cc
index 9ef6e2b..80b5e49 100644
--- a/content/browser/web_contents/opened_by_dom_browsertest.cc
+++ b/content/browser/web_contents/opened_by_dom_browsertest.cc
@@ -92,8 +92,8 @@
   // list has only one element. Navigate a bit so the second condition is false.
   GURL url1 = embedded_test_server()->GetURL("/site_isolation/blank.html?1");
   GURL url2 = embedded_test_server()->GetURL("/site_isolation/blank.html?2");
-  NavigateToURL(shell(), url1);
-  NavigateToURL(shell(), url2);
+  EXPECT_TRUE(NavigateToURL(shell(), url1));
+  EXPECT_TRUE(NavigateToURL(shell(), url2));
 
   // This window was not opened by DOM, so close does not reach the browser
   // process.
@@ -108,10 +108,10 @@
   GURL url1 = embedded_test_server()->GetURL("/site_isolation/blank.html?1");
   GURL url2 = embedded_test_server()->GetURL("/site_isolation/blank.html?2");
   GURL url3 = embedded_test_server()->GetURL("/site_isolation/blank.html?3");
-  NavigateToURL(shell(), url1);
+  EXPECT_TRUE(NavigateToURL(shell(), url1));
 
   Shell* popup = OpenWindowFromJavaScript(shell(), url2);
-  NavigateToURL(popup, url3);
+  EXPECT_TRUE(NavigateToURL(popup, url3));
   EXPECT_TRUE(AttemptCloseFromJavaScript(popup->web_contents()));
 }
 
@@ -130,10 +130,10 @@
   GURL url3 = embedded_test_server()->GetURL("/site_isolation/blank.html?3");
   url3 = url3.ReplaceComponents(replace_host);
 
-  NavigateToURL(shell(), url1);
+  EXPECT_TRUE(NavigateToURL(shell(), url1));
 
   Shell* popup = OpenWindowFromJavaScript(shell(), url2);
-  NavigateToURL(popup, url3);
+  EXPECT_TRUE(NavigateToURL(popup, url3));
   EXPECT_TRUE(AttemptCloseFromJavaScript(popup->web_contents()));
 }
 
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc
index ba9df57..ba76526 100644
--- a/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -91,7 +91,7 @@
   // If |set_start_page| is true, start with blank page to make sure resize
   // takes effect.
   if (set_start_page)
-    NavigateToURL(shell, GURL("about://blank"));
+    EXPECT_TRUE(NavigateToURL(shell, GURL(url::kAboutBlankURL)));
 #else
   static_cast<WebContentsImpl*>(shell->web_contents())->GetView()->
       SizeContents(size);
@@ -276,7 +276,8 @@
 
   LoadStopNotificationObserver load_observer(
       &shell()->web_contents()->GetController());
-  NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
+  EXPECT_TRUE(
+      NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
   load_observer.Wait();
 
   EXPECT_EQ("/title1.html", load_observer.url_.path());
@@ -302,7 +303,7 @@
   // We will hear a DidStopLoading from the first load as the new load
   // is started.
   NavigateOnCommitObserver commit_observer(shell(), url2);
-  NavigateToURL(shell(), url1);
+  EXPECT_TRUE(NavigateToURL(shell(), url1));
   load_observer.Wait();
 
   EXPECT_EQ(url1, load_observer.url_);
@@ -406,7 +407,8 @@
                        ClearNonVisiblePendingOnFail) {
   ASSERT_TRUE(embedded_test_server()->Start());
 
-  NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
+  EXPECT_TRUE(
+      NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
 
   // Navigate to an invalid URL and make sure it doesn't leave a pending entry.
   LoadStopNotificationObserver load_observer1(
@@ -448,7 +450,8 @@
 
   // When no size is set, RenderWidgetHostView adopts the size of
   // WebContentsView.
-  NavigateToURL(shell(), embedded_test_server()->GetURL("/title2.html"));
+  EXPECT_TRUE(
+      NavigateToURL(shell(), embedded_test_server()->GetURL("/title2.html")));
   EXPECT_EQ(shell()->web_contents()->GetContainerBounds().size(),
             shell()->web_contents()->GetRenderWidgetHostView()->GetViewBounds().
                 size());
@@ -459,7 +462,7 @@
   gfx::Size size_insets(10, 15);
   ResizeWebContentsView(shell(), size, true);
   delegate->set_size_insets(size_insets);
-  NavigateToURL(shell(), https_server.GetURL("/"));
+  EXPECT_TRUE(NavigateToURL(shell(), https_server.GetURL("/")));
   size.Enlarge(size_insets.width(), size_insets.height());
   EXPECT_EQ(size,
             shell()->web_contents()->GetRenderWidgetHostView()->GetViewBounds().
@@ -484,7 +487,8 @@
   ResizeWebContentsView(shell(), init_size, true);
   delegate->set_size_insets(size_insets);
   RenderViewSizeObserver observer(shell(), new_size);
-  NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
+  EXPECT_TRUE(
+      NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
   // RenderWidgetHostView is created at specified size.
   init_size.Enlarge(size_insets.width(), size_insets.height());
   EXPECT_EQ(init_size, observer.rwhv_create_size());
@@ -507,7 +511,7 @@
       "data:text/html,"
       "<title>A</title>"
       "<body onunload=\"document.title = 'B'\"></body>");
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
   ASSERT_EQ(1, shell()->web_contents()->GetController().GetEntryCount());
   NavigationEntryImpl* entry1 = NavigationEntryImpl::FromNavigationEntry(
       shell()->web_contents()->GetController().GetLastCommittedEntry());
@@ -517,7 +521,7 @@
   // Force a process switch by going to a privileged page.
   GURL web_ui_page(std::string(kChromeUIScheme) + "://" +
                    std::string(kChromeUIGpuHost));
-  NavigateToURL(shell(), web_ui_page);
+  EXPECT_TRUE(NavigateToURL(shell(), web_ui_page));
   NavigationEntryImpl* entry2 = NavigationEntryImpl::FromNavigationEntry(
       shell()->web_contents()->GetController().GetLastCommittedEntry());
   SiteInstance* site_instance2 = entry2->site_instance();
@@ -530,8 +534,8 @@
 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, OpenURLSubframe) {
   // Navigate to a page with frames and grab a subframe's FrameTreeNode ID.
   ASSERT_TRUE(embedded_test_server()->Start());
-  NavigateToURL(shell(),
-                embedded_test_server()->GetURL("/frame_tree/top.html"));
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("/frame_tree/top.html")));
   WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
   FrameTreeNode* root = wc->GetFrameTree()->root();
   ASSERT_EQ(3UL, root->child_count());
@@ -556,11 +560,11 @@
 
 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
                        AppendingFrameInWebUIDoesNotCrash) {
-  const GURL kWebUIUrl(GetWebUIURL("tracing"));
+  const GURL kWebUIUrl(GetWebUIURL("gpu"));
   const char kJSCodeForAppendingFrame[] =
       "document.body.appendChild(document.createElement('iframe'));";
 
-  NavigateToURL(shell(), kWebUIUrl);
+  EXPECT_TRUE(NavigateToURL(shell(), kWebUIUrl));
 
   EXPECT_TRUE(content::ExecuteScript(shell(), kJSCodeForAppendingFrame));
 }
@@ -606,12 +610,12 @@
 
   // Navigate to the initial URL and capture the RenderFrameHost for later
   // comparison.
-  NavigateToURL(shell(), initial_url);
+  EXPECT_TRUE(NavigateToURL(shell(), initial_url));
   RenderFrameHost* orig_rfh = shell()->web_contents()->GetMainFrame();
 
   // Install the observer and navigate cross-site.
   RenderFrameCreatedObserver observer(shell());
-  NavigateToURL(shell(), cross_site_url);
+  EXPECT_TRUE(NavigateToURL(shell(), cross_site_url));
 
   // The observer should've seen a RenderFrameCreated call for the new frame
   // and not the old one.
@@ -630,7 +634,8 @@
       &shell()->web_contents()->GetController());
   TitleWatcher title_watcher(shell()->web_contents(),
                              base::ASCIIToUTF16("pushState"));
-  NavigateToURL(shell(), embedded_test_server()->GetURL("/push_state.html"));
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("/push_state.html")));
   load_observer.Wait();
   base::string16 title = title_watcher.WaitAndGetTitle();
   ASSERT_EQ(title, base::ASCIIToUTF16("pushState"));
@@ -650,8 +655,8 @@
                        RenderViewCreatedForChildWindow) {
   ASSERT_TRUE(embedded_test_server()->Start());
 
-  NavigateToURL(shell(),
-                embedded_test_server()->GetURL("/title1.html"));
+  EXPECT_TRUE(
+      NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
 
   WebContentsAddedObserver new_web_contents_observer;
   ASSERT_TRUE(ExecuteScript(shell(),
@@ -813,7 +818,7 @@
   // Load a page with an image and an image.
   GURL page_url(embedded_test_server()->GetURL("/page_with_iframe.html"));
   base::TimeTicks before = base::TimeTicks::Now();
-  NavigateToURL(shell(), page_url);
+  EXPECT_TRUE(NavigateToURL(shell(), page_url));
   base::TimeTicks after = base::TimeTicks::Now();
   ASSERT_EQ(3U, observer.resource_load_infos().size());
   SCOPE_TRACED(observer.CheckResourceLoaded(
@@ -841,7 +846,7 @@
   GURL page_url(
       embedded_test_server()->GetURL("/page_with_cached_subresource.html"));
   base::TimeTicks before = base::TimeTicks::Now();
-  NavigateToURL(shell(), page_url);
+  EXPECT_TRUE(NavigateToURL(shell(), page_url));
   base::TimeTicks after = base::TimeTicks::Now();
 
   GURL resource_url = embedded_test_server()->GetURL("/cachetime");
@@ -864,7 +869,7 @@
 
   // Loading again should serve the request out of the in-memory cache.
   before = base::TimeTicks::Now();
-  NavigateToURL(shell(), page_url);
+  EXPECT_TRUE(NavigateToURL(shell(), page_url));
   after = base::TimeTicks::Now();
   ASSERT_EQ(1U, observer.resource_load_infos().size());
   SCOPE_TRACED(observer.CheckResourceLoaded(
@@ -878,11 +883,11 @@
   // Kill the renderer process so when the navigate again, it will be a fresh
   // renderer with an empty in-memory cache.
   ScopedAllowRendererCrashes scoped_allow_renderer_crashes(shell());
-  NavigateToURL(shell(), GetWebUIURL("crash"));
+  EXPECT_FALSE(NavigateToURL(shell(), GetWebUIURL("crash")));
 
   // Reload that URL, the subresource should be served from the network cache.
   before = base::TimeTicks::Now();
-  NavigateToURL(shell(), page_url);
+  EXPECT_TRUE(NavigateToURL(shell(), page_url));
   after = base::TimeTicks::Now();
   ASSERT_EQ(2U, observer.resource_load_infos().size());
   SCOPE_TRACED(observer.CheckResourceLoaded(
@@ -1093,6 +1098,16 @@
   bool NavigationResourceCached(const GURL& url,
                                 const GURL& sub_frame,
                                 bool subframe_navigation_resource_cached) {
+    return NavigationResourceCached(url, url, sub_frame,
+                                    subframe_navigation_resource_cached);
+  }
+
+  // Same as above, but allows explicitly specifying the expected commit URL
+  // for the navigation to |url|, in case it differs.
+  bool NavigationResourceCached(const GURL& url,
+                                const GURL& expected_commit_url,
+                                const GURL& sub_frame,
+                                bool subframe_navigation_resource_cached) {
     // Do a cross-process navigation to clear the in-memory cache.
     // We assume that we don't start this call from "chrome://gpu", as
     // otherwise it won't be a cross-process navigation. We are relying
@@ -1102,7 +1117,7 @@
     // Observe network requests.
     ResourceLoadObserver observer(shell());
 
-    NavigateToURL(shell(), url);
+    EXPECT_TRUE(NavigateToURL(shell(), url, expected_commit_url));
 
     RenderFrameHostImpl* main_frame = static_cast<RenderFrameHostImpl*>(
         shell()->web_contents()->GetMainFrame());
@@ -1442,7 +1457,8 @@
 
   // Navigate to a.com/redirect_to_d which redirects to d.com/title1.html.
   EXPECT_FALSE(NavigationResourceCached(GenURL("a.com", "/redirect_to_d"),
-                                        GURL(), false));
+                                        GenURL("d.com", "/title1.html"), GURL(),
+                                        false));
 
   // Navigate to d.com directly. The main resource should be cached due to the
   // earlier redirected navigation.
@@ -1631,8 +1647,8 @@
                        ResourceLoadCompleteFromLocalResource) {
   ResourceLoadObserver observer(shell());
   ASSERT_TRUE(embedded_test_server()->Start());
-  NavigateToURL(shell(),
-                GURL(embedded_test_server()->GetURL("/page_with_image.html")));
+  EXPECT_TRUE(NavigateToURL(
+      shell(), GURL(embedded_test_server()->GetURL("/page_with_image.html"))));
   ASSERT_EQ(2U, observer.resource_load_infos().size());
   EXPECT_TRUE(
       observer.resource_load_infos()[0]->network_info->network_accessed);
@@ -1640,7 +1656,7 @@
       observer.resource_load_infos()[1]->network_info->network_accessed);
   observer.Reset();
 
-  NavigateToURL(shell(), GetWebUIURL("gpu"));
+  EXPECT_TRUE(NavigateToURL(shell(), GetWebUIURL("gpu")));
   ASSERT_LE(1U, observer.resource_load_infos().size());
   for (const mojom::ResourceLoadInfoPtr& resource_load_info :
        observer.resource_load_infos()) {
@@ -1657,7 +1673,8 @@
       embedded_test_server()->GetURL("/page_with_image_redirect.html"));
   GURL page_original_url(embedded_test_server()->GetURL(
       "/server-redirect?" + page_destination_url.spec()));
-  NavigateToURL(shell(), page_original_url);
+  EXPECT_TRUE(NavigateToURL(shell(), page_original_url,
+                            page_destination_url /* expected_commit_url */));
 
   ASSERT_EQ(2U, observer.resource_load_infos().size());
   const mojom::ResourceLoadInfoPtr& page_load_info =
@@ -1683,7 +1700,7 @@
   GURL image_url(embedded_test_server()->GetURL("/blank.jpg"));
 
   // Load the page without errors.
-  NavigateToURL(shell(), page_url);
+  EXPECT_TRUE(NavigateToURL(shell(), page_url));
   ASSERT_EQ(2U, observer.resource_load_infos().size());
   EXPECT_EQ(net::OK, observer.resource_load_infos()[0]->net_error);
   EXPECT_EQ(net::OK, observer.resource_load_infos()[1]->net_error);
@@ -1701,7 +1718,7 @@
         return true;
       },
       image_url));
-  NavigateToURL(shell(), page_url);
+  EXPECT_TRUE(NavigateToURL(shell(), page_url));
   ASSERT_EQ(2U, observer.resource_load_infos().size());
   EXPECT_EQ(net::OK, observer.resource_load_infos()[0]->net_error);
   EXPECT_EQ(net::ERR_ADDRESS_UNREACHABLE,
@@ -1714,7 +1731,7 @@
   ASSERT_TRUE(embedded_test_server()->Start());
 
   GURL cacheable_url(embedded_test_server()->GetURL("/set-header"));
-  NavigateToURL(shell(), cacheable_url);
+  EXPECT_TRUE(NavigateToURL(shell(), cacheable_url));
   ASSERT_EQ(1U, observer.resource_load_infos().size());
   EXPECT_FALSE(
       observer.resource_load_infos()[0]->network_info->always_access_network);
@@ -1724,7 +1741,7 @@
       "cache-control: no-cache", "cache-control: no-store", "pragma: no-cache"};
   for (const std::string& header : headers) {
     GURL no_cache_url(embedded_test_server()->GetURL("/set-header?" + header));
-    NavigateToURL(shell(), no_cache_url);
+    EXPECT_TRUE(NavigateToURL(shell(), no_cache_url));
     ASSERT_EQ(1U, observer.resource_load_infos().size());
     EXPECT_TRUE(
         observer.resource_load_infos()[0]->network_info->always_access_network);
@@ -1743,7 +1760,8 @@
   GURL start_url(embedded_test_server()->GetURL("/server-redirect?" +
                                                 intermediate_url.spec()));
 
-  NavigateToURL(shell(), start_url);
+  EXPECT_TRUE(
+      NavigateToURL(shell(), start_url, target_url /* expected_commit_url */));
 
   ASSERT_EQ(1U, observer.resource_load_infos().size());
   EXPECT_EQ(target_url, observer.resource_load_infos()[0]->url);
@@ -1773,7 +1791,7 @@
   ASSERT_TRUE(embedded_test_server()->Start());
 
   GURL url(embedded_test_server()->GetURL("/page_with_image.html"));
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
   ASSERT_EQ(2U, observer.resource_load_infos().size());
   EXPECT_EQ(url, observer.resource_load_infos()[0]->url);
   EXPECT_TRUE(observer.resource_is_associated_with_main_frame()[0]);
@@ -1782,7 +1800,7 @@
 
   // Load that same page inside an iframe.
   GURL data_url("data:text/html,<iframe src='" + url.spec() + "'></iframe>");
-  NavigateToURL(shell(), data_url);
+  EXPECT_TRUE(NavigateToURL(shell(), data_url));
   ASSERT_EQ(3U, observer.resource_load_infos().size());
   EXPECT_EQ(data_url, observer.resource_load_infos()[0]->url);
   EXPECT_EQ(url, observer.resource_load_infos()[1]->url);
@@ -1832,7 +1850,8 @@
   std::unique_ptr<LoadProgressDelegateAndObserver> delegate(
       new LoadProgressDelegateAndObserver(shell()));
 
-  NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
+  EXPECT_TRUE(
+      NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
 
   const std::vector<double>& progresses = delegate->progresses;
   // All updates should be in order ...
@@ -1854,8 +1873,8 @@
   std::unique_ptr<LoadProgressDelegateAndObserver> delegate(
       new LoadProgressDelegateAndObserver(shell()));
 
-  NavigateToURL(shell(),
-                embedded_test_server()->GetURL("/frame_tree/top.html"));
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("/frame_tree/top.html")));
 
   const std::vector<double>& progresses = delegate->progresses;
   // All updates should be in order ...
@@ -1879,7 +1898,8 @@
   ASSERT_TRUE(embedded_test_server()->Start());
 
   // Start at a real page.
-  NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
+  EXPECT_TRUE(
+      NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
 
   // Simulate a navigation that has not completed.
   const GURL kURL2 = embedded_test_server()->GetURL("/title2.html");
@@ -1946,7 +1966,8 @@
   std::unique_ptr<FirstVisuallyNonEmptyPaintObserver> observer(
       new FirstVisuallyNonEmptyPaintObserver(shell()));
 
-  NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
+  EXPECT_TRUE(
+      NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
 
   observer->WaitForDidFirstVisuallyNonEmptyPaint();
   ASSERT_TRUE(observer->did_fist_visually_non_empty_paint_);
@@ -1976,7 +1997,7 @@
   WebDisplayModeDelegate delegate(blink::kWebDisplayModeMinimalUi);
   shell()->web_contents()->SetDelegate(&delegate);
 
-  NavigateToURL(shell(), GURL("about://blank"));
+  EXPECT_TRUE(NavigateToURL(shell(), GURL(url::kAboutBlankURL)));
 
   ASSERT_TRUE(ExecuteScript(shell(),
                             "document.title = "
@@ -2038,7 +2059,8 @@
 // a notification to the browser so that WebContentsObservers are notified.
 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, ChangePageScale) {
   ASSERT_TRUE(embedded_test_server()->Start());
-  NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
+  EXPECT_TRUE(
+      NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
 
   MockPageScaleObserver observer(shell());
   ::testing::InSequence expect_call_sequence;
@@ -2058,7 +2080,7 @@
   ASSERT_TRUE(embedded_test_server()->Start());
   const GURL kUrl(embedded_test_server()->GetURL("/simple_page.html"));
   const GURL kViewSourceURL(kViewSourceScheme + std::string(":") + kUrl.spec());
-  NavigateToURL(shell(), kViewSourceURL);
+  EXPECT_TRUE(NavigateToURL(shell(), kViewSourceURL));
   // Displayed view-source URLs don't include the scheme of the effective URL if
   // the effective URL is HTTP. (e.g. view-source:example.com is displayed
   // instead of view-source:http://example.com).
@@ -2078,7 +2100,7 @@
   ASSERT_TRUE(embedded_test_server()->Start());
   const GURL kUrl(embedded_test_server()->GetURL("/simple_page.html"));
   const GURL kViewSourceURL(kViewSourceScheme + std::string(":") + kUrl.spec());
-  NavigateToURL(shell(), kUrl);
+  EXPECT_TRUE(NavigateToURL(shell(), kUrl));
 
   auto console_delegate = std::make_unique<ConsoleObserverDelegate>(
       shell()->web_contents(),
@@ -2098,7 +2120,7 @@
   ASSERT_TRUE(embedded_test_server()->Start());
   const GURL kUrl(embedded_test_server()->GetURL("/simple_page.html"));
   const GURL kViewSourceURL(kViewSourceScheme + std::string(":") + kUrl.spec());
-  NavigateToURL(shell(), kUrl);
+  EXPECT_TRUE(NavigateToURL(shell(), kUrl));
 
   std::unique_ptr<ConsoleObserverDelegate> console_delegate(
       new ConsoleObserverDelegate(
@@ -2122,8 +2144,10 @@
 // Test that view source mode for a webui page can be opened.
 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, ViewSourceWebUI) {
   const std::string kUrl = "view-source:" + GetWebUIURLString(kChromeUIGpuHost);
-  const GURL kGURL(kUrl);
-  NavigateToURL(shell(), kGURL);
+  // To ensure that NavigateToURL succeeds, append a slash to the view-source:
+  // URL, since the slash would be appended anyway as part of the navigation.
+  const GURL kGURL(kUrl + "/");
+  EXPECT_TRUE(NavigateToURL(shell(), kGURL));
   EXPECT_EQ(base::ASCIIToUTF16(kUrl), shell()->web_contents()->GetTitle());
   EXPECT_TRUE(shell()
                   ->web_contents()
@@ -2250,7 +2274,7 @@
     const std::string& html,
     bool expect_onunload,
     bool expect_onbeforeunload) {
-  NavigateToURL(shell, GURL("data:text/html," + html));
+  EXPECT_TRUE(NavigateToURL(shell, GURL("data:text/html," + html)));
   RenderFrameHostImpl* rfh =
       static_cast<RenderFrameHostImpl*>(shell->web_contents()->GetMainFrame());
   EXPECT_EQ(expect_onunload || expect_onbeforeunload,
@@ -2457,8 +2481,8 @@
 
   ASSERT_TRUE(embedded_test_server()->Start());
 
-  NavigateToURL(shell(),
-                embedded_test_server()->GetURL("a.com", "/title1.html"));
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
   EXPECT_TRUE(WaitForLoadStop(wc));
 
   FrameTreeNode* root = wc->GetFrameTree()->root();
@@ -2515,8 +2539,8 @@
             GURL(test_delegate.last_message()).ReplaceComponents(clear_port));
 
   // Navigate the top frame cross-site; ensure that dialogs work.
-  NavigateToURL(shell(),
-                embedded_test_server()->GetURL("c.com", "/title3.html"));
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("c.com", "/title3.html")));
   EXPECT_TRUE(WaitForLoadStop(wc));
   test_delegate.WillWaitForDialog();
   EXPECT_TRUE(
@@ -2826,8 +2850,8 @@
   shell()->web_contents()->SetDelegate(delegate.get());
   ASSERT_TRUE(shell()->web_contents()->GetDelegate() == delegate.get());
 
-  NavigateToURL(shell(),
-                embedded_test_server()->GetURL("a.com", "/title1.html"));
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
 
   // Try to request pointer lock. WebContentsDelegate should get a notification.
   ASSERT_TRUE(ExecuteScript(shell(),
@@ -2854,8 +2878,8 @@
   EXPECT_FALSE(delegate.get()->request_to_lock_mouse_called_);
 
   // Force a cross-process navigation so that the RenderWidgetHost is deleted.
-  NavigateToURL(shell(),
-                embedded_test_server()->GetURL("b.com", "/title1.html"));
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
 
   // Make sure the WebContents cleaned up the previous pending request. A new
   // request should be forwarded to the WebContentsDelegate.
@@ -2874,7 +2898,7 @@
   const GURL kUrl(embedded_test_server()->GetURL(kHeaderPath));
   const std::string kUserAgentOverride = "foo";
 
-  NavigateToURL(shell(), kUrl);
+  EXPECT_TRUE(NavigateToURL(shell(), kUrl));
   std::string header_value;
   EXPECT_TRUE(ExecuteScriptAndExtractString(
       shell()->web_contents(),
@@ -2883,7 +2907,7 @@
   EXPECT_NE(kUserAgentOverride, header_value);
 
   shell()->web_contents()->SetUserAgentOverride("foo", false);
-  NavigateToURL(shell(), kUrl);
+  EXPECT_TRUE(NavigateToURL(shell(), kUrl));
   EXPECT_TRUE(ExecuteScriptAndExtractString(
       shell()->web_contents(),
       "window.domAutomationController.send(document.body.textContent);",
@@ -3327,7 +3351,7 @@
   EXPECT_TRUE(embedded_test_server()->Start());
 
   GURL test_url = embedded_test_server()->GetURL("/pause_schedule_task.html");
-  NavigateToURL(shell(), test_url);
+  EXPECT_TRUE(NavigateToURL(shell(), test_url));
   EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
 
   int text_length;
@@ -3728,7 +3752,7 @@
   // Load a page with a subframe link.
   GURL main_url(
       embedded_test_server()->GetURL("/ctrl-click-subframe-link.html"));
-  NavigateToURL(shell(), main_url);
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
 
   // Start intercepting the DidOpenRequestedURL callback.
   MockDidOpenRequestedURLObserver mock_observer(shell());
diff --git a/content/browser/web_contents/web_contents_view_aura_browsertest.cc b/content/browser/web_contents/web_contents_view_aura_browsertest.cc
index 3e0aa35..deda0c9 100644
--- a/content/browser/web_contents/web_contents_view_aura_browsertest.cc
+++ b/content/browser/web_contents/web_contents_view_aura_browsertest.cc
@@ -85,7 +85,7 @@
       test_url = GURL(url);
     else
       test_url = GURL(embedded_test_server()->GetURL(url));
-    NavigateToURL(shell(), test_url);
+    EXPECT_TRUE(NavigateToURL(shell(), test_url));
 
     frame_observer_ = std::make_unique<RenderFrameSubmissionObserver>(
         shell()->web_contents());
diff --git a/content/browser/web_contents_binding_set_browsertest.cc b/content/browser/web_contents_binding_set_browsertest.cc
index c375f87..20872b5 100644
--- a/content/browser/web_contents_binding_set_browsertest.cc
+++ b/content/browser/web_contents_binding_set_browsertest.cc
@@ -66,7 +66,7 @@
 }  // namespace
 
 IN_PROC_BROWSER_TEST_F(WebContentsBindingSetBrowserTest, OverrideForTesting) {
-  NavigateToURL(shell(), GURL("data:text/html,ho hum"));
+  EXPECT_TRUE(NavigateToURL(shell(), GURL("data:text/html,ho hum")));
 
   // Ensure that we can add a WebContentsFrameBindingSet and then override its
   // request handler.
diff --git a/content/browser/webauth/webauth_browsertest.cc b/content/browser/webauth/webauth_browsertest.cc
index 3fa5f3b..6f12380 100644
--- a/content/browser/webauth/webauth_browsertest.cc
+++ b/content/browser/webauth/webauth_browsertest.cc
@@ -392,7 +392,8 @@
         new WebAuthBrowserTestContentBrowserClient(&test_state_));
     old_client_ = SetBrowserClientForTesting(test_client_.get());
 
-    NavigateToURL(shell(), GetHttpsURL("www.acme.com", "/title1.html"));
+    EXPECT_TRUE(
+        NavigateToURL(shell(), GetHttpsURL("www.acme.com", "/title1.html")));
   }
 
   void TearDown() override {
@@ -551,7 +552,8 @@
                                   create_callback_receiver.callback());
 
   fake_hid_discovery->WaitForCallToStartAndSimulateSuccess();
-  NavigateToURL(shell(), GetHttpsURL("www.acme.com", "/title2.html"));
+  EXPECT_TRUE(
+      NavigateToURL(shell(), GetHttpsURL("www.acme.com", "/title2.html")));
   WaitForConnectionError();
 
   // The next active document should be able to successfully call
@@ -573,7 +575,8 @@
                                 get_callback_receiver.callback());
 
   fake_hid_discovery->WaitForCallToStartAndSimulateSuccess();
-  NavigateToURL(shell(), GetHttpsURL("www.acme.com", "/title2.html"));
+  EXPECT_TRUE(
+      NavigateToURL(shell(), GetHttpsURL("www.acme.com", "/title2.html")));
   WaitForConnectionError();
 
   // The next active document should be able to successfully call
@@ -629,7 +632,8 @@
           if (behavior == AttestationCallbackBehavior::BEFORE_NAVIGATION) {
             std::move(callback).Run(false);
           }
-          NavigateToURL(shell(), GetHttpsURL("www.acme.com", "/title2.html"));
+          EXPECT_TRUE(NavigateToURL(
+              shell(), GetHttpsURL("www.acme.com", "/title2.html")));
           if (behavior == AttestationCallbackBehavior::AFTER_NAVIGATION) {
             std::move(callback).Run(false);
           }
@@ -648,7 +652,9 @@
   ScopedNavigationCancellingThrottleInstaller navigation_canceller(
       shell()->web_contents());
 
-  NavigateToURL(shell(), GetHttpsURL("www.acme.com", "/title2.html"));
+  // This navigation should be canceled and hence should not succeed.
+  EXPECT_FALSE(
+      NavigateToURL(shell(), GetHttpsURL("www.acme.com", "/title2.html")));
 
   auto* fake_hid_discovery = discovery_factory_->ForgeNextHidDiscovery();
   TestCreateCallbackReceiver create_callback_receiver;
@@ -672,7 +678,8 @@
       }));
 
   auto* fake_hid_discovery = discovery_factory_->ForgeNextHidDiscovery();
-  NavigateToURL(shell(), GetHttpsURL("www.acme.com", "/title2.html"));
+  EXPECT_TRUE(
+      NavigateToURL(shell(), GetHttpsURL("www.acme.com", "/title2.html")));
   WaitForConnectionError();
 
   // Normally, when the request is serviced, the implementation retrieves the
@@ -1117,7 +1124,8 @@
                        RequestsFromIFrames) {
   static constexpr char kOuterHost[] = "acme.com";
   static constexpr char kInnerHost[] = "notacme.com";
-  NavigateToURL(shell(), GetHttpsURL(kOuterHost, "/page_with_iframe.html"));
+  EXPECT_TRUE(NavigateToURL(shell(),
+                            GetHttpsURL(kOuterHost, "/page_with_iframe.html")));
 
   auto* virtual_device_factory = InjectVirtualFidoDeviceFactory();
   static constexpr uint8_t kOuterCredentialID = 1;
@@ -1193,7 +1201,8 @@
         return true;
       });
 
-  NavigateToURL(shell(), GetHttpsURL("www.acme.com", "/page_with_iframe.html"));
+  EXPECT_TRUE(NavigateToURL(
+      shell(), GetHttpsURL("www.acme.com", "/page_with_iframe.html")));
 
   // The plain ExecuteScriptAndExtractString cannot be used because
   // NavigateIframeToURL uses it internally and they get confused about which
@@ -1247,8 +1256,8 @@
         },
         shell()->web_contents(), &prompt_callback_was_invoked, behavior);
 
-    NavigateToURL(shell(),
-                  GetHttpsURL("www.acme.com", "/page_with_iframe.html"));
+    EXPECT_TRUE(NavigateToURL(
+        shell(), GetHttpsURL("www.acme.com", "/page_with_iframe.html")));
 
     CreateParameters parameters;
     parameters.attestation = "direct";
@@ -1302,7 +1311,8 @@
 
 #if defined(OS_WIN)
 IN_PROC_BROWSER_TEST_F(WebAuthJavascriptClientBrowserTest, WinMakeCredential) {
-  NavigateToURL(shell(), GetHttpsURL("www.acme.com", "/title1.html"));
+  EXPECT_TRUE(
+      NavigateToURL(shell(), GetHttpsURL("www.acme.com", "/title1.html")));
 
   device::FakeWinWebAuthnApi fake_api;
   fake_api.set_is_uvpaa(true);
@@ -1319,7 +1329,8 @@
 
 IN_PROC_BROWSER_TEST_F(WebAuthJavascriptClientBrowserTest,
                        WinMakeCredentialReturnCodeFailure) {
-  NavigateToURL(shell(), GetHttpsURL("www.acme.com", "/title1.html"));
+  EXPECT_TRUE(
+      NavigateToURL(shell(), GetHttpsURL("www.acme.com", "/title1.html")));
   device::FakeWinWebAuthnApi fake_api;
   auto* virtual_device_factory = InjectVirtualFidoDeviceFactory();
   virtual_device_factory->set_win_webauthn_api(&fake_api);
@@ -1355,7 +1366,8 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebAuthJavascriptClientBrowserTest, WinGetAssertion) {
-  NavigateToURL(shell(), GetHttpsURL("www.acme.com", "/title1.html"));
+  EXPECT_TRUE(
+      NavigateToURL(shell(), GetHttpsURL("www.acme.com", "/title1.html")));
 
   device::FakeWinWebAuthnApi fake_api;
   fake_api.set_hresult(S_OK);
@@ -1379,7 +1391,8 @@
 
 IN_PROC_BROWSER_TEST_F(WebAuthJavascriptClientBrowserTest,
                        WinGetAssertionReturnCodeFailure) {
-  NavigateToURL(shell(), GetHttpsURL("www.acme.com", "/title1.html"));
+  EXPECT_TRUE(
+      NavigateToURL(shell(), GetHttpsURL("www.acme.com", "/title1.html")));
   device::FakeWinWebAuthnApi fake_api;
   auto* virtual_device_factory = InjectVirtualFidoDeviceFactory();
   virtual_device_factory->set_win_webauthn_api(&fake_api);
diff --git a/content/browser/webkit_browsertest.cc b/content/browser/webkit_browsertest.cc
index eacc310b..510c48e 100644
--- a/content/browser/webkit_browsertest.cc
+++ b/content/browser/webkit_browsertest.cc
@@ -64,7 +64,7 @@
   URLLoaderInterceptor interceptor(base::BindRepeating(&AbortOnEndInterceptor));
   GURL url = embedded_test_server()->GetURL(kAsyncScriptThatAbortsOnEndPage);
 
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
 
   // If you are seeing this test fail, please strongly investigate the
   // possibility that http://crbug.com/75604 and
@@ -86,7 +86,7 @@
   URLLoaderInterceptor interceptor(base::BindRepeating(&AbortOnEndInterceptor));
   GURL url = embedded_test_server()->GetURL(kXsltBadImportPage);
 
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
 
   EXPECT_FALSE(shell()->web_contents()->IsCrashed());
 }
@@ -106,7 +106,7 @@
   ASSERT_TRUE(embedded_test_server()->Start());
   GURL url = embedded_test_server()->GetURL(kPrerenderNoCrashPage);
 
-  NavigateToURL(shell(), url);
+  EXPECT_TRUE(NavigateToURL(shell(), url));
 
   EXPECT_FALSE(shell()->web_contents()->IsCrashed());
 }
diff --git a/content/browser/webui/web_ui_mojo_browsertest.cc b/content/browser/webui/web_ui_mojo_browsertest.cc
index c9c44e3..7f6e404 100644
--- a/content/browser/webui/web_ui_mojo_browsertest.cc
+++ b/content/browser/webui/web_ui_mojo_browsertest.cc
@@ -309,7 +309,7 @@
     g_got_message = false;
     base::RunLoop run_loop;
     factory()->set_run_loop(&run_loop);
-    NavigateToURL(shell(), test_url);
+    EXPECT_TRUE(NavigateToURL(shell(), test_url));
     // RunLoop is quit when message received from page.
     run_loop.Run();
     EXPECT_TRUE(g_got_message);
@@ -321,7 +321,7 @@
     g_got_message = false;
     base::RunLoop other_run_loop;
     factory()->set_run_loop(&other_run_loop);
-    NavigateToURL(other_shell, test_url);
+    EXPECT_TRUE(NavigateToURL(other_shell, test_url));
     // RunLoop is quit when message received from page.
     other_run_loop.Run();
     EXPECT_TRUE(g_got_message);
@@ -349,7 +349,7 @@
     g_got_message = false;
     base::RunLoop other_run_loop;
     factory()->set_run_loop(&other_run_loop);
-    NavigateToURL(other_shell, test_url);
+    EXPECT_TRUE(NavigateToURL(other_shell, test_url));
     // RunLoop is quit when message received from page.
     other_run_loop.Run();
     EXPECT_TRUE(g_got_message);
diff --git a/content/browser/worker_host/shared_worker_service_impl.cc b/content/browser/worker_host/shared_worker_service_impl.cc
index 1690af4d..f21a68f 100644
--- a/content/browser/worker_host/shared_worker_service_impl.cc
+++ b/content/browser/worker_host/shared_worker_service_impl.cc
@@ -132,8 +132,10 @@
   RenderFrameHost* main_frame =
       render_frame_host->frame_tree_node()->frame_tree()->GetMainFrame();
   if (!GetContentClient()->browser()->AllowSharedWorker(
-          info->url, main_frame->GetLastCommittedURL(), info->name,
-          constructor_origin,
+          info->url,
+          // TODO(crbug.com/989926): Get an actual site_for_cookies.
+          main_frame->GetLastCommittedURL(),
+          main_frame->GetLastCommittedOrigin(), info->name, constructor_origin,
           WebContentsImpl::FromRenderFrameHostID(client_process_id, frame_id)
               ->GetBrowserContext(),
           client_process_id, frame_id)) {
diff --git a/content/browser/worker_host/worker_browsertest.cc b/content/browser/worker_host/worker_browsertest.cc
index 6fcee68..68ab191 100644
--- a/content/browser/worker_host/worker_browsertest.cc
+++ b/content/browser/worker_host/worker_browsertest.cc
@@ -88,7 +88,7 @@
     const base::string16 fail_title = base::ASCIIToUTF16("FAIL");
     TitleWatcher title_watcher(window->web_contents(), ok_title);
     title_watcher.AlsoWaitForTitle(fail_title);
-    NavigateToURL(window, url);
+    EXPECT_TRUE(NavigateToURL(window, url));
     base::string16 final_title = title_watcher.WaitAndGetTitle();
     EXPECT_EQ(expect_failure ? fail_title : ok_title, final_title);
   }
@@ -252,7 +252,7 @@
   Shell* window = shell();
   const base::string16 expected_title = base::ASCIIToUTF16("OK");
   TitleWatcher title_watcher(window->web_contents(), expected_title);
-  NavigateToURL(window, url);
+  EXPECT_TRUE(NavigateToURL(window, url));
   base::string16 final_title = title_watcher.WaitAndGetTitle();
   EXPECT_EQ(expected_title, final_title);
 }
diff --git a/content/browser/worker_host/worker_script_loader_factory_unittest.cc b/content/browser/worker_host/worker_script_loader_factory_unittest.cc
index f90a93e..63e03331 100644
--- a/content/browser/worker_host/worker_script_loader_factory_unittest.cc
+++ b/content/browser/worker_host/worker_script_loader_factory_unittest.cc
@@ -13,6 +13,7 @@
 #include "content/browser/service_worker/service_worker_navigation_handle_core.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/test/fake_network_url_loader_factory.h"
+#include "net/base/network_isolation_key.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "services/network/public/cpp/wrapper_shared_url_loader_factory.h"
 #include "services/network/test/test_url_loader_client.h"
@@ -65,6 +66,10 @@
     network::mojom::URLLoaderPtr loader;
     network::ResourceRequest resource_request;
     resource_request.url = url;
+    resource_request.trusted_params = network::ResourceRequest::TrustedParams();
+    resource_request.trusted_params->network_isolation_key =
+        net::NetworkIsolationKey(url::Origin::Create(url),
+                                 url::Origin::Create(url));
     resource_request.resource_type =
         static_cast<int>(ResourceType::kSharedWorker);
     factory->CreateLoaderAndStart(
diff --git a/content/public/browser/browser_thread.h b/content/public/browser/browser_thread.h
index b1d1f6c..dcec2a0 100644
--- a/content/public/browser/browser_thread.h
+++ b/content/public/browser/browser_thread.h
@@ -69,8 +69,13 @@
   // NOTE: Task posting APIs have moved to post_task.h. See
   // browser_task_traits.h.
 
-  // TODO(crbug.com/878356): Consider replacing callsites of this with
-  // base::CreateTaskRunner({id})->DeleteSoon(..).
+  // Delete/ReleaseSoon() helpers allow future deletion of an owned object on
+  // its associated thread. If you already have a task runner bound to a
+  // BrowserThread you should use its SequencedTaskRunner::DeleteSoon() member
+  // method. If you don't, the helpers below avoid having to do
+  // base::CreateSingleThreadTaskRunner({BrowserThread::ID})->DeleteSoon(...)
+  // which is equivalent.
+
   template <class T>
   static bool DeleteSoon(ID identifier,
                          const base::Location& from_here,
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index 64e7acb..4e28aae 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -298,7 +298,8 @@
 
 bool ContentBrowserClient::AllowServiceWorkerOnIO(
     const GURL& scope,
-    const GURL& first_party,
+    const GURL& site_for_cookies,
+    const base::Optional<url::Origin>& top_frame_origin,
     const GURL& script_url,
     ResourceContext* context,
     base::RepeatingCallback<WebContents*()> wc_getter) {
@@ -307,7 +308,8 @@
 
 bool ContentBrowserClient::AllowServiceWorkerOnUI(
     const GURL& scope,
-    const GURL& first_party,
+    const GURL& site_for_cookies,
+    const base::Optional<url::Origin>& top_frame_origin,
     const GURL& script_url,
     BrowserContext* context,
     base::RepeatingCallback<WebContents*()> wc_getter) {
@@ -316,7 +318,8 @@
 
 bool ContentBrowserClient::AllowSharedWorker(
     const GURL& worker_url,
-    const GURL& main_frame_url,
+    const GURL& site_for_cookies,
+    const base::Optional<url::Origin>& top_frame_origin,
     const std::string& name,
     const url::Origin& constructor_origin,
     BrowserContext* context,
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index 84a8e2f..80f9b3a 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -541,9 +541,14 @@
                              BrowserContext* context);
 
   // Allows the embedder to control if a service worker is allowed at the given
-  // |scope| and can be accessed from |first_party|. This function is called
-  // whenever an attempt is made to create or access the persistent state of the
-  // registration, or to start the service worker.
+  // |scope| and can be accessed from |site_for_cookies| and |top_frame_origin|.
+  // |site_for_cookies| is used to determine whether the request is done in a
+  // third-party context. |top_frame_origin| is used to check if any
+  // content_setting affects this request. Only calls that are made within the
+  // context of a tab can provide a proper |top_frame_origin|, otherwise the
+  // scope of the service worker is used.
+  // This function is called whenever an attempt is made to create or access the
+  // persistent state of the registration, or to start the service worker.
   //
   // If non-empty, |script_url| is the script of the service worker that is
   // attempted to be registered or started. If it's empty, an attempt is being
@@ -555,14 +560,16 @@
   // This is called on the IO thread.
   virtual bool AllowServiceWorkerOnIO(
       const GURL& scope,
-      const GURL& first_party,
+      const GURL& site_for_cookies,
+      const base::Optional<url::Origin>& top_frame_origin,
       const GURL& script_url,
       ResourceContext* context,
       base::RepeatingCallback<WebContents*()> wc_getter);
   // Same but for the UI thread.
   virtual bool AllowServiceWorkerOnUI(
       const GURL& scope,
-      const GURL& first_party,
+      const GURL& site_for_cookies,
+      const base::Optional<url::Origin>& top_frame_origin,
       const GURL& script_url,
       BrowserContext* context,
       base::RepeatingCallback<WebContents*()> wc_getter);
@@ -570,13 +577,15 @@
   // Allow the embedder to control if a Shared Worker can be connected from a
   // given tab.
   // This is called on the UI thread.
-  virtual bool AllowSharedWorker(const GURL& worker_url,
-                                 const GURL& main_frame_url,
-                                 const std::string& name,
-                                 const url::Origin& constructor_origin,
-                                 BrowserContext* context,
-                                 int render_process_id,
-                                 int render_frame_id);
+  virtual bool AllowSharedWorker(
+      const GURL& worker_url,
+      const GURL& site_for_cookies,
+      const base::Optional<url::Origin>& top_frame_origin,
+      const std::string& name,
+      const url::Origin& constructor_origin,
+      BrowserContext* context,
+      int render_process_id,
+      int render_frame_id);
 
   // Allow the embedder to control if a page/worker with |scheme| URL can create
   // a cross-origin shared workers.
diff --git a/content/renderer/dom_serializer_browsertest.cc b/content/renderer/dom_serializer_browsertest.cc
index bda6ad1..eaf66a5 100644
--- a/content/renderer/dom_serializer_browsertest.cc
+++ b/content/renderer/dom_serializer_browsertest.cc
@@ -638,7 +638,7 @@
   GURL file_url = net::FilePathToFileURL(page_file_path);
   ASSERT_TRUE(file_url.SchemeIsFile());
   // Load the test file.
-  NavigateToURL(shell(), file_url);
+  EXPECT_TRUE(NavigateToURL(shell(), file_url));
 
   PostTaskToInProcessRendererAndWait(base::BindOnce(
       &MAYBE_DomSerializerTests::SerializeHTMLDOMWithDocTypeOnRenderer,
@@ -654,7 +654,7 @@
   GURL file_url = net::FilePathToFileURL(page_file_path);
   ASSERT_TRUE(file_url.SchemeIsFile());
   // Load the test file.
-  NavigateToURL(shell(), file_url);
+  EXPECT_TRUE(NavigateToURL(shell(), file_url));
 
   PostTaskToInProcessRendererAndWait(base::BindOnce(
       &MAYBE_DomSerializerTests::SerializeHTMLDOMWithoutDocTypeOnRenderer,
@@ -683,7 +683,7 @@
   ASSERT_TRUE(file_url.SchemeIsFile());
 
   // Load the test file.
-  NavigateToURL(shell(), file_url);
+  EXPECT_TRUE(NavigateToURL(shell(), file_url));
 
   PostTaskToInProcessRendererAndWait(base::BindOnce(
       &MAYBE_DomSerializerTests::SerializeXMLDocWithBuiltInEntitiesOnRenderer,
@@ -708,7 +708,7 @@
   ASSERT_TRUE(file_url.SchemeIsFile());
 
   // Load the test file.
-  NavigateToURL(shell(), file_url);
+  EXPECT_TRUE(NavigateToURL(shell(), file_url));
 
   PostTaskToInProcessRendererAndWait(base::BindOnce(
       &MAYBE_DomSerializerTests::SerializeHTMLDOMWithAddingMOTWOnRenderer,
@@ -733,7 +733,7 @@
   ASSERT_TRUE(file_url.SchemeIsFile());
 
   // Load the test file.
-  NavigateToURL(shell(), file_url);
+  EXPECT_TRUE(NavigateToURL(shell(), file_url));
 
   PostTaskToInProcessRendererAndWait(base::BindOnce(
       &MAYBE_DomSerializerTests::SerializeHTMLDOMWithAddingMOTWOnRenderer,
@@ -755,7 +755,7 @@
   GURL file_url = net::FilePathToFileURL(page_file_path);
   ASSERT_TRUE(file_url.SchemeIsFile());
   // Load the test file.
-  NavigateToURL(shell(), file_url);
+  EXPECT_TRUE(NavigateToURL(shell(), file_url));
 
   PostTaskToInProcessRendererAndWait(base::BindOnce(
       &MAYBE_DomSerializerTests::
@@ -777,7 +777,7 @@
   GURL file_url = net::FilePathToFileURL(page_file_path);
   ASSERT_TRUE(file_url.SchemeIsFile());
   // Load the test file.
-  NavigateToURL(shell(), file_url);
+  EXPECT_TRUE(NavigateToURL(shell(), file_url));
 
   PostTaskToInProcessRendererAndWait(base::BindOnce(
       &MAYBE_DomSerializerTests::
@@ -791,7 +791,7 @@
   // Need to spin up the renderer and also navigate to a file url so that the
   // renderer code doesn't attempt a fork when it sees a load to file scheme
   // from non-file scheme.
-  NavigateToURL(shell(), GetTestUrl(".", "simple_page.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), GetTestUrl(".", "simple_page.html")));
 
   PostTaskToInProcessRendererAndWait(base::BindOnce(
       &MAYBE_DomSerializerTests::SerializeHTMLDOMWithEntitiesInTextOnRenderer,
@@ -806,7 +806,7 @@
   // Need to spin up the renderer and also navigate to a file url so that the
   // renderer code doesn't attempt a fork when it sees a load to file scheme
   // from non-file scheme.
-  NavigateToURL(shell(), GetTestUrl(".", "simple_page.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), GetTestUrl(".", "simple_page.html")));
 
   PostTaskToInProcessRendererAndWait(
       base::BindOnce(&MAYBE_DomSerializerTests::
@@ -822,7 +822,7 @@
   base::FilePath page_file_path = GetTestFilePath(
       "dom_serializer", "nonstandard_htmlentities.htm");
   GURL file_url = net::FilePathToFileURL(page_file_path);
-  NavigateToURL(shell(), file_url);
+  EXPECT_TRUE(NavigateToURL(shell(), file_url));
 
   PostTaskToInProcessRendererAndWait(
       base::BindOnce(&MAYBE_DomSerializerTests::
@@ -848,7 +848,7 @@
   GURL file_url = net::FilePathToFileURL(page_file_path);
   ASSERT_TRUE(file_url.SchemeIsFile());
   // Load the test file.
-  NavigateToURL(shell(), file_url);
+  EXPECT_TRUE(NavigateToURL(shell(), file_url));
 
   PostTaskToInProcessRendererAndWait(base::BindOnce(
       &MAYBE_DomSerializerTests::SerializeHTMLDOMWithBaseTagOnRenderer,
@@ -861,7 +861,7 @@
   // Need to spin up the renderer and also navigate to a file url so that the
   // renderer code doesn't attempt a fork when it sees a load to file scheme
   // from non-file scheme.
-  NavigateToURL(shell(), GetTestUrl(".", "simple_page.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), GetTestUrl(".", "simple_page.html")));
 
   PostTaskToInProcessRendererAndWait(base::BindOnce(
       &MAYBE_DomSerializerTests::SerializeHTMLDOMWithEmptyHeadOnRenderer,
@@ -873,7 +873,7 @@
   base::FilePath page_file_path = GetTestFilePath(
       "dom_serializer", "non_html_namespace.htm");
   GURL file_url = net::FilePathToFileURL(page_file_path);
-  NavigateToURL(shell(), file_url);
+  EXPECT_TRUE(NavigateToURL(shell(), file_url));
 
   PostTaskToInProcessRendererAndWait(
       base::BindOnce(&MAYBE_DomSerializerTests::
diff --git a/content/renderer/render_frame_impl_browsertest.cc b/content/renderer/render_frame_impl_browsertest.cc
index 2e9ac3e..7c408996 100644
--- a/content/renderer/render_frame_impl_browsertest.cc
+++ b/content/renderer/render_frame_impl_browsertest.cc
@@ -788,8 +788,6 @@
       mojo::PendingReceiver<blink::mojom::CredentialManager>) override {}
   void GetAuthenticator(
       mojo::PendingReceiver<blink::mojom::Authenticator> receiver) override {}
-  void GetPushMessaging(
-      mojo::PendingReceiver<blink::mojom::PushMessaging> receiver) override {}
   void GetVirtualAuthenticatorManager(
       mojo::PendingReceiver<blink::test::mojom::VirtualAuthenticatorManager>
           receiver) override {}
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index 1832cee..7cd7d03 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -23,9 +23,7 @@
 #include "base/observer_list.h"
 #include "base/optional.h"
 #include "base/strings/string16.h"
-#include "base/threading/thread_checker.h"
 #include "base/time/time.h"
-#include "base/timer/timer.h"
 #include "build/build_config.h"
 #include "content/child/child_thread_impl.h"
 #include "content/common/content_export.h"
@@ -65,10 +63,6 @@
 #include "third_party/blink/public/web/web_memory_statistics.h"
 #include "ui/gfx/native_widget_types.h"
 
-#if defined(OS_MACOSX)
-#include "third_party/blink/public/platform/mac/web_scrollbar_theme.h"
-#endif
-
 class SkBitmap;
 
 namespace blink {
@@ -81,8 +75,6 @@
 }
 
 namespace cc {
-class BeginFrameSource;
-class SyntheticBeginFrameSource;
 class TaskGraphRunner;
 }
 
@@ -94,20 +86,11 @@
 class GpuChannelHost;
 }
 
-namespace IPC {
-class MessageFilter;
-}
-
 namespace media {
 class GpuVideoAcceleratorFactories;
 }
 
-namespace v8 {
-class Extension;
-}
-
 namespace viz {
-class BeginFrameSource;
 class ContextProviderCommandBuffer;
 class Gpu;
 class RasterContextProvider;
@@ -360,11 +343,6 @@
   // first call.
   AudioRendererMixerManager* GetAudioRendererMixerManager();
 
-#if defined(OS_WIN)
-  void PreCacheFontCharacters(const LOGFONT& log_font,
-                              const base::string16& str);
-#endif
-
   class UnfreezableMessageFilter : public IPC::MessageFilter {
    public:
     explicit UnfreezableMessageFilter(RenderThreadImpl* render_thread_impl);
diff --git a/content/renderer/render_thread_impl_browsertest.cc b/content/renderer/render_thread_impl_browsertest.cc
index 2fa4fee..129cea20 100644
--- a/content/renderer/render_thread_impl_browsertest.cc
+++ b/content/renderer/render_thread_impl_browsertest.cc
@@ -453,7 +453,7 @@
   }
 
   void SetUpOnMainThread() override {
-    NavigateToURL(shell(), GURL(url::kAboutBlankURL));
+    EXPECT_TRUE(NavigateToURL(shell(), GURL(url::kAboutBlankURL)));
     PostTaskToInProcessRendererAndWait(base::BindOnce(
         &RenderThreadImplGpuMemoryBufferBrowserTest::SetUpOnRenderThread,
         base::Unretained(this)));
diff --git a/content/renderer/render_thread_impl_discardable_memory_browsertest.cc b/content/renderer/render_thread_impl_discardable_memory_browsertest.cc
index 179c98fd..bdb4f382 100644
--- a/content/renderer/render_thread_impl_discardable_memory_browsertest.cc
+++ b/content/renderer/render_thread_impl_discardable_memory_browsertest.cc
@@ -42,7 +42,7 @@
   }
 
   void SetUpOnMainThread() override {
-    NavigateToURL(shell(), GURL(url::kAboutBlankURL));
+    EXPECT_TRUE(NavigateToURL(shell(), GURL(url::kAboutBlankURL)));
     PostTaskToInProcessRendererAndWait(base::BindOnce(
         &RenderThreadImplDiscardableMemoryBrowserTest::SetUpOnRenderThread,
         base::Unretained(this)));
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index fd79ca16..e753d69 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -485,7 +485,7 @@
 }
 
 RenderWidget::~RenderWidget() {
-  DCHECK(!webwidget_internal_) << "Leaking our WebWidget!";
+  DCHECK(!webwidget_) << "Leaking our WebWidget!";
   DCHECK(closed_)
       << " RenderWidget must be destroyed via RenderWidget::Close()";
 
@@ -529,6 +529,8 @@
 
 void RenderWidget::CloseForFrame(std::unique_ptr<RenderWidget> widget) {
   DCHECK(for_child_local_root_frame_);
+  DCHECK_EQ(widget.get(), this);  // This method takes ownership of |this|.
+
   PrepareForClose();
 
   // The RenderWidget may be deattached from JS, which in turn may be called
@@ -541,7 +543,7 @@
 }
 
 void RenderWidget::Init(ShowCallback show_callback, WebWidget* web_widget) {
-  DCHECK(!webwidget_internal_);
+  DCHECK(!webwidget_);
   DCHECK_NE(routing_id_, MSG_ROUTING_NONE);
 
   RenderThreadImpl* render_thread_impl = RenderThreadImpl::current();
@@ -589,7 +591,7 @@
       std::make_unique<TextInputClientObserver>(for_frame() ? this : nullptr);
 #endif
 
-  webwidget_internal_ = web_widget;
+  webwidget_ = web_widget;
   webwidget_mouse_lock_target_.reset(new WebWidgetLockTarget(this));
   mouse_lock_dispatcher_.reset(new RenderWidgetMouseLockDispatcher(this));
 
@@ -760,7 +762,40 @@
   if (input_event_queue_)
     input_event_queue_->ClearClient();
 
-  CloseWebWidget();
+  // If the browser has not sent OnDisableDeviceEmulation, we have an emulator
+  // hanging out still. Destroying it must happen *after* the IPC route is
+  // removed so that another IPC does not arrive and re-create the emulator
+  // during closing.
+  //
+  // This destruction is normally part of an IPC and expects objects to be alive
+  // that would be alive while the IPC route is active such as the
+  // |layer_tree_view_|. So we ensure that it is the first thing to be
+  // destroyed here before deleting things from the RenderWidget or the
+  // delegate().
+  //
+  // TODO(danakj): The emulator could reset to non-emulated values in an
+  // explicit method call (instead of in the destructor) that occurs when
+  // emulation is disabled, but does not need to occur during RenderWidget
+  // closing. Then we would not have to destroy this so carefully.
+  //
+  // Screen metrics emulation can only be set by the local main frame render
+  // widget.
+  if (delegate_)
+    page_properties_->SetScreenMetricsEmulator(nullptr);
+
+  // TODO(https://crbug.com/995981): This logic is very confusing and should be
+  // fixed. When RenderWidget is owned by a RenderViewImpl, its lifetime is tied
+  // to the RenderViewImpl. In that case the RenderViewImpl takes responsibility
+  // for closing the WebWidget when the main frame is detached.
+  //
+  // For all other RenderWidgets, the RenderWidget is destroyed at the same
+  // time as the WebWidget, and the RenderWidget takes responsibility for doing
+  // that here.
+  if (!delegate())
+    webwidget_->Close();
+  webwidget_ = nullptr;
+
+  close_weak_ptr_factory_.InvalidateWeakPtrs();
 }
 
 void RenderWidget::SynchronizeVisualPropertiesFromRenderView(
@@ -2027,44 +2062,6 @@
   DCHECK_EQ(widget.get(), this);
 }
 
-void RenderWidget::CloseWebWidget() {
-  // If the browser has not sent OnDisableDeviceEmulation, we have an emulator
-  // hanging out still. Destroying it must happen *after* the IPC route is
-  // removed so that another IPC does not arrive and re-create the emulator
-  // during closing.
-  //
-  // This destruction is normally part of an IPC and expects objects to be alive
-  // that would be alive while the IPC route is active such as the
-  // |layer_tree_view_|. So we ensure that it is the first thing to be
-  // destroyed here before deleting things from the RenderWidget or the
-  // delegate().
-  //
-  // TODO(danakj): The emulator could reset to non-emulated values in an
-  // explicit method call (instead of in the destructor) that occurs when
-  // emulation is disabled, but does not need to occur during RenderWidget
-  // closing. Then we would not have to destroy this so carefully.
-  //
-  // Screen metrics emulation can only be set by the local main frame render
-  // widget.
-  if (delegate_)
-    page_properties_->SetScreenMetricsEmulator(nullptr);
-
-  // TODO(https://crbug.com/995981): This logic is very confusing and should be
-  // fixed. When the RenderWidget is associated with a RenderView,
-  // webwidget_internal_ points to an instance of WebView. This is owned by the
-  // RenderView, which also owns the RenderWidget and is calling into this
-  // method. We do nothing here and let RenderView destroy the WebView.
-  //
-  // For all other RenderWidgets, webwidget_internal_ points at a 'real'
-  // instance of a WebWidget which is owned by the RenderWidget. In this case,
-  // we must close the webwidget.
-  if (!delegate())
-    webwidget_internal_->Close();
-  webwidget_internal_ = nullptr;
-
-  close_weak_ptr_factory_.InvalidateWeakPtrs();
-}
-
 blink::WebFrameWidget* RenderWidget::GetFrameWidget() const {
   // TODO(danakj): Remove this check and don't call this method for non-frames.
   if (!for_frame())
@@ -2073,7 +2070,7 @@
   // check for a null WebWidget.
   if (closing_)
     return nullptr;
-  return static_cast<blink::WebFrameWidget*>(webwidget_internal_);
+  return static_cast<blink::WebFrameWidget*>(webwidget_);
 }
 
 bool RenderWidget::IsForProvisionalFrame() const {
@@ -2081,9 +2078,9 @@
     return false;
   // No widget here means the main frame is remote and there is no
   // provisional frame at the moment.
-  if (!webwidget_internal_)
+  if (!webwidget_)
     return false;
-  auto* frame_widget = static_cast<blink::WebFrameWidget*>(webwidget_internal_);
+  auto* frame_widget = static_cast<blink::WebFrameWidget*>(webwidget_);
   return frame_widget->LocalRoot()->IsProvisional();
 }
 
@@ -3929,13 +3926,13 @@
   return weak_ptr_factory_.GetWeakPtr();
 }
 
-void RenderWidget::SetWebWidgetInternal(blink::WebWidget* web_widget) {
+void RenderWidget::SetWebWidgetInternal(blink::WebWidget* webwidget) {
   // TODO(https://crbug.com/995981): This method should not need to exist, since
   // we should be creating and destroying a RenderWidget along with the
   // WebWidget.
-  if (web_widget)
-    web_widget->SetAnimationHost(layer_tree_view_->animation_host());
-  webwidget_internal_ = web_widget;
+  if (webwidget)
+    webwidget->SetAnimationHost(layer_tree_view_->animation_host());
+  webwidget_ = webwidget;
 }
 
 }  // namespace content
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index cba8c77..a752dd6 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -275,7 +275,7 @@
   // is true, the widget returned is a blink::WebFrameWidget.
   // TODO(crbug.com/419087): The main frame RenderWidget will also return
   // nullptr while the main frame is remote.
-  blink::WebWidget* GetWebWidget() const { return webwidget_internal_; }
+  blink::WebWidget* GetWebWidget() const { return webwidget_; }
 
   // Returns the current instance of WebInputMethodController which is to be
   // used for IME related tasks. This instance corresponds to the one from
@@ -704,7 +704,7 @@
   // should be tied to the lifetime of the WebWidget. In the short term, for
   // main frames, the RenderView has to explicitly set/unset the WebWidget on
   // attach/detach.
-  void SetWebWidgetInternal(blink::WebWidget* web_widget);
+  void SetWebWidgetInternal(blink::WebWidget* webwidget);
 
  protected:
   // Notify subclasses that we initiated the paint operation.
@@ -767,11 +767,6 @@
   // is always in physical pixels.
   gfx::Rect CompositorViewportRect() const;
 
-  // Just Close the WebWidget, in cases where the Close() will be deferred.
-  // It is safe to call this multiple times, which happens in the case of
-  // frame widgets beings closed, since subsequent calls are ignored.
-  void CloseWebWidget();
-
 #if BUILDFLAG(USE_EXTERNAL_POPUP_MENU)
   void SetExternalPopupOriginAdjustmentsForEmulation(ExternalPopupMenu* popup);
 #endif
@@ -937,10 +932,13 @@
   // features.
   CompositorDependencies* const compositor_deps_;
 
-  // Use GetWebWidget() instead of using webwidget_internal_ directly.
-  // We are responsible for destroying this object via its Close method.
-  // May be NULL when the window is closing.
-  blink::WebWidget* webwidget_internal_ = nullptr;
+  // We are responsible for destroying this object via its Close method, unless
+  // the RenderWidget is associated with a RenderViewImpl through |delegate_|.
+  // Becomes null once close is initiated on the RenderWidget.
+  // TODO(https://crbug.com/995981): For main frame RenderWidgets associated
+  // with a RenderViewImpl through |delegate_|, this is also null when the
+  // RenderWidget is undead.
+  blink::WebWidget* webwidget_ = nullptr;
 
   // The delegate for this object which is just a RenderViewImpl.
   // This member is non-null if and only if the RenderWidget is associated with
@@ -952,7 +950,6 @@
   // frame widgets.
   PageProperties* const page_properties_;
 
-  // This is lazily constructed and must not outlive webwidget_.
   std::unique_ptr<LayerTreeView> layer_tree_view_;
   // This is valid while |layer_tree_view_| is valid.
   cc::LayerTreeHost* layer_tree_host_ = nullptr;
diff --git a/content/renderer/render_widget_unittest.cc b/content/renderer/render_widget_unittest.cc
index 67a8339..4377ac3 100644
--- a/content/renderer/render_widget_unittest.cc
+++ b/content/renderer/render_widget_unittest.cc
@@ -187,7 +187,6 @@
         mojo::PendingReceiver<mojom::WidgetInputHandler>(),
         mock_input_handler_host_->BindNewPipeAndPassRemote());
   }
-  ~InteractiveRenderWidget() override { webwidget_internal_ = nullptr; }
 
   void SendInputEvent(const blink::WebInputEvent& event,
                       HandledEventCallback callback) {
diff --git a/content/renderer/savable_resources_browsertest.cc b/content/renderer/savable_resources_browsertest.cc
index 08c18e33..ceade9d4 100644
--- a/content/renderer/savable_resources_browsertest.cc
+++ b/content/renderer/savable_resources_browsertest.cc
@@ -44,7 +44,7 @@
     // Convert local file path to file URL.
     GURL file_url = net::FilePathToFileURL(page_file_path);
     // Load the test file.
-    NavigateToURL(shell(), file_url);
+    EXPECT_TRUE(NavigateToURL(shell(), file_url));
 
     PostTaskToInProcessRendererAndWait(base::BindOnce(
         &SavableResourcesTest::CheckResources, base::Unretained(this),
diff --git a/content/renderer/visual_state_browsertest.cc b/content/renderer/visual_state_browsertest.cc
index bf81f60..8c206d8 100644
--- a/content/renderer/visual_state_browsertest.cc
+++ b/content/renderer/visual_state_browsertest.cc
@@ -103,7 +103,7 @@
   // two commits then this test will prove nothing. We could detect this
   // with a high level of confidence if we used a timeout, but that's
   // discouraged (see https://codereview.chromium.org/939673002).
-  NavigateToURL(shell(), GURL("about:blank"));
+  EXPECT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
   CommitObserver observer(RenderView::FromRoutingID(
       shell()->web_contents()->GetRenderViewHost()->GetRoutingID()));
 
diff --git a/content/renderer/webclipboard_impl_browsertest.cc b/content/renderer/webclipboard_impl_browsertest.cc
index 2f71afe..889ebc3 100644
--- a/content/renderer/webclipboard_impl_browsertest.cc
+++ b/content/renderer/webclipboard_impl_browsertest.cc
@@ -30,7 +30,7 @@
 
   FrameFocusedObserver focus_observer(shell()->web_contents()->GetMainFrame());
   // paste_listener.html takes RTF from the clipboard and sets the title.
-  NavigateToURL(shell(), GetTestUrl(".", "paste_listener.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), GetTestUrl(".", "paste_listener.html")));
   focus_observer.Wait();
 
   const base::string16 expected_title = base::UTF8ToUTF16(rtf_content);
diff --git a/content/test/content_browser_test_test.cc b/content/test/content_browser_test_test.cc
index b501246..d329ef9 100644
--- a/content/test/content_browser_test_test.cc
+++ b/content/test/content_browser_test_test.cc
@@ -56,7 +56,7 @@
       shell()->web_contents()->GetMainFrame()->GetProcess(),
       content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
 
-  NavigateToURL(shell(), GetWebUIURL("crash"));
+  EXPECT_FALSE(NavigateToURL(shell(), GetWebUIURL("crash")));
   renderer_shutdown_observer.Wait();
 
   EXPECT_FALSE(renderer_shutdown_observer.did_exit_normally());
@@ -232,7 +232,7 @@
 
     base::string16 expected_title(base::ASCIIToUTF16("OK"));
     TitleWatcher title_watcher(shell()->web_contents(), expected_title);
-    NavigateToURL(shell(), url);
+    EXPECT_TRUE(NavigateToURL(shell(), url));
     base::string16 title = title_watcher.WaitAndGetTitle();
     EXPECT_EQ(expected_title, title);
   }
diff --git a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
index 39c5dd2..32a8bc37 100644
--- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -99,7 +99,7 @@
 crbug.com/660461 [ mac ] Pixel_ScissorTestWithPreserveDrawingBuffer [ RetryOnFailure ]
 
 # Failing on Nexus 5; haven't investigated why yet.
-crbug.com/773293 [ android qualcomm-adreno-(tm)-330 ] Pixel_WebGL2_BlitFramebuffer_Result_Displayed [ Skip ]
+crbug.com/773293 [ android no-use-gl qualcomm-adreno-(tm)-330 ] Pixel_WebGL2_BlitFramebuffer_Result_Displayed [ Skip ]
 crbug.com/773293 [ android qualcomm-adreno-(tm)-330 ] Pixel_WebGL2_ClearBufferfv_Result_Displayed [ Skip ]
 
 crbug.com/774809 [ highsierra intel-0xa2e ] Pixel_WebGLGreenTriangle_NonChromiumImage_NoAA_NoAlpha [ Failure ]
@@ -234,7 +234,9 @@
 crbug.com/969864 [ android skia-renderer use-gl no-use-vulkan ] Pixel_Video_MP4_FourColors_Rot_180 [ Skip ]
 crbug.com/969864 [ android skia-renderer use-gl no-use-vulkan ] Pixel_Video_MP4_FourColors_Rot_270 [ Skip ]
 crbug.com/969864 [ android skia-renderer use-gl no-use-vulkan ] Pixel_Video_MP4_FourColors_Rot_90 [ Skip ]
+crbug.com/969864 [ android skia-renderer use-gl no-use-vulkan ] Pixel_Video_MP4_Rounded_Corner [ Skip ]
 crbug.com/969864 [ android skia-renderer use-gl no-use-vulkan ] Pixel_Video_VP9 [ Skip ]
+crbug.com/969864 [ android skia-renderer use-gl no-use-vulkan ] Pixel_WebGL2_BlitFramebuffer_Result_Displayed [ Skip ]
 
 # Produces blank images on Intel HD 630 w/ Mesa 19.0.2
 crbug.com/976861 [ linux intel-0x5912 ] Pixel_OffscreenCanvasTransferToImageBitmap [ Skip ]
diff --git a/content/test/webui_resource_browsertest.cc b/content/test/webui_resource_browsertest.cc
index 902a228..6cc594d 100644
--- a/content/test/webui_resource_browsertest.cc
+++ b/content/test/webui_resource_browsertest.cc
@@ -31,7 +31,7 @@
       ASSERT_TRUE(PathExists(file));
     }
 
-    NavigateToURL(shell(), net::FilePathToFileURL(file));
+    EXPECT_TRUE(NavigateToURL(shell(), net::FilePathToFileURL(file)));
 
     content::WebContents* web_contents = shell()->web_contents();
     ASSERT_TRUE(web_contents);
diff --git a/content/zygote/zygote_browsertest.cc b/content/zygote/zygote_browsertest.cc
index 8c1a139..b93c8e9 100644
--- a/content/zygote/zygote_browsertest.cc
+++ b/content/zygote/zygote_browsertest.cc
@@ -35,7 +35,7 @@
   const char kTestCommand[] =
       "window.domAutomationController.send(new Date().toString());";
 
-  NavigateToURL(shell(), GURL("data:text/html,start page"));
+  EXPECT_TRUE(NavigateToURL(shell(), GURL("data:text/html,start page")));
   std::string result;
   ASSERT_TRUE(ExecuteScriptAndExtractString(shell(), kTestCommand, &result));
   std::vector<std::string> parts = base::SplitString(
@@ -67,14 +67,14 @@
 // Test that the renderer doesn't crash during launch if zygote is disabled.
 IN_PROC_BROWSER_TEST_F(LinuxZygoteDisabledBrowserTest,
                        NoCrashWhenZygoteDisabled) {
-  NavigateToURL(shell(), GURL("data:text/html,start page"));
+  EXPECT_TRUE(NavigateToURL(shell(), GURL("data:text/html,start page")));
 }
 #endif
 
 #if BUILDFLAG(USE_ZYGOTE_HANDLE)
 IN_PROC_BROWSER_TEST_F(LinuxZygoteDisabledBrowserTest,
                        NoZygoteWhenZygoteDisabled) {
-  NavigateToURL(shell(), GURL("data:text/html,start page"));
+  EXPECT_TRUE(NavigateToURL(shell(), GURL("data:text/html,start page")));
 
   EXPECT_FALSE(service_manager::ZygoteHostImpl::GetInstance()->HasZygote());
 }
diff --git a/extensions/browser/extension_event_histogram_value.h b/extensions/browser/extension_event_histogram_value.h
index 359ebe6..9dbe05d 100644
--- a/extensions/browser/extension_event_histogram_value.h
+++ b/extensions/browser/extension_event_histogram_value.h
@@ -461,6 +461,7 @@
   ACCESSIBILITY_PRIVATE_ON_SWITCH_ACCESS_COMMAND = 439,
   ACCESSIBILITY_PRIVATE_FIND_SCROLLABLE_BOUNDS_FOR_POINT = 440,
   LOGIN_STATE_ON_SESSION_STATE_CHANGED = 441,
+  PRINTING_METRICS_ON_PRINT_JOB_FINISHED = 442,
   // Last entry: Add new entries above, then run:
   // python tools/metrics/histograms/update_extension_histograms.py
   ENUM_BOUNDARY
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index 417cb2c..32b43e0 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -1446,6 +1446,7 @@
   AUTOTESTPRIVATE_TAKESCREENSHOTFORDISPLAY = 1383,
   AUTOFILLPRIVATE_SETCREDITCARDFIDOAUTHENABLEDSTATE = 1384,
   USERSPRIVATE_ISWHITELISTEDUSER = 1385,
+  PRINTINGMETRICS_GETPRINTJOBS = 1386,
   // Last entry: Add new entries above, then run:
   // python tools/metrics/histograms/update_extension_histograms.py
   ENUM_BOUNDARY
diff --git a/extensions/common/permissions/api_permission.h b/extensions/common/permissions/api_permission.h
index 6b87c87..55f7dfa 100644
--- a/extensions/common/permissions/api_permission.h
+++ b/extensions/common/permissions/api_permission.h
@@ -264,6 +264,7 @@
     kLogin = 220,
     kLoginScreenStorage = 221,
     kLoginState = 222,
+    kPrintingMetrics = 223,
     // Last entry: Add new entries above and ensure to update the
     // "ExtensionPermission3" enum in tools/metrics/histograms/enums.xml
     // (by running update_extension_permission.py).
diff --git a/extensions/common/permissions/extensions_api_permissions.cc b/extensions/common/permissions/extensions_api_permissions.cc
index 000d8653..3f3780f 100644
--- a/extensions/common/permissions/extensions_api_permissions.cc
+++ b/extensions/common/permissions/extensions_api_permissions.cc
@@ -92,6 +92,7 @@
      APIPermissionInfo::kFlagCannotBeOptional},
     {APIPermission::kPower, "power"},
     {APIPermission::kPrinterProvider, "printerProvider"},
+    {APIPermission::kPrintingMetrics, "printingMetrics"},
     {APIPermission::kSerial, "serial"},
     {APIPermission::kSocket, "socket", APIPermissionInfo::kFlagCannotBeOptional,
      &CreateAPIPermission<SocketPermission>},
diff --git a/gpu/ipc/service/gpu_init.cc b/gpu/ipc/service/gpu_init.cc
index ec9fe28..b8fe808 100644
--- a/gpu/ipc/service/gpu_init.cc
+++ b/gpu/ipc/service/gpu_init.cc
@@ -508,7 +508,6 @@
       ui::OzonePlatform::GetInstance()
           ->GetSurfaceFactoryOzone()
           ->GetSupportedFormatsForTexturing();
-  ui::OzonePlatform::GetInstance()->AfterSandboxEntry();
 #endif
   bool needs_more_info = true;
 #if !defined(IS_CHROMECAST)
diff --git a/ios/chrome/app/strings/ios_chromium_strings.grd b/ios/chrome/app/strings/ios_chromium_strings.grd
index 166b803..d7595b2 100644
--- a/ios/chrome/app/strings/ios_chromium_strings.grd
+++ b/ios/chrome/app/strings/ios_chromium_strings.grd
@@ -195,9 +195,6 @@
       <message name="IDS_IOS_MANAGE_SYNC_DATA_FROM_CHROME_SYNC_TITLE" desc="Title for the cell to open 'Data from Chromium sync' web page where the user can control all their data data from sync.">
         Data from Chromium sync
       </message>
-      <message name="IDS_IOS_MANAGED_DISCONNECT_DIALOG_INFO" desc="Message explaining that signing out of a managed account will clear all the Chromium data.[Length: 200em, may be line wrapped to multiple lines at run time.] [iOS only].">
-        You are signing out of an account managed by <ph name="SIGNOUT_MANAGED_DOMAIN">$1<ex>google.com</ex></ph>. This will delete your Chromium data from this device, but your data will remain in your Google account.
-      </message>
       <message name="IDS_IOS_MANAGED_DISCONNECT_DIALOG_INFO_UNITY" desc="Message explaining that signing out of a managed account will clear all the Chromium data.[Length: 200em, may be line wrapped to multiple lines at run time.] [iOS only].">
         Because you're signing out of an account managed by <ph name="SIGNOUT_MANAGED_DOMAIN">$1<ex>google.com</ex></ph>, your Chromium data will be deleted from this device. Your data will remain in your Google Account.
       </message>
@@ -222,9 +219,6 @@
       <message name="IDS_IOS_OPEN_TABS_SYNC_IS_OFF_MOBILE" desc="Short paragraph(s) encouraging the user to enable sync on device [Length: 300em, may be line wrapped to multiple lines at run time.]">
         Tabs that you've opened in Chromium on your other devices will appear here.
       </message>
-      <message name="IDS_IOS_OPTIONS_ACCOUNTS_SIGNOUT" desc="Title of the button to sign out of Chromium [iOS only] [60em]">
-        Sign out of Chromium
-      </message>
       <message name="IDS_IOS_OPTIONS_IMPORT_DATA_TITLE_SIGNIN" desc="The title of the Import Data settings screen when signing in. [30em]">
         Sign in to Chromium
       </message>
diff --git a/ios/chrome/app/strings/ios_google_chrome_strings.grd b/ios/chrome/app/strings/ios_google_chrome_strings.grd
index 5057cbc..a22ee18b 100644
--- a/ios/chrome/app/strings/ios_google_chrome_strings.grd
+++ b/ios/chrome/app/strings/ios_google_chrome_strings.grd
@@ -195,9 +195,6 @@
       <message name="IDS_IOS_MANAGE_SYNC_DATA_FROM_CHROME_SYNC_TITLE" desc="Title for the cell to open 'Data from Chrome sync' web page where the user can control all their data data from sync.">
         Data from Chrome sync
       </message>
-      <message name="IDS_IOS_MANAGED_DISCONNECT_DIALOG_INFO" desc="Message explaining that signing out of a managed account will clear all the Chrome data.[Length: 200em, may be line wrapped to multiple lines at run time.] [iOS only].">
-        You are signing out of an account managed by <ph name="SIGNOUT_MANAGED_DOMAIN">$1<ex>google.com</ex></ph>. This will delete your Chrome data from this device, but your data will remain in your Google account.
-      </message>
       <message name="IDS_IOS_MANAGED_DISCONNECT_DIALOG_INFO_UNITY" desc="Message explaining that signing out of a managed account will clear all the Chrome data. [Length: 200em, may be line wrapped to multiple lines at run time.] [iOS only].">
         Because you're signing out of an account managed by <ph name="SIGNOUT_MANAGED_DOMAIN">$1<ex>google.com</ex></ph>, your Chrome data will be deleted from this device. Your data will remain in your Google Account.
       </message>
@@ -222,9 +219,6 @@
       <message name="IDS_IOS_OPEN_TABS_SYNC_IS_OFF_MOBILE" desc="Short paragraph(s) encouraging the user to enable sync on device [Length: 300em, may be line wrapped to multiple lines at run time.]">
         Tabs that you've opened in Chrome on your other devices will appear here.
       </message>
-      <message name="IDS_IOS_OPTIONS_ACCOUNTS_SIGNOUT" desc="Title of the button to sign out of Chrome [iOS only] [60em]">
-        Sign out of Chrome
-      </message>
       <message name="IDS_IOS_OPTIONS_IMPORT_DATA_TITLE_SIGNIN" desc="The title of the Import Data settings screen when signing in. [30em]">
         Sign in to Chrome
       </message>
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index 6c9f0fc..8f58991 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -866,15 +866,9 @@
       <message name="IDS_IOS_MANAGE_SYNC_DATA_FROM_CHROME_SYNC_DESCRIPTION" desc="Subtitle for the cell to open 'Data from Chromium sync' web page where the user can control all their data data from sync.">
         Manage synced data on Google Dashboard
       </message>
-      <message name="IDS_IOS_MANAGED_DISCONNECT_DIALOG_ACCEPT" desc="Label on the button to proceed with signout and clear all Chrome data.[Length: 30em].">
-        Accept and sign out
-      </message>
       <message name="IDS_IOS_MANAGED_DISCONNECT_DIALOG_ACCEPT_UNITY" desc="Label on the button to proceed with signout and clear all Chrome data.[Length: 30em].">
         Clear
       </message>
-      <message name="IDS_IOS_MANAGED_DISCONNECT_DIALOG_TITLE" desc="Title of the dialog shown when signing out of a managed account.[Length: 50em] [iOS only].">
-        Sign out of managed account
-      </message>
       <message name="IDS_IOS_MANAGED_SIGNIN_ACCEPT_BUTTON" desc="The title of the Accept button of the Sign in to a managed account dialog. [40em]">
         Accept and sign in
       </message>
@@ -1022,21 +1016,9 @@
       <message name="IDS_IOS_OPTIONS_ACCOUNTS_DESCRIPTION" desc="Text informing the user of the accounts they are signed in to Chrome with [iOS only] [150em]">
         Signed In to Google as
       </message>
-      <message name="IDS_IOS_OPTIONS_ACCOUNTS_GOOGLE_DESCRIPTION" desc="Text of the Google Activity Controls button on the accounts settings screen [Length: 150em]">
-        Control how Google uses your browsing history to personalize Search, ads, and other Google services
-      </message>
-      <message name="IDS_IOS_OPTIONS_ACCOUNTS_GOOGLE_TITLE" desc="Title of the Google Activity Controls button on the accounts settings screen [Length: 50em]">
-        Google Activity Controls
-      </message>
-      <message name="IDS_IOS_OPTIONS_ACCOUNTS_SYNC_ERROR" desc="Text informing the user that sync isn't working properly [iOS only] [60em]">
-        Sync isn't working. Tap to fix.
-      </message>
       <message name="IDS_IOS_OPTIONS_ACCOUNTS_SYNC_IS_OFF" desc="Text informing the user that sync is off [iOS only] [60em]">
         Off
       </message>
-      <message name="IDS_IOS_OPTIONS_ACCOUNTS_SYNC_TITLE" desc="Title of the Sync button on the accounts settings screen [iOS only] [30em]">
-        Sync
-      </message>
       <message name="IDS_IOS_OPTIONS_ACCOUNTS_SIGN_OUT_TURN_OFF_SYNC" desc="Title of the button to sign out and turn off sync. [iOS only]">
         Sign out and turn off sync
       </message>
@@ -1492,6 +1474,15 @@
       <message name="IDS_IOS_SETTINGS_TOOLBAR_DELETE" desc="Label of the button displayed on the bottom toolbar of the settings' collections when they are in edit mode. Pressing this button deletes the currently selected items.">
         Delete
       </message>
+        <message name="IDS_IOS_SETTINGS_SWIPE_DOWN_MESSAGE" desc="Message displayed whenever a user tries to dismiss a Settings screen which is being edited, or information is being added to it.">
+        Are you sure you want to discard your changes?
+      </message>
+      <message name="IDS_IOS_SETTINGS_SWIPE_DOWN_DISCARD" desc="Button displayed along with a message alert whenever a user tries to dismiss a Settings screen which is being edited, or information is being added to it. Selecting this option will discard the current changes and dismiss the screen.">
+        Discard Changes
+      </message>
+      <message name="IDS_IOS_SETTINGS_SWIPE_DOWN_KEEP" desc="Button displayed along with a message alert whenever a user tries to dismiss a Settings screen which is being edited, or information is being added to it. Selecting this option will dismiss the message alert, and will keep displaying the settings screen.">
+        Keep Editing
+      </message>
       <message name="IDS_IOS_TOGGLE_SETTING_SWITCH_ACCESSIBILITY_HINT" desc="Action hint for any switch in settings. This is spoken by VoiceOver. [iOS only]">
         Double tap to toggle setting
       </message>
@@ -1660,9 +1651,6 @@
       <message name="IDS_IOS_SYNC_CONFIRM_PASSPHRASE_LABEL" desc="The text for the confirm-passphrase field. [Length: 20em] [iOS only]">
         Confirm passphrase
       </message>
-      <message name="IDS_IOS_SYNC_DATA_TYPES_TITLE" desc="The title for the section of the data types to sync to">
-        Data Types
-      </message>
       <message name="IDS_IOS_SYNC_DECRYPT_BUTTON" desc="The title for the decrypt button on the encryption password screen [Length: 10em] [iOS only]">
         Submit
       </message>
@@ -1732,12 +1720,6 @@
       <message name="IDS_IOS_SYNC_PASSPHRASE_RECOVER" desc="Message about how to recover from a lost passphrase. [Length:100em, may be multiple lines] [iOS only]">
         If you forget your passphrase or want to change this setting, <ph name="BEGIN_LINK">BEGIN_LINK</ph>reset sync<ph name="END_LINK">END_LINK</ph>
       </message>
-      <message name="IDS_IOS_SYNC_RESET_GOOGLE_DASHBOARD_NO_LINK" desc="Message about how to reset sync via Google Dashboard without any link. [Length: 50em] [iOS only]">
-        Manage Synced Data…
-      </message>
-      <message name="IDS_IOS_SYNC_SETTING_TITLE" desc="The title for the Sync control for sync [iOS only]">
-        Sync
-      </message>
       <message name="IDS_IOS_SYNC_SETTINGS_NOT_CONFIRMED" desc="The error message to display when sign-in was interrupted and the user didn't review the sync settings.">
         Initial sync setup was not finished. Sync is off.
       </message>
@@ -1759,9 +1741,6 @@
       <message name="IDS_IOS_SYNC_STATUS_UNRECOVERABLE_ERROR" desc="Message shown throughout the sync settings screens when there is an unrecoverable error. [Length: 80em, can be multiple lines] [iOS only]">
         Sync has stopped working.
       </message>
-      <message name="IDS_IOS_SYNC_TO_TITLE" desc="The title for the section of the accounts available for sync">
-        Sync to
-      </message>
       <message name="IDS_IOS_SYNC_UPDATE_CREDENTIALS" desc="Title displayed when the signed in user needs to update its credentials. [Length: 20em] [iOS only]">
         Update
       </message>
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_SETTINGS_SWIPE_DOWN.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_SETTINGS_SWIPE_DOWN.png.sha1
new file mode 100644
index 0000000..f8d1f90
--- /dev/null
+++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_SETTINGS_SWIPE_DOWN.png.sha1
@@ -0,0 +1 @@
+86557c53bab25e735c9becf4120f6a1b9cc66cb3
\ No newline at end of file
diff --git a/ios/chrome/browser/infobars/infobar_badge_model.h b/ios/chrome/browser/infobars/infobar_badge_model.h
index 8e26d74..07e7663 100644
--- a/ios/chrome/browser/infobars/infobar_badge_model.h
+++ b/ios/chrome/browser/infobars/infobar_badge_model.h
@@ -13,8 +13,7 @@
 // A model object that represents a badge for an Infobar.
 @interface InfobarBadgeModel : NSObject <BadgeItem>
 
-- (instancetype)initWithInfobarType:(InfobarType)type
-                           accepted:(BOOL)accepted NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithInfobarType:(InfobarType)type NS_DESIGNATED_INITIALIZER;
 - (instancetype)init NS_UNAVAILABLE;
 
 @end
diff --git a/ios/chrome/browser/infobars/infobar_badge_model.mm b/ios/chrome/browser/infobars/infobar_badge_model.mm
index d33ad80..17ed26f 100644
--- a/ios/chrome/browser/infobars/infobar_badge_model.mm
+++ b/ios/chrome/browser/infobars/infobar_badge_model.mm
@@ -18,17 +18,17 @@
 @end
 
 @implementation InfobarBadgeModel
-// Synthesized from protocol.
+// Synthesized from BadgeItem.
 @synthesize tappable = _tappable;
-// Synthesized from protocol.
-@synthesize accepted = _accepted;
+// Synthesized from BadgeItem.
+@synthesize badgeState = _badgeState;
 
-- (instancetype)initWithInfobarType:(InfobarType)type accepted:(BOOL)accepted {
+- (instancetype)initWithInfobarType:(InfobarType)type {
   self = [super init];
   if (self) {
     _tappable = YES;
     _infobarType = type;
-    _accepted = accepted;
+    _badgeState = BadgeStateNone;
   }
   return self;
 }
diff --git a/ios/chrome/browser/infobars/infobar_badge_tab_helper.mm b/ios/chrome/browser/infobars/infobar_badge_tab_helper.mm
index 76470ac..94c9768c 100644
--- a/ios/chrome/browser/infobars/infobar_badge_tab_helper.mm
+++ b/ios/chrome/browser/infobars/infobar_badge_tab_helper.mm
@@ -33,11 +33,8 @@
 
 void InfobarBadgeTabHelper::UpdateBadgeForInfobarAccepted(
     InfobarType infobar_type) {
-    InfobarBadgeModel* badgeModel =
-        [[InfobarBadgeModel alloc] initWithInfobarType:infobar_type
-                                              accepted:YES];
-    [delegate_ updateInfobarBadge:badgeModel];
-    infobar_badge_models_[infobar_type] = badgeModel;
+  infobar_badge_models_[infobar_type].badgeState = BadgeStateAccepted;
+  [delegate_ updateInfobarBadge:infobar_badge_models_[infobar_type]];
 }
 
 void InfobarBadgeTabHelper::UpdateBadgeForInfobarBannerDismissed(
@@ -91,8 +88,7 @@
     InfobarType infobar_type = controller_.infobarType;
     if (display) {
       InfobarBadgeModel* new_badge =
-          [[InfobarBadgeModel alloc] initWithInfobarType:infobar_type
-                                                accepted:NO];
+          [[InfobarBadgeModel alloc] initWithInfobarType:infobar_type];
       infobar_badge_models_[infobar_type] = new_badge;
       [delegate_ addInfobarBadge:new_badge];
     } else {
diff --git a/ios/chrome/browser/infobars/infobar_badge_tab_helper_unittest.mm b/ios/chrome/browser/infobars/infobar_badge_tab_helper_unittest.mm
index a7d1a2d3..3d04302 100644
--- a/ios/chrome/browser/infobars/infobar_badge_tab_helper_unittest.mm
+++ b/ios/chrome/browser/infobars/infobar_badge_tab_helper_unittest.mm
@@ -34,20 +34,20 @@
     : NSObject <InfobarBadgeTabHelperDelegate>
 @property(nonatomic, assign) BOOL displayingBadge;
 @property(nonatomic, assign) BOOL badgeIsTappable;
-@property(nonatomic, assign) BOOL badgeIsAccepted;
+@property(nonatomic, assign) BadgeState badgeState;
 @property(nonatomic, assign) BadgeType badgeType;
 @end
 
 @implementation InfobarBadgeTabHelperTestDelegate
 - (void)updateInfobarBadge:(id<BadgeItem>)badgeItem {
   self.badgeIsTappable = badgeItem.isTappable;
-  self.badgeIsAccepted = badgeItem.isAccepted;
+  self.badgeState = badgeItem.badgeState;
   self.badgeType = badgeItem.badgeType;
 }
 - (void)addInfobarBadge:(id<BadgeItem>)badgeItem {
   self.displayingBadge = YES;
   self.badgeIsTappable = badgeItem.isTappable;
-  self.badgeIsAccepted = badgeItem.isAccepted;
+  self.badgeState = badgeItem.badgeState;
   self.badgeType = badgeItem.badgeType;
 }
 - (void)removeInfobarBadge:(id<BadgeItem>)badgeItem {
@@ -219,16 +219,16 @@
 TEST_F(InfobarBadgeTabHelperTest, TestInfobarBadgeState) {
   EXPECT_FALSE(infobar_badge_tab_delegate_.displayingBadge);
   EXPECT_FALSE(infobar_badge_tab_delegate_.badgeIsTappable);
-  EXPECT_FALSE(infobar_badge_tab_delegate_.badgeIsAccepted);
+  EXPECT_NE(infobar_badge_tab_delegate_.badgeState, BadgeStateAccepted);
   AddInfoBar(/*has_badge=*/true);
   EXPECT_TRUE(infobar_badge_tab_delegate_.displayingBadge);
   EXPECT_TRUE(infobar_badge_tab_delegate_.badgeIsTappable);
-  EXPECT_FALSE(infobar_badge_tab_delegate_.badgeIsAccepted);
+  EXPECT_NE(infobar_badge_tab_delegate_.badgeState, BadgeStateAccepted);
   // Test that accepting the Infobar sets the badge to accepted state.
   tab_helper()->UpdateBadgeForInfobarAccepted(
       InfobarType::kInfobarTypePasswordSave);
   EXPECT_TRUE(infobar_badge_tab_delegate_.badgeIsTappable);
-  EXPECT_TRUE(infobar_badge_tab_delegate_.badgeIsAccepted);
+  EXPECT_EQ(infobar_badge_tab_delegate_.badgeState, BadgeStateAccepted);
 }
 
 // Test the badge state after doesn't change after adding an Infobar with no
@@ -236,11 +236,11 @@
 TEST_F(InfobarBadgeTabHelperTest, TestInfobarBadgeStateNoBadge) {
   EXPECT_FALSE(infobar_badge_tab_delegate_.displayingBadge);
   EXPECT_FALSE(infobar_badge_tab_delegate_.badgeIsTappable);
-  EXPECT_FALSE(infobar_badge_tab_delegate_.badgeIsAccepted);
+  EXPECT_NE(infobar_badge_tab_delegate_.badgeState, BadgeStateAccepted);
   AddInfoBar(/*has_badge=*/false);
   EXPECT_FALSE(infobar_badge_tab_delegate_.displayingBadge);
   EXPECT_FALSE(infobar_badge_tab_delegate_.badgeIsTappable);
-  EXPECT_FALSE(infobar_badge_tab_delegate_.badgeIsAccepted);
+  EXPECT_NE(infobar_badge_tab_delegate_.badgeState, BadgeStateAccepted);
 }
 
 // Tests that the InfobarBadge has not been removed after dismissing the
@@ -259,7 +259,7 @@
 // InfobarBanner.
 TEST_F(InfobarBadgeTabHelperTest, TestInfobarBadgeOnBannerAccepted) {
   AddInfoBar(/*has_badge=*/true);
-  EXPECT_FALSE(infobar_badge_tab_delegate_.badgeIsAccepted);
+  EXPECT_NE(infobar_badge_tab_delegate_.badgeState, BadgeStateAccepted);
   tab_helper()->UpdateBadgeForInfobarAccepted(
       InfobarType::kInfobarTypePasswordSave);
   [infobar_container_coordinator_ dismissBanner];
@@ -267,7 +267,7 @@
       base::test::ios::kWaitForUIElementTimeout, ^bool {
         return !infobar_container_coordinator_.bannerIsPresenting;
       }));
-  EXPECT_TRUE(infobar_badge_tab_delegate_.badgeIsAccepted);
+  EXPECT_EQ(infobar_badge_tab_delegate_.badgeState, BadgeStateAccepted);
 }
 
 // Test that removing the InfobarView doesn't stop displaying the badge.
diff --git a/ios/chrome/browser/ui/authentication/cells/BUILD.gn b/ios/chrome/browser/ui/authentication/cells/BUILD.gn
index 37c857e..ee6359bd 100644
--- a/ios/chrome/browser/ui/authentication/cells/BUILD.gn
+++ b/ios/chrome/browser/ui/authentication/cells/BUILD.gn
@@ -7,8 +7,6 @@
 source_set("cells") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
-    "account_control_item.h",
-    "account_control_item.mm",
     "signin_promo_view.h",
     "signin_promo_view.mm",
     "signin_promo_view_configurator.h",
@@ -44,7 +42,6 @@
   configs += [ "//build/config/compiler:enable_arc" ]
   testonly = true
   sources = [
-    "account_control_item_unittest.mm",
     "signin_promo_view_unittest.mm",
     "table_view_account_item_unittest.mm",
   ]
diff --git a/ios/chrome/browser/ui/authentication/cells/account_control_item.h b/ios/chrome/browser/ui/authentication/cells/account_control_item.h
deleted file mode 100644
index c257d13..0000000
--- a/ios/chrome/browser/ui/authentication/cells/account_control_item.h
+++ /dev/null
@@ -1,36 +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 IOS_CHROME_BROWSER_UI_AUTHENTICATION_CELLS_ACCOUNT_CONTROL_ITEM_H_
-#define IOS_CHROME_BROWSER_UI_AUTHENTICATION_CELLS_ACCOUNT_CONTROL_ITEM_H_
-
-#import <UIKit/UIKit.h>
-
-#import "ios/chrome/browser/ui/table_view/cells/table_view_item.h"
-
-// Item for account collection view and sign-in confirmation view.
-@interface AccountControlItem : TableViewItem
-
-// If this image should be tinted to match the text color (e.g. in dark mode),
-// the provided image should have rendering mode
-// UIImageRenderingModeAlwaysTemplate.
-@property(nonatomic, strong) UIImage* image;
-@property(nonatomic, copy) NSString* text;
-@property(nonatomic, copy) NSString* detailText;
-@property(nonatomic, assign) BOOL shouldDisplayError;
-
-
-@end
-
-// Cell for account settings view with a leading imageView, title text label,
-// and detail text label. The imageView is top-leading aligned.
-@interface AccountControlCell : TableViewCell
-
-@property(nonatomic, readonly, strong) UIImageView* imageView;
-@property(nonatomic, readonly, strong) UILabel* textLabel;
-@property(nonatomic, readonly, strong) UILabel* detailTextLabel;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_AUTHENTICATION_CELLS_ACCOUNT_CONTROL_ITEM_H_
diff --git a/ios/chrome/browser/ui/authentication/cells/account_control_item.mm b/ios/chrome/browser/ui/authentication/cells/account_control_item.mm
deleted file mode 100644
index e3d9b55..0000000
--- a/ios/chrome/browser/ui/authentication/cells/account_control_item.mm
+++ /dev/null
@@ -1,182 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/authentication/cells/account_control_item.h"
-
-#include "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h"
-#import "ios/chrome/browser/ui/util/uikit_ui_util.h"
-#import "ios/chrome/common/colors/UIColor+cr_semantic_colors.h"
-#import "ios/chrome/common/colors/semantic_color_names.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-@implementation AccountControlItem
-
-- (instancetype)initWithType:(NSInteger)type {
-  self = [super initWithType:type];
-  if (self) {
-    self.cellClass = [AccountControlCell class];
-    self.accessibilityTraits |= UIAccessibilityTraitButton;
-  }
-  return self;
-}
-
-#pragma mark - TableViewItem
-
-- (void)configureCell:(AccountControlCell*)cell
-           withStyler:(ChromeTableViewStyler*)styler {
-  [super configureCell:cell withStyler:styler];
-  cell.imageView.image = self.image;
-  cell.imageView.tintColor = UIColor.cr_labelColor;
-
-  cell.textLabel.text = self.text;
-  cell.textLabel.textColor = UIColor.cr_labelColor;
-
-  cell.detailTextLabel.text = self.detailText;
-  cell.detailTextLabel.textColor = self.shouldDisplayError
-                                       ? [UIColor colorNamed:kRedColor]
-                                       : UIColor.cr_secondaryLabelColor;
-}
-
-#pragma mark - Helper methods
-
-- (NSAttributedString*)attributedStringForText:(NSString*)text
-                                          font:(UIFont*)font
-                                         color:(UIColor*)color {
-  NSMutableParagraphStyle* paragraphStyle =
-      [[NSMutableParagraphStyle alloc] init];
-  paragraphStyle.lineHeightMultiple = 1.15;
-  return [[NSAttributedString alloc]
-      initWithString:text
-          attributes:@{
-            NSParagraphStyleAttributeName : paragraphStyle,
-            NSFontAttributeName : font,
-            NSForegroundColorAttributeName : color
-          }];
-}
-
-@end
-
-@interface AccountControlCell () {
-  // Constraint used to set padding between image and text when image exists.
-  NSLayoutConstraint* _textLeadingAnchorConstraint;
-}
-@end
-
-@implementation AccountControlCell
-
-@synthesize imageView = _imageView;
-@synthesize textLabel = _textLabel;
-@synthesize detailTextLabel = _detailTextLabel;
-
-- (instancetype)initWithStyle:(UITableViewCellStyle)style
-              reuseIdentifier:(NSString*)reuseIdentifier {
-  self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
-  if (self) {
-    self.isAccessibilityElement = YES;
-    [self addSubviews];
-    [self setViewConstraints];
-  }
-  return self;
-}
-
-// Create and add subviews.
-- (void)addSubviews {
-  UIView* contentView = self.contentView;
-  contentView.clipsToBounds = YES;
-
-  _imageView = [[UIImageView alloc] init];
-  _imageView.translatesAutoresizingMaskIntoConstraints = NO;
-  [_imageView
-      setContentCompressionResistancePriority:UILayoutPriorityDefaultHigh + 1
-                                      forAxis:UILayoutConstraintAxisHorizontal];
-  [contentView addSubview:_imageView];
-
-  _textLabel = [[UILabel alloc] init];
-  _textLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
-  _textLabel.adjustsFontForContentSizeCategory = YES;
-  _textLabel.translatesAutoresizingMaskIntoConstraints = NO;
-  [contentView addSubview:_textLabel];
-
-  _detailTextLabel = [[UILabel alloc] init];
-  _detailTextLabel.font =
-      [UIFont preferredFontForTextStyle:kTableViewSublabelFontStyle];
-  _detailTextLabel.adjustsFontForContentSizeCategory = YES;
-  _detailTextLabel.translatesAutoresizingMaskIntoConstraints = NO;
-  _detailTextLabel.numberOfLines = 0;
-  [contentView addSubview:_detailTextLabel];
-}
-
-// Set constraints on subviews.
-- (void)setViewConstraints {
-  UIView* contentView = self.contentView;
-
-  _textLeadingAnchorConstraint = [_textLabel.leadingAnchor
-      constraintEqualToAnchor:_imageView.trailingAnchor];
-
-  [NSLayoutConstraint activateConstraints:@[
-    // Set leading anchors.
-    [_imageView.leadingAnchor
-        constraintEqualToAnchor:contentView.leadingAnchor
-                       constant:kTableViewHorizontalSpacing],
-    [_detailTextLabel.leadingAnchor
-        constraintEqualToAnchor:_textLabel.leadingAnchor],
-    _textLeadingAnchorConstraint,
-
-    // Set vertical anchors.
-    [_textLabel.topAnchor
-        constraintEqualToAnchor:contentView.topAnchor
-                       constant:kTableViewLargeVerticalSpacing],
-    [_textLabel.bottomAnchor
-        constraintEqualToAnchor:_detailTextLabel.topAnchor
-                       constant:-kTableViewVerticalSpacing],
-    [_imageView.centerYAnchor constraintEqualToAnchor:_textLabel.centerYAnchor],
-    [_detailTextLabel.bottomAnchor
-        constraintEqualToAnchor:contentView.bottomAnchor
-                       constant:-kTableViewLargeVerticalSpacing],
-
-    // Set trailing anchors.
-    [_textLabel.trailingAnchor
-        constraintLessThanOrEqualToAnchor:contentView.trailingAnchor
-                                 constant:-kTableViewHorizontalSpacing],
-    [_detailTextLabel.trailingAnchor
-        constraintLessThanOrEqualToAnchor:contentView.trailingAnchor
-                                 constant:-kTableViewHorizontalSpacing],
-  ]];
-}
-
-#pragma mark - UIView
-
-- (void)layoutSubviews {
-  [super layoutSubviews];
-
-  // Adjust the text label preferredMaxLayoutWidth when the parent's width
-  // changes, for instance on screen rotation.
-  if (_imageView.image) {
-    _textLeadingAnchorConstraint.constant = kTableViewHorizontalSpacing;
-  } else {
-    _textLeadingAnchorConstraint.constant = 0;
-  }
-}
-
-#pragma mark - UITableViewCell
-
-- (void)prepareForReuse {
-  [super prepareForReuse];
-  self.imageView.image = nil;
-  self.textLabel.text = nil;
-  self.detailTextLabel.text = nil;
-  self.detailTextLabel.textColor = UIColor.cr_secondaryLabelColor;
-}
-
-#pragma mark - NSObject(Accessibility)
-
-- (NSString*)accessibilityLabel {
-  return [NSString stringWithFormat:@"%@, %@", self.textLabel.text,
-                                    self.detailTextLabel.text];
-}
-
-@end
diff --git a/ios/chrome/browser/ui/authentication/cells/account_control_item_unittest.mm b/ios/chrome/browser/ui/authentication/cells/account_control_item_unittest.mm
deleted file mode 100644
index 6f8e623..0000000
--- a/ios/chrome/browser/ui/authentication/cells/account_control_item_unittest.mm
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/authentication/cells/account_control_item.h"
-
-#include "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h"
-#import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h"
-#import "ios/chrome/browser/ui/util/uikit_ui_util.h"
-#import "ios/chrome/common/colors/UIColor+cr_semantic_colors.h"
-#import "ios/chrome/common/colors/semantic_color_names.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-using AccountControlItemTest = PlatformTest;
-
-// Tests that the cell is properly configured with image and texts after a call
-// to |configureCell:withStyler:|. All other cell decorations are default.
-TEST_F(AccountControlItemTest, ConfigureCellDefault) {
-  AccountControlItem* item = [[AccountControlItem alloc] initWithType:0];
-  UIImage* image = [[UIImage alloc] init];
-  NSString* mainText = @"Main text";
-  NSString* detailText = @"Detail text";
-
-  item.image = image;
-  item.text = mainText;
-  item.detailText = detailText;
-
-  id cell = [[[item cellClass] alloc] init];
-  ASSERT_TRUE([cell isMemberOfClass:[AccountControlCell class]]);
-
-  AccountControlCell* accountCell = cell;
-  [accountCell prepareForReuse];
-  EXPECT_FALSE(accountCell.imageView.image);
-  EXPECT_FALSE(accountCell.textLabel.text);
-  EXPECT_FALSE(accountCell.detailTextLabel.text);
-  EXPECT_EQ(UITableViewCellAccessoryNone, accountCell.accessoryType);
-  EXPECT_NSEQ(UIColor.cr_secondaryLabelColor,
-              accountCell.detailTextLabel.textColor);
-
-  [item configureCell:cell withStyler:[[ChromeTableViewStyler alloc] init]];
-  EXPECT_NSEQ(image, accountCell.imageView.image);
-  EXPECT_NSEQ(mainText, accountCell.textLabel.text);
-  EXPECT_NSEQ(detailText, accountCell.detailTextLabel.text);
-  EXPECT_EQ(UITableViewCellAccessoryNone, accountCell.accessoryType);
-  EXPECT_NSEQ(UIColor.cr_secondaryLabelColor,
-              accountCell.detailTextLabel.textColor);
-}
-
-// Tests that the cell is properly configured with error and an accessory after
-// a call to |configureCell:withStyler:|.
-TEST_F(AccountControlItemTest, ConfigureCellWithErrorAndAccessory) {
-  AccountControlItem* item = [[AccountControlItem alloc] initWithType:0];
-  UIImage* image = [[UIImage alloc] init];
-  NSString* mainText = @"Main text";
-  NSString* detailText = @"Detail text";
-
-  item.image = image;
-  item.text = mainText;
-  item.detailText = detailText;
-  item.accessoryType = UITableViewCellAccessoryCheckmark;
-  item.shouldDisplayError = YES;
-
-  id cell = [[[item cellClass] alloc] init];
-  ASSERT_TRUE([cell isMemberOfClass:[AccountControlCell class]]);
-
-  AccountControlCell* accountCell = cell;
-  [accountCell prepareForReuse];
-  EXPECT_FALSE(accountCell.imageView.image);
-  EXPECT_FALSE(accountCell.textLabel.text);
-  EXPECT_FALSE(accountCell.detailTextLabel.text);
-  EXPECT_EQ(UITableViewCellAccessoryNone, accountCell.accessoryType);
-  EXPECT_NSEQ(UIColor.cr_secondaryLabelColor,
-              accountCell.detailTextLabel.textColor);
-
-  [item configureCell:cell withStyler:[[ChromeTableViewStyler alloc] init]];
-  EXPECT_NSEQ(image, accountCell.imageView.image);
-  EXPECT_NSEQ(mainText, accountCell.textLabel.text);
-  EXPECT_NSEQ(detailText, accountCell.detailTextLabel.text);
-  EXPECT_EQ(UITableViewCellAccessoryCheckmark, accountCell.accessoryType);
-  EXPECT_NSEQ([UIColor colorNamed:kRedColor],
-              accountCell.detailTextLabel.textColor);
-}
diff --git a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
index b8f5c7a..38cbf86 100644
--- a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
+++ b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
@@ -200,7 +200,6 @@
     _currentState = NULL_STATE;
 
     self.modalPresentationStyle = UIModalPresentationFormSheet;
-    self.presentationController.delegate = self;
   }
   return self;
 }
@@ -857,6 +856,18 @@
   [self updateGradientColors];
   [[_gradientView layer] insertSublayer:_gradientLayer atIndex:0];
   [self.view addSubview:_gradientView];
+  if (!self.navigationController) {
+    // If the view controller is part of a navigation controller, there is no
+    // need to be the presentation delegate. The point to be the delegate is to
+    // receive notification when the view is swiped to be dismissed.
+    // The view cannot be swiped away if it is inside a navigation controller.
+    // In that case, the ChromeSigninViewController is leaked because of some
+    // iOS bug. See crbug.com/1004695.
+    // This view controller is presented by itself for signin-in, and it is
+    // presented inside a navigation view controller when being part of the
+    // first run.
+    self.presentationController.delegate = self;
+  }
 }
 
 - (void)viewWillAppear:(BOOL)animated {
diff --git a/ios/chrome/browser/ui/badges/badge_item.h b/ios/chrome/browser/ui/badges/badge_item.h
index c14bde0..fc39cbb 100644
--- a/ios/chrome/browser/ui/badges/badge_item.h
+++ b/ios/chrome/browser/ui/badges/badge_item.h
@@ -9,6 +9,15 @@
 
 #import "ios/chrome/browser/ui/badges/badge_type.h"
 
+// States for the InfobarBadge.
+typedef NS_ENUM(NSInteger, BadgeState) {
+  // The badge is not accepted.
+  BadgeStateNone = 0,
+  // The Infobar Badge is accepted. e.g. The Infobar was accepted/confirmed, and
+  // the Infobar action has taken place.
+  BadgeStateAccepted,
+};
+
 // Holds properties and values the UI needs to configure a badge button.
 @protocol BadgeItem
 
@@ -19,8 +28,8 @@
 - (BOOL)isFullScreen;
 // Some badges may not be tappable if there is no action associated with it.
 @property(nonatomic, assign, readonly, getter=isTappable) BOOL tappable;
-// Whether this badge is in an accepted state.
-@property(nonatomic, assign, getter=isAccepted) BOOL accepted;
+// The BadgeState of the badge.
+@property(nonatomic, assign) BadgeState badgeState;
 
 @end
 
diff --git a/ios/chrome/browser/ui/badges/badge_mediator.mm b/ios/chrome/browser/ui/badges/badge_mediator.mm
index 8d1f648a..e52367a 100644
--- a/ios/chrome/browser/ui/badges/badge_mediator.mm
+++ b/ios/chrome/browser/ui/badges/badge_mediator.mm
@@ -89,7 +89,7 @@
 - (void)updateInfobarBadge:(id<BadgeItem>)badgeItem {
   for (id<BadgeItem> item in self.badges) {
     if (item.badgeType == badgeItem.badgeType) {
-      item.accepted = badgeItem.accepted;
+      item.badgeState = badgeItem.badgeState;
       [self updateBadgesShown];
       return;
     }
diff --git a/ios/chrome/browser/ui/badges/badge_mediator_unittest.mm b/ios/chrome/browser/ui/badges/badge_mediator_unittest.mm
index 57014df..a759447 100644
--- a/ios/chrome/browser/ui/badges/badge_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/badges/badge_mediator_unittest.mm
@@ -39,8 +39,7 @@
 
   void AddInfobar(InfobarType infobar_type) {
     InfobarBadgeModel* new_badge =
-        [[InfobarBadgeModel alloc] initWithInfobarType:infobar_type
-                                              accepted:NO];
+        [[InfobarBadgeModel alloc] initWithInfobarType:infobar_type];
     infobar_badge_models_[infobar_type] = new_badge;
     [delegate_ addInfobarBadge:new_badge];
   }
@@ -183,11 +182,11 @@
   AddAndActivateWebState(0, false);
   AddInfobar();
   ASSERT_TRUE(badge_consumer_.displayedBadge);
-  EXPECT_FALSE(badge_consumer_.displayedBadge.accepted);
+  EXPECT_NE(badge_consumer_.displayedBadge.badgeState, BadgeStateAccepted);
 
   GetFakeInfobarBadgeTabHelper()->UpdateBadgeForInfobarAccepted(
       InfobarType::kInfobarTypePasswordSave);
-  EXPECT_TRUE(badge_consumer_.displayedBadge.accepted);
+  EXPECT_EQ(badge_consumer_.displayedBadge.badgeState, BadgeStateAccepted);
 }
 
 // Test that the BadgeMediator adds an incognito badge when the webstatelist
diff --git a/ios/chrome/browser/ui/badges/badge_static_item.mm b/ios/chrome/browser/ui/badges/badge_static_item.mm
index 3873cce..4faf36d6 100644
--- a/ios/chrome/browser/ui/badges/badge_static_item.mm
+++ b/ios/chrome/browser/ui/badges/badge_static_item.mm
@@ -21,14 +21,14 @@
 // Synthesized from protocol.
 @synthesize tappable = _tappable;
 // Sythesized from protocol.
-@synthesize accepted = _accepted;
+@synthesize badgeState = _badgeState;
 
 - (instancetype)initWithBadgeType:(BadgeType)badgeType {
   self = [super init];
   if (self) {
     _badgeType = badgeType;
     _tappable = NO;
-    _accepted = NO;
+    _badgeState = BadgeStateNone;
   }
   return self;
 }
diff --git a/ios/chrome/browser/ui/badges/badge_tappable_item.mm b/ios/chrome/browser/ui/badges/badge_tappable_item.mm
index 2ba50f697..977dde3 100644
--- a/ios/chrome/browser/ui/badges/badge_tappable_item.mm
+++ b/ios/chrome/browser/ui/badges/badge_tappable_item.mm
@@ -21,14 +21,14 @@
 // Synthesized from protocol.
 @synthesize tappable = _tappable;
 // Synthesized from protocol.
-@synthesize accepted = _accepted;
+@synthesize badgeState = _badgeState;
 
 - (instancetype)initWithBadgeType:(BadgeType)badgeType {
   self = [super init];
   if (self) {
     _badgeType = badgeType;
     _tappable = YES;
-    _accepted = NO;
+    _badgeState = BadgeStateNone;
   }
   return self;
 }
diff --git a/ios/chrome/browser/ui/badges/badge_view_controller.mm b/ios/chrome/browser/ui/badges/badge_view_controller.mm
index 867975a..73d239e 100644
--- a/ios/chrome/browser/ui/badges/badge_view_controller.mm
+++ b/ios/chrome/browser/ui/badges/badge_view_controller.mm
@@ -76,7 +76,8 @@
   if (displayedBadgeItem) {
     BadgeButton* newButton = [self.buttonFactory
         getBadgeButtonForBadgeType:displayedBadgeItem.badgeType];
-    [newButton setAccepted:displayedBadgeItem.accepted animated:NO];
+    [newButton setAccepted:displayedBadgeItem.badgeState == BadgeStateAccepted
+                  animated:NO];
     self.displayedBadge = newButton;
   }
   if (fullscreenBadgeItem) {
@@ -101,12 +102,14 @@
   if (displayedBadgeItem) {
     if (self.displayedBadge &&
         self.displayedBadge.badgeType == displayedBadgeItem.badgeType) {
-      [self.displayedBadge setAccepted:displayedBadgeItem.accepted
-                              animated:YES];
+      [self.displayedBadge
+          setAccepted:displayedBadgeItem.badgeState == BadgeStateAccepted
+             animated:YES];
     } else {
       BadgeButton* newButton = [self.buttonFactory
           getBadgeButtonForBadgeType:displayedBadgeItem.badgeType];
-      [newButton setAccepted:displayedBadgeItem.accepted animated:NO];
+      [newButton setAccepted:displayedBadgeItem.badgeState == BadgeStateAccepted
+                    animated:NO];
       self.displayedBadge = newButton;
     }
   } else {
diff --git a/ios/chrome/browser/ui/dialogs/javascript_dialog_egtest.mm b/ios/chrome/browser/ui/dialogs/javascript_dialog_egtest.mm
index 7ac9f2f6..6b6c48f33 100644
--- a/ios/chrome/browser/ui/dialogs/javascript_dialog_egtest.mm
+++ b/ios/chrome/browser/ui/dialogs/javascript_dialog_egtest.mm
@@ -575,6 +575,11 @@
 
 // Tests that an alert is presented after a new tab animation is finished.
 - (void)testShowJavaScriptAfterNewTabAnimation {
+  // TODO(crbug.com/1007986) Test flaky on iOS13.
+  if (@available(iOS 13, *)) {
+    EARL_GREY_TEST_DISABLED(@"Test disabled on iOS13.");
+  }
+
   // Load the test page with a link to kOnLoadAlertURL and long tap on the link.
   [self loadPageWithLink];
 
diff --git a/ios/chrome/browser/ui/infobars/banners/infobar_banner_constants.h b/ios/chrome/browser/ui/infobars/banners/infobar_banner_constants.h
index 5c3dbf3..5d8411b 100644
--- a/ios/chrome/browser/ui/infobars/banners/infobar_banner_constants.h
+++ b/ios/chrome/browser/ui/infobars/banners/infobar_banner_constants.h
@@ -11,5 +11,7 @@
 extern NSString* const kInfobarBannerViewIdentifier;
 // Accessibility identifier of the Banner Accept Button.
 extern NSString* const kInfobarBannerAcceptButtonIdentifier;
+// Accessibility identifier of the Banner Open Modal Button.
+extern NSString* const kInfobarBannerOpenModalButtonIdentifier;
 
 #endif  // IOS_CHROME_BROWSER_UI_INFOBARS_BANNERS_INFOBAR_BANNER_CONSTANTS_H_
diff --git a/ios/chrome/browser/ui/infobars/banners/infobar_banner_constants.mm b/ios/chrome/browser/ui/infobars/banners/infobar_banner_constants.mm
index 8cd64997..e5a43ce3 100644
--- a/ios/chrome/browser/ui/infobars/banners/infobar_banner_constants.mm
+++ b/ios/chrome/browser/ui/infobars/banners/infobar_banner_constants.mm
@@ -11,3 +11,5 @@
 NSString* const kInfobarBannerViewIdentifier = @"kInfobarBannerViewIdentifier";
 NSString* const kInfobarBannerAcceptButtonIdentifier =
     @"kInfobarBannerAcceptButtonIdentifier";
+NSString* const kInfobarBannerOpenModalButtonIdentifier =
+    @"kInfobarBannerOpenModalButtonIdentifier";
diff --git a/ios/chrome/browser/ui/infobars/banners/infobar_banner_view_controller.mm b/ios/chrome/browser/ui/infobars/banners/infobar_banner_view_controller.mm
index 3383209f5..f16f96b 100644
--- a/ios/chrome/browser/ui/infobars/banners/infobar_banner_view_controller.mm
+++ b/ios/chrome/browser/ui/infobars/banners/infobar_banner_view_controller.mm
@@ -38,8 +38,9 @@
 const CGFloat kButtonMaxFontSize = 45;
 
 // Container Stack constants.
-const CGFloat kContainerStackSpacing = 18.0;
+const CGFloat kContainerStackSpacing = 10.0;
 const CGFloat kContainerStackVerticalPadding = 18.0;
+const CGFloat kContainerStackHorizontalPadding = 18.0;
 
 // Icon constants.
 const CGFloat kIconWidth = 25.0;
@@ -124,11 +125,13 @@
   self.view.accessibilityCustomActions = [self accessibilityActions];
 
   // Icon setup.
-  self.iconImage = [self.iconImage
-      imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
-  UIImageView* iconImageView =
-      [[UIImageView alloc] initWithImage:self.iconImage];
-  iconImageView.contentMode = UIViewContentModeScaleAspectFit;
+  UIImageView* iconImageView = nil;
+  if (self.iconImage) {
+    self.iconImage = [self.iconImage
+        imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
+    iconImageView = [[UIImageView alloc] initWithImage:self.iconImage];
+    iconImageView.contentMode = UIViewContentModeScaleAspectFit;
+  }
 
   // Labels setup.
   self.titleLabel = [[UILabel alloc] init];
@@ -161,6 +164,8 @@
       scaledFontForFont:[UIFont
                             preferredFontForTextStyle:UIFontTextStyleHeadline]
        maximumPointSize:kButtonMaxFontSize];
+  self.infobarButton.titleLabel.numberOfLines = 0;
+  self.infobarButton.titleLabel.textAlignment = NSTextAlignmentCenter;
   [self.infobarButton addTarget:self
                          action:@selector(bannerInfobarButtonWasPressed:)
                forControlEvents:UIControlEventTouchUpInside];
@@ -173,9 +178,36 @@
   [self.infobarButton addSubview:buttonSeparator];
 
   // Container Stack setup.
-  UIStackView* containerStack = [[UIStackView alloc] initWithArrangedSubviews:@[
-    iconImageView, labelsStackView, self.infobarButton
-  ]];
+  UIStackView* containerStack = [[UIStackView alloc] init];
+  // Check if it should have an icon.
+  if (iconImageView) {
+    [containerStack addArrangedSubview:iconImageView];
+    [iconImageView.widthAnchor constraintEqualToConstant:kIconWidth].active =
+        YES;
+  }
+  // Add labels.
+  [containerStack addArrangedSubview:labelsStackView];
+  // Check if it should have an Open Modal button.
+  if (self.presentsModal) {
+    // Open Modal Button setup.
+    UIButton* openModalButton = [UIButton buttonWithType:UIButtonTypeSystem];
+    UIImage* gearImage = [[UIImage imageNamed:@"infobar_settings_icon"]
+        imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
+    [openModalButton setImage:gearImage forState:UIControlStateNormal];
+    openModalButton.tintColor = [UIColor colorNamed:kTextSecondaryColor];
+    [openModalButton addTarget:self
+                        action:@selector(animateBannerTappedAndPresentModal)
+              forControlEvents:UIControlEventTouchUpInside];
+    [openModalButton
+        setContentHuggingPriority:UILayoutPriorityDefaultHigh
+                          forAxis:UILayoutConstraintAxisHorizontal];
+    openModalButton.accessibilityIdentifier =
+        kInfobarBannerOpenModalButtonIdentifier;
+    [containerStack addArrangedSubview:openModalButton];
+  }
+  // Add accept button.
+  [containerStack addArrangedSubview:self.infobarButton];
+  // Configure it.
   containerStack.axis = UILayoutConstraintAxisHorizontal;
   containerStack.spacing = kContainerStackSpacing;
   containerStack.distribution = UIStackViewDistributionFill;
@@ -192,14 +224,12 @@
     // Container Stack.
     [containerStack.leadingAnchor
         constraintEqualToAnchor:self.view.leadingAnchor
-                       constant:kContainerStackSpacing],
+                       constant:kContainerStackHorizontalPadding],
     [containerStack.trailingAnchor
         constraintEqualToAnchor:self.view.trailingAnchor],
     [containerStack.topAnchor constraintEqualToAnchor:self.view.topAnchor],
     [containerStack.bottomAnchor
         constraintEqualToAnchor:self.view.bottomAnchor],
-    // Icon.
-    [iconImageView.widthAnchor constraintEqualToConstant:kIconWidth],
     // Button.
     [self.infobarButton.widthAnchor constraintEqualToConstant:kButtonWidth],
     [buttonSeparator.widthAnchor
@@ -224,14 +254,6 @@
   longPressGestureRecognizer.minimumPressDuration =
       kLongPressTimeDurationInSeconds;
   [self.view addGestureRecognizer:longPressGestureRecognizer];
-
-  if (self.presentsModal) {
-    UITapGestureRecognizer* tapGestureRecognizer =
-        [[UITapGestureRecognizer alloc]
-            initWithTarget:self
-                    action:@selector(animateBannerTappedAndPresentModal)];
-    [self.view addGestureRecognizer:tapGestureRecognizer];
-  }
 }
 
 - (void)viewDidAppear:(BOOL)animated {
diff --git a/ios/chrome/browser/ui/settings/BUILD.gn b/ios/chrome/browser/ui/settings/BUILD.gn
index 7317c1a..17ce1e34 100644
--- a/ios/chrome/browser/ui/settings/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/BUILD.gn
@@ -89,7 +89,6 @@
     "resources:settings_payment_methods",
     "resources:settings_privacy",
     "resources:settings_search_engine",
-    "resources:settings_sync",
     "resources:settings_voice_search",
     "resources:sync_and_google_services",
     "resources:sync_and_google_services_sync_error",
diff --git a/ios/chrome/browser/ui/settings/google_services/BUILD.gn b/ios/chrome/browser/ui/settings/google_services/BUILD.gn
index 53205d53..c79d37f9 100644
--- a/ios/chrome/browser/ui/settings/google_services/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/google_services/BUILD.gn
@@ -92,7 +92,6 @@
     "//components/prefs",
     "//components/strings",
     "//components/sync",
-    "//components/unified_consent",
     "//ios/chrome/app:app_internal",
     "//ios/chrome/app/strings",
     "//ios/chrome/browser",
diff --git a/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm b/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm
index 5f48c836..336d86f4c 100644
--- a/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm
+++ b/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm
@@ -11,7 +11,6 @@
 #include "components/sync/driver/sync_service.h"
 #include "components/sync/engine/sync_encryption_handler.h"
 #include "components/sync/protocol/proto_value_conversions.h"
-#include "components/unified_consent/feature.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory.h"
 #include "ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory_util.h"
@@ -19,7 +18,6 @@
 #import "ios/chrome/browser/signin/authentication_service_factory.h"
 #include "ios/chrome/browser/sync/profile_sync_service_factory.h"
 #include "ios/chrome/browser/system_flags.h"
-#import "ios/chrome/browser/ui/authentication/cells/account_control_item.h"
 #import "ios/chrome/browser/ui/authentication/signin_earl_grey_ui.h"
 #import "ios/chrome/browser/ui/authentication/signin_earlgrey_utils.h"
 #include "ios/chrome/grit/ios_strings.h"
@@ -70,9 +68,6 @@
   [SigninEarlGreyUI signinWithIdentity:identity];
   [ChromeEarlGreyUI openSettingsMenu];
   [ChromeEarlGreyUI tapSettingsMenuButton:SettingsAccountButton()];
-  if (!unified_consent::IsUnifiedConsentFeatureEnabled()) {
-    [ChromeEarlGreyUI tapAccountsMenuButton:AccountsSyncButton()];
-  }
 
   // Forget |identity|, screens should be popped back to the Main Settings.
   [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
@@ -146,52 +141,6 @@
       performAction:grey_tap()];
 }
 
-// Tests that the Sync Settings screen is correctly reloaded when one of the
-// secondary accounts disappears.
-- (void)testSignInReloadSyncOnForgetIdentity {
-  if (unified_consent::IsUnifiedConsentFeatureEnabled()) {
-    EARL_GREY_TEST_DISABLED(
-        @"Sync section was moved to the Sync and Google services settings "
-         "screen, so it is no longer present in the account settings screen. "
-         "This test is now covered by GoogleServicesSettingsTestCase.");
-  }
-
-  ios::FakeChromeIdentityService* identity_service =
-      ios::FakeChromeIdentityService::GetInstanceFromChromeProvider();
-  ChromeIdentity* identity1 = [SigninEarlGreyUtils fakeIdentity1];
-  ChromeIdentity* identity2 = [SigninEarlGreyUtils fakeIdentity2];
-  identity_service->AddIdentity(identity2);
-
-  // Sign In |identity|, then open the Sync Settings.
-  [SigninEarlGreyUI signinWithIdentity:identity1];
-  [ChromeEarlGreyUI openSettingsMenu];
-  [ChromeEarlGreyUI tapSettingsMenuButton:SettingsAccountButton()];
-  [ChromeEarlGreyUI tapAccountsMenuButton:AccountsSyncButton()];
-
-  // Forget |identity2|, allowing the UI to synchronize before and after
-  // forgetting the identity.
-  [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
-  identity_service->ForgetIdentity(identity2, nil);
-  [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
-
-  // Check that both |identity1| and |identity2| aren't shown in the Sync
-  // Settings.
-  [[EarlGrey
-      selectElementWithMatcher:grey_allOf(
-                                   grey_accessibilityLabel(identity1.userEmail),
-                                   grey_sufficientlyVisible(), nil)]
-      assertWithMatcher:grey_nil()];
-  [[EarlGrey
-      selectElementWithMatcher:grey_allOf(
-                                   grey_accessibilityLabel(identity2.userEmail),
-                                   grey_sufficientlyVisible(), nil)]
-      assertWithMatcher:grey_nil()];
-  [SigninEarlGreyUtils checkSignedInWithIdentity:identity1];
-
-  [[EarlGrey selectElementWithMatcher:SettingsDoneButton()]
-      performAction:grey_tap()];
-}
-
 // Tests that the Account Settings screen is popped and the user signed out
 // when the account is removed.
 - (void)testSignOutOnRemoveAccount {
@@ -247,92 +196,4 @@
       performAction:grey_tap()];
 }
 
-// Checks if the sync cell is correctly configured with the expected detail text
-// label and an image.
-- (void)checkSyncCellWithExpectedTextLabelCallback:
-    (ExpectedTextLabelCallback)callback {
-  NSAssert(callback, @"Need callback");
-  NSAssert(!unified_consent::IsUnifiedConsentFeatureEnabled(),
-           @"Only runs when unified consent is disabled");
-  ChromeIdentity* identity = [SigninEarlGreyUtils fakeIdentity1];
-
-  // Sign In |identity|, then open the Account Settings.
-  [SigninEarlGreyUI signinWithIdentity:identity];
-  [ChromeEarlGreyUI openSettingsMenu];
-  [ChromeEarlGreyUI tapSettingsMenuButton:SettingsAccountButton()];
-
-  NSString* expectedDetailTextLabel = callback([identity userEmail]);
-  // Check that account sync button displays the expected detail text label and
-  // an image.
-  GREYPerformBlock block = ^BOOL(id element, NSError* __strong* errorOrNil) {
-    GREYAssertTrue([element isKindOfClass:[AccountControlCell class]],
-                   @"Should be AccountControlCell type");
-    AccountControlCell* cell = static_cast<AccountControlCell*>(element);
-    return
-        [cell.detailTextLabel.text isEqualToString:expectedDetailTextLabel] &&
-        cell.imageView.image != nil;
-  };
-  [[EarlGrey selectElementWithMatcher:AccountsSyncButton()]
-      performAction:[GREYActionBlock
-                        actionWithName:@"Invoke clearStateForTest selector"
-                          performBlock:block]];
-}
-
-// Tests the sync cell is correctly configured when having a MDM error.
-- (void)testMDMError {
-  if (unified_consent::IsUnifiedConsentFeatureEnabled()) {
-    EARL_GREY_TEST_DISABLED(
-        @"Sync section was moved to the Sync and Google services settings "
-         "screen, so it is no longer present in the account settings screen. "
-         "This test is now covered by GoogleServicesSettingsTestCase.");
-  }
-  ios::FakeChromeIdentityService* fakeChromeIdentityService =
-      ios::FakeChromeIdentityService::GetInstanceFromChromeProvider();
-  fakeChromeIdentityService->SetFakeMDMError(true);
-  ExpectedTextLabelCallback callback = ^(NSString* identityEmail) {
-    return l10n_util::GetNSString(IDS_IOS_OPTIONS_ACCOUNTS_SYNC_ERROR);
-  };
-  [self checkSyncCellWithExpectedTextLabelCallback:callback];
-}
-
-// Tests the sync cell is correctly configured when no error.
-- (void)testSyncItemWithSyncingMessage {
-  if (unified_consent::IsUnifiedConsentFeatureEnabled()) {
-    EARL_GREY_TEST_DISABLED(
-        @"Sync section was moved to the Sync and Google services settings "
-         "screen, so it is no longer present in the account settings screen. "
-         "This test is now covered by GoogleServicesSettingsTestCase.");
-  }
-
-  ExpectedTextLabelCallback callback = ^(NSString* identityEmail) {
-    return l10n_util::GetNSStringF(IDS_IOS_SIGN_IN_TO_CHROME_SETTING_SYNCING,
-                                   base::SysNSStringToUTF16(identityEmail));
-  };
-  [self checkSyncCellWithExpectedTextLabelCallback:callback];
-}
-
-// Tests the sync cell is correctly configured when the passphrase is required.
-- (void)testSyncItemWithPassphraseRequired {
-  if (unified_consent::IsUnifiedConsentFeatureEnabled()) {
-    EARL_GREY_TEST_DISABLED(
-        @"Sync section was moved to the Sync and Google services settings "
-         "screen, so it is no longer present in the account settings screen. "
-         "This test is now covered by GoogleServicesSettingsTestCase.");
-  }
-
-  ExpectedTextLabelCallback callback = ^(NSString* identityEmail) {
-    ios::ChromeBrowserState* browser_state =
-        chrome_test_util::GetOriginalBrowserState();
-    syncer::ProfileSyncService* profile_sync_service =
-        ProfileSyncServiceFactory::GetAsProfileSyncServiceForBrowserState(
-            browser_state);
-    profile_sync_service->GetEncryptionObserverForTest()->OnPassphraseRequired(
-        syncer::REASON_DECRYPTION,
-        syncer::KeyDerivationParams::CreateForPbkdf2(),
-        sync_pb::EncryptedData());
-    return l10n_util::GetNSString(IDS_IOS_SYNC_ENCRYPTION_DESCRIPTION);
-  };
-  [self checkSyncCellWithExpectedTextLabelCallback:callback];
-}
-
 @end
diff --git a/ios/chrome/browser/ui/settings/google_services/accounts_table_view_controller.mm b/ios/chrome/browser/ui/settings/google_services/accounts_table_view_controller.mm
index 0f625ec..ffdf772 100644
--- a/ios/chrome/browser/ui/settings/google_services/accounts_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/google_services/accounts_table_view_controller.mm
@@ -12,25 +12,21 @@
 #import "components/signin/public/identity_manager/objc/identity_manager_observer_bridge.h"
 #include "components/strings/grit/components_strings.h"
 #include "components/sync/driver/sync_service.h"
-#include "components/unified_consent/feature.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/signin/authentication_service.h"
 #include "ios/chrome/browser/signin/authentication_service_factory.h"
 #import "ios/chrome/browser/signin/chrome_identity_service_observer_bridge.h"
 #include "ios/chrome/browser/signin/identity_manager_factory.h"
 #include "ios/chrome/browser/sync/profile_sync_service_factory.h"
-#import "ios/chrome/browser/sync/sync_observer_bridge.h"
 #include "ios/chrome/browser/sync/sync_setup_service.h"
 #include "ios/chrome/browser/sync/sync_setup_service_factory.h"
 #import "ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h"
-#import "ios/chrome/browser/ui/authentication/cells/account_control_item.h"
 #import "ios/chrome/browser/ui/authentication/cells/table_view_account_item.h"
 #import "ios/chrome/browser/ui/authentication/resized_avatar_cache.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
 #import "ios/chrome/browser/ui/icons/chrome_icon.h"
 #import "ios/chrome/browser/ui/settings/cells/settings_text_item.h"
-#import "ios/chrome/browser/ui/settings/sync/sync_settings_table_view_controller.h"
 #import "ios/chrome/browser/ui/settings/sync/utils/sync_util.h"
 #import "ios/chrome/browser/ui/signin_interaction/signin_interaction_coordinator.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_detail_text_item.h"
@@ -70,8 +66,6 @@
 typedef NS_ENUM(NSInteger, ItemType) {
   ItemTypeAccount = kItemTypeEnumZero,
   ItemTypeAddAccount,
-  ItemTypeSync,
-  ItemTypeGoogleActivityControls,
   ItemTypeSignOut,
   ItemTypeHeader,
 };
@@ -81,11 +75,9 @@
 @interface AccountsTableViewController () <
     ChromeIdentityServiceObserver,
     ChromeIdentityBrowserOpener,
-    IdentityManagerObserverBridgeDelegate,
-    SyncObserverModelBridge> {
+    IdentityManagerObserverBridgeDelegate> {
   ios::ChromeBrowserState* _browserState;  // weak
   BOOL _closeSettingsOnAddAccount;
-  std::unique_ptr<SyncObserverBridge> _syncObserver;
   std::unique_ptr<signin::IdentityManagerObserverBridge>
       _identityManagerObserver;
   // Modal alert for sign out.
@@ -132,26 +124,9 @@
   if (self) {
     _browserState = browserState;
     _closeSettingsOnAddAccount = closeSettingsOnAddAccount;
-    syncer::SyncService* syncService =
-        ProfileSyncServiceFactory::GetForBrowserState(_browserState);
-    if (!unified_consent::IsUnifiedConsentFeatureEnabled()) {
-      // When unified consent flag is enabled, the sync settings are available
-      // in the "Google Services and sync" settings.
-      _syncObserver.reset(new SyncObserverBridge(self, syncService));
-    }
     _identityManagerObserver =
         std::make_unique<signin::IdentityManagerObserverBridge>(
             IdentityManagerFactory::GetForBrowserState(_browserState), self);
-    [[NSNotificationCenter defaultCenter]
-        addObserver:self
-           selector:@selector(willStartSwitchAccount)
-               name:kSwitchAccountWillStartNotification
-             object:nil];
-    [[NSNotificationCenter defaultCenter]
-        addObserver:self
-           selector:@selector(didFinishSwitchAccount)
-               name:kSwitchAccountDidFinishNotification
-             object:nil];
     _avatarCache = [[ResizedAvatarCache alloc] init];
     _identityServiceObserver.reset(
         new ChromeIdentityServiceObserverBridge(self));
@@ -169,7 +144,6 @@
 
 - (void)stopBrowserStateServiceObservers {
   _identityManagerObserver.reset();
-  _syncObserver.reset();
 }
 
 #pragma mark - SettingsControllerProtocol
@@ -235,17 +209,6 @@
   [model addItem:[self addAccountItem]
       toSectionWithIdentifier:SectionIdentifierAccounts];
 
-  if (!unified_consent::IsUnifiedConsentFeatureEnabled()) {
-    // Sync and Google Activity section.
-    // When unified consent flag is enabled, those settings are available in
-    // the Google Services and sync settings.
-    [model addSectionWithIdentifier:SectionIdentifierSync];
-    [model addItem:[self syncItem]
-        toSectionWithIdentifier:SectionIdentifierSync];
-    [model addItem:[self googleActivityControlsItem]
-        toSectionWithIdentifier:SectionIdentifierSync];
-  }
-
   // Sign out section.
   [model addSectionWithIdentifier:SectionIdentifierSignOut];
   [model addItem:[self signOutItem]
@@ -286,82 +249,11 @@
   return item;
 }
 
-- (TableViewItem*)syncItem {
-  AccountControlItem* item =
-      [[AccountControlItem alloc] initWithType:ItemTypeSync];
-  item.text = l10n_util::GetNSString(IDS_IOS_OPTIONS_ACCOUNTS_SYNC_TITLE);
-  item.accessibilityIdentifier = kSettingsAccountsTableViewSyncCellId;
-  [self updateSyncItem:item];
-  item.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
-  return item;
-}
-
-// Updates the sync item according to the sync status (in progress, sync error,
-// mdm error, sync disabled or sync enabled).
-- (void)updateSyncItem:(AccountControlItem*)syncItem {
-  SyncSetupService* syncSetupService =
-      SyncSetupServiceFactory::GetForBrowserState(_browserState);
-  if (!syncSetupService->HasFinishedInitialSetup()) {
-    syncItem.image = [UIImage imageNamed:@"settings_sync"];
-    syncItem.detailText =
-        l10n_util::GetNSString(IDS_IOS_SYNC_SETUP_IN_PROGRESS);
-    syncItem.shouldDisplayError = NO;
-    return;
-  }
-
-  ChromeIdentity* identity = [self authService] -> GetAuthenticatedIdentity();
-  if (!IsTransientSyncError(syncSetupService->GetSyncServiceState())) {
-    // Sync error.
-    syncItem.shouldDisplayError = YES;
-    NSString* errorMessage =
-        GetSyncErrorDescriptionForSyncSetupService(syncSetupService);
-    DCHECK(errorMessage);
-    syncItem.image = [UIImage imageNamed:@"settings_error"];
-    syncItem.detailText = errorMessage;
-  } else if ([self authService] -> HasCachedMDMErrorForIdentity(identity)) {
-    // MDM error.
-    syncItem.shouldDisplayError = YES;
-    syncItem.image = [UIImage imageNamed:@"settings_error"];
-    syncItem.detailText =
-        l10n_util::GetNSString(IDS_IOS_OPTIONS_ACCOUNTS_SYNC_ERROR);
-  } else if (!syncSetupService->IsSyncEnabled()) {
-    // Sync disabled.
-    syncItem.shouldDisplayError = NO;
-    syncItem.image = [UIImage imageNamed:@"settings_sync"];
-    syncItem.detailText =
-        l10n_util::GetNSString(IDS_IOS_OPTIONS_ACCOUNTS_SYNC_IS_OFF);
-  } else {
-    // Sync enabled.
-    syncItem.shouldDisplayError = NO;
-    syncItem.image = [UIImage imageNamed:@"settings_sync"];
-    syncItem.detailText =
-        l10n_util::GetNSStringF(IDS_IOS_SIGN_IN_TO_CHROME_SETTING_SYNCING,
-                                base::SysNSStringToUTF16([identity userEmail]));
-  }
-}
-
-- (TableViewItem*)googleActivityControlsItem {
-  AccountControlItem* item =
-      [[AccountControlItem alloc] initWithType:ItemTypeGoogleActivityControls];
-  item.text = l10n_util::GetNSString(IDS_IOS_OPTIONS_ACCOUNTS_GOOGLE_TITLE);
-  item.detailText =
-      l10n_util::GetNSString(IDS_IOS_OPTIONS_ACCOUNTS_GOOGLE_DESCRIPTION);
-  item.image = ios::GetChromeBrowserProvider()
-                   ->GetBrandedImageProvider()
-                   ->GetAccountsListActivityControlsImage();
-  item.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
-  return item;
-}
-
 - (TableViewItem*)signOutItem {
   TableViewDetailTextItem* item =
       [[TableViewDetailTextItem alloc] initWithType:ItemTypeSignOut];
-  if (unified_consent::IsUnifiedConsentFeatureEnabled()) {
-    item.text =
-        l10n_util::GetNSString(IDS_IOS_OPTIONS_ACCOUNTS_SIGN_OUT_TURN_OFF_SYNC);
-  } else {
-    item.text = l10n_util::GetNSString(IDS_IOS_OPTIONS_ACCOUNTS_SIGNOUT);
-  }
+  item.text =
+      l10n_util::GetNSString(IDS_IOS_OPTIONS_ACCOUNTS_SIGN_OUT_TURN_OFF_SYNC);
   item.accessibilityTraits |= UIAccessibilityTraitButton;
   item.accessibilityIdentifier = kSettingsAccountsTableViewSignoutCellId;
   return item;
@@ -387,12 +279,6 @@
     case ItemTypeAddAccount:
       [self showAddAccount];
       break;
-    case ItemTypeSync:
-      [self showSyncSettings];
-      break;
-    case ItemTypeGoogleActivityControls:
-      [self showGoogleActivitySettings];
-      break;
     case ItemTypeSignOut:
       [self showDisconnect];
       break;
@@ -403,29 +289,6 @@
   [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
 }
 
-#pragma mark - SyncObserverModelBridge
-
-- (void)onSyncStateChanged {
-  if (![self authService] -> IsAuthenticated()) {
-    // Ignore sync state changed notification if signed out.
-    return;
-  }
-
-  NSIndexPath* index =
-      [self.tableViewModel indexPathForItemType:ItemTypeSync
-                              sectionIdentifier:SectionIdentifierSync];
-
-  TableViewModel* model = self.tableViewModel;
-  if ([model numberOfSections] > index.section &&
-      [model numberOfItemsInSection:index.section] > index.row) {
-    AccountControlItem* item = base::mac::ObjCCastStrict<AccountControlItem>(
-        [model itemAtIndexPath:index]);
-    [self updateSyncItem:item];
-    [self.tableView reloadRowsAtIndexPaths:@[ index ]
-                          withRowAnimation:UITableViewRowAnimationAutomatic];
-  }
-}
-
 #pragma mark - IdentityManagerObserverBridgeDelegate
 
 - (void)onEndBatchOfRefreshTokenStateChanges {
@@ -438,38 +301,6 @@
   }
 }
 
-#pragma mark - Sync and Activity Controls
-
-- (void)showSyncSettings {
-  if ([_alertCoordinator isVisible])
-    return;
-
-  if ([self authService]
-      -> ShowMDMErrorDialogForIdentity(
-          [self authService] -> GetAuthenticatedIdentity())) {
-    // If there is an MDM error for the synced identity, show it instead.
-    return;
-  }
-
-  SyncSettingsTableViewController* controllerToPush =
-      [[SyncSettingsTableViewController alloc]
-            initWithBrowserState:_browserState
-          allowSwitchSyncAccount:YES];
-  controllerToPush.dispatcher = self.dispatcher;
-  [self.navigationController pushViewController:controllerToPush animated:YES];
-}
-
-- (void)showGoogleActivitySettings {
-  if ([_alertCoordinator isVisible])
-    return;
-  base::RecordAction(base::UserMetricsAction(
-      "Signin_AccountSettings_GoogleActivityControlsClicked"));
-  ios::GetChromeBrowserProvider()
-      ->GetChromeIdentityService()
-      ->PresentWebAndAppSettingDetailsController(
-          [self authService] -> GetAuthenticatedIdentity(), self, YES);
-}
-
 #pragma mark - Authentication operations
 
 - (void)showAddAccount {
@@ -534,22 +365,14 @@
     std::string hosted_domain = accountInfo.has_value()
                                     ? accountInfo.value().hosted_domain
                                     : std::string();
-    if (unified_consent::IsUnifiedConsentFeatureEnabled()) {
-      title =
-          l10n_util::GetNSString(IDS_IOS_MANAGED_DISCONNECT_DIALOG_TITLE_UNITY);
-      message =
-          l10n_util::GetNSStringF(IDS_IOS_MANAGED_DISCONNECT_DIALOG_INFO_UNITY,
-                                  base::UTF8ToUTF16(hosted_domain));
-      continueButtonTitle = l10n_util::GetNSString(
-          IDS_IOS_MANAGED_DISCONNECT_DIALOG_ACCEPT_UNITY);
-    } else {
-      title = l10n_util::GetNSString(IDS_IOS_MANAGED_DISCONNECT_DIALOG_TITLE);
-      message = l10n_util::GetNSStringF(IDS_IOS_MANAGED_DISCONNECT_DIALOG_INFO,
-                                        base::UTF8ToUTF16(hosted_domain));
-      continueButtonTitle =
-          l10n_util::GetNSString(IDS_IOS_MANAGED_DISCONNECT_DIALOG_ACCEPT);
-    }
-  } else if (unified_consent::IsUnifiedConsentFeatureEnabled()) {
+    title =
+        l10n_util::GetNSString(IDS_IOS_MANAGED_DISCONNECT_DIALOG_TITLE_UNITY);
+    message =
+        l10n_util::GetNSStringF(IDS_IOS_MANAGED_DISCONNECT_DIALOG_INFO_UNITY,
+                                base::UTF8ToUTF16(hosted_domain));
+    continueButtonTitle =
+        l10n_util::GetNSString(IDS_IOS_MANAGED_DISCONNECT_DIALOG_ACCEPT_UNITY);
+  } else {
     title = l10n_util::GetNSString(IDS_IOS_DISCONNECT_DIALOG_TITLE_UNITY);
     message =
         l10n_util::GetNSString(IDS_IOS_DISCONNECT_DIALOG_INFO_MOBILE_UNITY);
@@ -627,16 +450,6 @@
   return AuthenticationServiceFactory::GetForBrowserState(_browserState);
 }
 
-#pragma mark - Switch accounts notifications
-
-- (void)willStartSwitchAccount {
-  _authenticationOperationInProgress = YES;
-}
-
-- (void)didFinishSwitchAccount {
-  [self handleAuthenticationOperationDidFinish];
-}
-
 #pragma mark - ChromeIdentityBrowserOpener
 
 - (void)openURL:(NSURL*)url
diff --git a/ios/chrome/browser/ui/settings/google_services/google_services_settings_egtest.mm b/ios/chrome/browser/ui/settings/google_services/google_services_settings_egtest.mm
index 3a29784c..9920202 100644
--- a/ios/chrome/browser/ui/settings/google_services/google_services_settings_egtest.mm
+++ b/ios/chrome/browser/ui/settings/google_services/google_services_settings_egtest.mm
@@ -6,7 +6,6 @@
 #import <XCTest/XCTest.h>
 
 #include "components/prefs/pref_service.h"
-#include "components/unified_consent/feature.h"
 #import "ios/chrome/app/main_controller.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/tabs/tab_model.h"
@@ -65,13 +64,6 @@
 
 @implementation GoogleServicesSettingsTestCase
 
-- (void)setUp {
-  [super setUp];
-
-  CHECK(unified_consent::IsUnifiedConsentFeatureEnabled())
-      << "This test suite must be run with Unified Consent feature enabled.";
-}
-
 // Opens the Google services settings view, and closes it.
 - (void)testOpenGoogleServicesSettings {
   [self openGoogleServicesSettings];
diff --git a/ios/chrome/browser/ui/settings/resources/BUILD.gn b/ios/chrome/browser/ui/settings/resources/BUILD.gn
index dfe0806..8259221 100644
--- a/ios/chrome/browser/ui/settings/resources/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/resources/BUILD.gn
@@ -46,15 +46,6 @@
   ]
 }
 
-imageset("settings_sync") {
-  sources = [
-    "settings_sync.imageset/Contents.json",
-    "settings_sync.imageset/settings_sync.png",
-    "settings_sync.imageset/settings_sync@2x.png",
-    "settings_sync.imageset/settings_sync@3x.png",
-  ]
-}
-
 imageset("settings_about_chrome") {
   sources = [
     "settings_about_chrome.imageset/Contents.json",
diff --git a/ios/chrome/browser/ui/settings/resources/settings_sync.imageset/Contents.json b/ios/chrome/browser/ui/settings/resources/settings_sync.imageset/Contents.json
deleted file mode 100644
index 191001f..0000000
--- a/ios/chrome/browser/ui/settings/resources/settings_sync.imageset/Contents.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "1x",
-            "filename": "settings_sync.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "settings_sync@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "settings_sync@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/settings/resources/settings_sync.imageset/settings_sync.png b/ios/chrome/browser/ui/settings/resources/settings_sync.imageset/settings_sync.png
deleted file mode 100644
index 66a60f9..0000000
--- a/ios/chrome/browser/ui/settings/resources/settings_sync.imageset/settings_sync.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/settings/resources/settings_sync.imageset/settings_sync@2x.png b/ios/chrome/browser/ui/settings/resources/settings_sync.imageset/settings_sync@2x.png
deleted file mode 100644
index 89c2950..0000000
--- a/ios/chrome/browser/ui/settings/resources/settings_sync.imageset/settings_sync@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/settings/resources/settings_sync.imageset/settings_sync@3x.png b/ios/chrome/browser/ui/settings/resources/settings_sync.imageset/settings_sync@3x.png
deleted file mode 100644
index ca88d21..0000000
--- a/ios/chrome/browser/ui/settings/resources/settings_sync.imageset/settings_sync@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/settings/sync/BUILD.gn b/ios/chrome/browser/ui/settings/sync/BUILD.gn
index 94d8f90..86c82d6 100644
--- a/ios/chrome/browser/ui/settings/sync/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/sync/BUILD.gn
@@ -11,8 +11,6 @@
     "sync_encryption_passphrase_table_view_controller.mm",
     "sync_encryption_table_view_controller.h",
     "sync_encryption_table_view_controller.mm",
-    "sync_settings_table_view_controller.h",
-    "sync_settings_table_view_controller.mm",
   ]
   deps = [
     "//base",
@@ -61,7 +59,6 @@
     "sync_create_passphrase_table_view_controller_unittest.mm",
     "sync_encryption_passphrase_table_view_controller_unittest.mm",
     "sync_encryption_table_view_controller_unittest.mm",
-    "sync_settings_table_view_controller_unittest.mm",
   ]
   deps = [
     ":sync",
diff --git a/ios/chrome/browser/ui/settings/sync/sync_settings_table_view_controller.h b/ios/chrome/browser/ui/settings/sync/sync_settings_table_view_controller.h
deleted file mode 100644
index 4070d86..0000000
--- a/ios/chrome/browser/ui/settings/sync/sync_settings_table_view_controller.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_SYNC_SYNC_SETTINGS_TABLE_VIEW_CONTROLLER_H_
-#define IOS_CHROME_BROWSER_UI_SETTINGS_SYNC_SYNC_SETTINGS_TABLE_VIEW_CONTROLLER_H_
-
-#import "ios/chrome/browser/ui/settings/settings_root_table_view_controller.h"
-
-namespace ios {
-class ChromeBrowserState;
-}  // namespace ios
-
-// The a11y identifier of the view controller's view.
-extern NSString* const kSettingsSyncId;
-// Notification when a switch account operation will start.
-extern NSString* const kSwitchAccountWillStartNotification;
-// Notification when a switch account operation did finish.
-extern NSString* const kSwitchAccountDidFinishNotification;
-
-@interface SyncSettingsTableViewController : SettingsRootTableViewController
-
-// |browserState| must not be nil.
-// |allowSwitchSyncAccount| indicates whether switching sync account is allowed
-// on the screen.
-- (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
-              allowSwitchSyncAccount:(BOOL)allowSwitchSyncAccount
-    NS_DESIGNATED_INITIALIZER;
-- (instancetype)initWithTableViewStyle:(UITableViewStyle)style
-                           appBarStyle:
-                               (ChromeTableViewControllerStyle)appBarStyle
-    NS_UNAVAILABLE;
-
-@end
-
-@interface SyncSettingsTableViewController (UsedForTesting)
-// Returns YES if a sync error cell should be displayed.
-- (BOOL)shouldDisplaySyncError;
-// Return YES if the Sync settings should be disabled because of a Sync error.
-- (BOOL)shouldDisableSettingsOnSyncError;
-// Returns YES if the encryption cell should display an error.
-- (BOOL)shouldDisplayEncryptionError;
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_SETTINGS_SYNC_SYNC_SETTINGS_TABLE_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/settings/sync/sync_settings_table_view_controller.mm b/ios/chrome/browser/ui/settings/sync/sync_settings_table_view_controller.mm
deleted file mode 100644
index b581f69b..0000000
--- a/ios/chrome/browser/ui/settings/sync/sync_settings_table_view_controller.mm
+++ /dev/null
@@ -1,1053 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/settings/sync/sync_settings_table_view_controller.h"
-
-#include <memory>
-
-#include "base/auto_reset.h"
-#include "base/mac/foundation_util.h"
-#include "components/autofill/core/common/autofill_prefs.h"
-#include "components/google/core/common/google_util.h"
-#include "components/prefs/pref_service.h"
-#import "components/signin/public/identity_manager/objc/identity_manager_observer_bridge.h"
-#include "components/strings/grit/components_strings.h"
-#include "components/sync/base/model_type.h"
-#include "components/sync/driver/sync_service.h"
-#include "components/sync/driver/sync_user_settings.h"
-#include "components/unified_consent/feature.h"
-#include "ios/chrome/browser/application_context.h"
-#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#include "ios/chrome/browser/chrome_url_constants.h"
-#import "ios/chrome/browser/signin/authentication_service.h"
-#include "ios/chrome/browser/signin/authentication_service_factory.h"
-#import "ios/chrome/browser/signin/chrome_identity_service_observer_bridge.h"
-#include "ios/chrome/browser/signin/identity_manager_factory.h"
-#include "ios/chrome/browser/sync/profile_sync_service_factory.h"
-#include "ios/chrome/browser/sync/sync_setup_service.h"
-#include "ios/chrome/browser/sync/sync_setup_service_factory.h"
-#include "ios/chrome/browser/system_flags.h"
-#import "ios/chrome/browser/ui/authentication/authentication_flow.h"
-#import "ios/chrome/browser/ui/authentication/cells/table_view_account_item.h"
-#import "ios/chrome/browser/ui/authentication/resized_avatar_cache.h"
-#import "ios/chrome/browser/ui/commands/application_commands.h"
-#import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
-#import "ios/chrome/browser/ui/commands/show_signin_command.h"
-#import "ios/chrome/browser/ui/settings/cells/settings_switch_cell.h"
-#import "ios/chrome/browser/ui/settings/cells/sync_switch_item.h"
-#import "ios/chrome/browser/ui/settings/settings_navigation_controller.h"
-#import "ios/chrome/browser/ui/settings/sync/sync_encryption_passphrase_table_view_controller.h"
-#import "ios/chrome/browser/ui/settings/sync/sync_encryption_table_view_controller.h"
-#import "ios/chrome/browser/ui/settings/sync/utils/sync_util.h"
-#import "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h"
-#import "ios/chrome/browser/ui/table_view/cells/table_view_image_item.h"
-#import "ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.h"
-#import "ios/chrome/browser/ui/table_view/cells/table_view_text_item.h"
-#import "ios/chrome/browser/ui/table_view/table_view_model.h"
-#include "ios/chrome/browser/ui/ui_feature_flags.h"
-#import "ios/chrome/browser/ui/util/uikit_ui_util.h"
-#import "ios/chrome/common/colors/UIColor+cr_semantic_colors.h"
-#include "ios/chrome/grit/ios_strings.h"
-#import "ios/public/provider/chrome/browser/chrome_browser_provider.h"
-#import "ios/public/provider/chrome/browser/signin/chrome_identity.h"
-#import "ios/public/provider/chrome/browser/signin/chrome_identity_service.h"
-#include "ui/base/l10n/l10n_util_mac.h"
-#include "url/gurl.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-// The a11y identifier of the view controller's view.
-NSString* const kSettingsSyncId = @"kSettingsSyncId";
-// Notification when a switch account operation will start.
-NSString* const kSwitchAccountWillStartNotification =
-    @"kSwitchAccountWillStartNotification";
-// Notification when a switch account operation did finish.
-NSString* const kSwitchAccountDidFinishNotification =
-    @"kSwitchAccountDidFinishNotification";
-// Used to tag and retrieve ItemTypeSyncableDataType cell tags.
-const NSInteger kTagShift = 1000;
-
-namespace {
-
-typedef NS_ENUM(NSInteger, SectionIdentifier) {
-  SectionIdentifierSyncError = kSectionIdentifierEnumZero,
-  SectionIdentifierEnableSync,
-  SectionIdentifierSyncAccounts,
-  SectionIdentifierSyncServices,
-  SectionIdentifierEncryptionAndFooter,
-};
-
-typedef NS_ENUM(NSInteger, ItemType) {
-  ItemTypeSyncError = kItemTypeEnumZero,
-  ItemTypeSyncSwitch,
-  ItemTypeAccount,
-  ItemTypeSyncEverything,
-  ItemTypeSyncableDataType,
-  ItemTypeAutofillWalletImport,
-  ItemTypeEncryption,
-  ItemTypeManageSyncedData,
-  ItemTypeHeader,
-};
-
-}  // namespace
-
-@interface SyncSettingsTableViewController () <
-    ChromeIdentityServiceObserver,
-    IdentityManagerObserverBridgeDelegate,
-    SettingsControllerProtocol,
-    SyncObserverModelBridge> {
-  ios::ChromeBrowserState* _browserState;  // Weak.
-  SyncSetupService* _syncSetupService;     // Weak.
-  std::unique_ptr<SyncObserverBridge> _syncObserver;
-  std::unique_ptr<signin::IdentityManagerObserverBridge>
-      _identityManagerObserver;
-  AuthenticationFlow* _authenticationFlow;
-  // Whether switching sync account is allowed on the screen.
-  BOOL _allowSwitchSyncAccount;
-  // Whether an authentication operation is in progress (e.g switch accounts).
-  BOOL _authenticationOperationInProgress;
-  // Whether Sync State changes should be currently ignored.
-  BOOL _ignoreSyncStateChanges;
-
-  // Cache for Identity items avatar images.
-  ResizedAvatarCache* _avatarCache;
-  std::unique_ptr<ChromeIdentityServiceObserverBridge> _identityServiceObserver;
-  // Enable lookup of item corresponding to a given identity GAIA ID string.
-  NSDictionary<NSString*, TableViewItem*>* _identityMap;
-}
-
-// Stops observing browser state services.
-- (void)stopBrowserStateServiceObservers;
-// Pops the view if user is signed out and not authentication operation is in
-// progress. Returns YES if the view was popped.
-- (BOOL)popViewIfSignedOut;
-
-// Returns a switch item for sync, set to on if |isOn| is YES.
-- (TableViewItem*)syncSwitchItem:(BOOL)isOn;
-// Returns an item for sync errors other than sync encryption.
-- (TableViewItem*)syncErrorItem;
-// Returns a switch item for sync everything, set to on if |isOn| is YES.
-- (TableViewItem*)syncEverythingSwitchItem:(BOOL)isOn;
-// Returns a switch item for the syncable data type |dataType|, set to on if
-// |IsDataTypePreferred| for that type returns true.
-- (TableViewItem*)switchItemForDataType:
-    (SyncSetupService::SyncableDatatype)dataType;
-// Returns a switch item for the Autofill wallet import setting.
-- (TableViewItem*)switchItemForAutofillWalletImport;
-// Returns an item for Encryption.
-- (TableViewItem*)encryptionCellItem;
-// Returns an item to open a link to manage the synced data.
-- (TableViewItem*)manageSyncedDataItem;
-
-// Action method for sync switch.
-- (void)changeSyncStatusToOn:(UISwitch*)sender;
-// Action method for the sync error cell.
-- (void)fixSyncErrorIfPossible;
-// Action method for the account cells.
-- (void)startSwitchAccountForIdentity:(ChromeIdentity*)identity
-                     postSignInAction:(PostSignInAction)postSigninAction;
-// Callback for switch account action method.
-- (void)didSwitchAccountWithSuccess:(BOOL)success;
-// Action method for the Sync Everything switch.
-- (void)changeSyncEverythingStatusToOn:(UISwitch*)sender;
-// Action method for the data type switches.
-- (void)changeDataTypeSyncStatusToOn:(UISwitch*)sender;
-// Action method for the Autofill wallet import switch.
-- (void)autofillWalletImportChanged:(UISwitch*)sender;
-// Action method for the encryption cell.
-- (void)showEncryption;
-
-// Updates the visual status of the screen (i.e. whether cells are enabled,
-// whether errors are displayed, ...).
-- (void)updateTableView;
-// Ensures the Sync error cell is shown when there is an error.
-- (void)updateSyncError;
-// Updates the Autofill wallet import cell (i.e. whether it is enabled and on).
-- (void)updateAutofillWalletImportCell;
-// Ensures the encryption cell displays an error if needed.
-- (void)updateEncryptionCell;
-// Updates the account item so it can reflect the latest state of the identity.
-- (void)updateAccountItem:(TableViewAccountItem*)item
-             withIdentity:(ChromeIdentity*)identity;
-
-// Returns whether the Sync Settings screen has an Accounts section, allowing
-// users to choose to which account they want to sync to.
-- (BOOL)hasAccountsSection;
-// Returns whether a sync error cell should be displayed.
-- (BOOL)shouldDisplaySyncError;
-// Returns whether the Sync settings should be disabled because of a Sync error.
-- (BOOL)shouldDisableSettingsOnSyncError;
-// Returns whether an error should be displayed on the encryption cell.
-- (BOOL)shouldDisplayEncryptionError;
-// Returns whether the existing sync error is fixable by a user action.
-- (BOOL)isSyncErrorFixableByUserAction;
-// Returns the ID to use to access the l10n string for the given data type.
-- (int)titleIdForSyncableDataType:(SyncSetupService::SyncableDatatype)datatype;
-// Returns whether the encryption item should be enabled.
-- (BOOL)shouldEncryptionItemBeEnabled;
-// Returns whether the sync everything item should be enabled.
-- (BOOL)shouldSyncEverythingItemBeEnabled;
-// Returns whether the data type items should be enabled.
-- (BOOL)shouldSyncableItemsBeEnabled;
-// Returns the tag for a data type switch based on its index path.
-- (NSInteger)tagForIndexPath:(NSIndexPath*)indexPath;
-// Returns the indexPath for a data type switch based on its tag.
-- (NSIndexPath*)indexPathForTag:(NSInteger)shiftedTag;
-
-// Whether the Autofill wallet import item should be enabled.
-@property(nonatomic, readonly, getter=isAutofillWalletImportItemEnabled)
-    BOOL autofillWalletImportItemEnabled;
-
-// Whether the Autofill wallet import item should be on.
-@property(nonatomic, assign, getter=isAutofillWalletImportOn)
-    BOOL autofillWalletImportOn;
-
-@end
-
-@implementation SyncSettingsTableViewController
-
-#pragma mark Initialization
-
-- (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
-              allowSwitchSyncAccount:(BOOL)allowSwitchSyncAccount {
-  DCHECK(!unified_consent::IsUnifiedConsentFeatureEnabled());
-  DCHECK(browserState);
-  UITableViewStyle style = base::FeatureList::IsEnabled(kSettingsRefresh)
-                               ? UITableViewStylePlain
-                               : UITableViewStyleGrouped;
-  self = [super initWithTableViewStyle:style
-                           appBarStyle:ChromeTableViewControllerStyleNoAppBar];
-  if (self) {
-    _allowSwitchSyncAccount = allowSwitchSyncAccount;
-    _browserState = browserState;
-    _syncSetupService =
-        SyncSetupServiceFactory::GetForBrowserState(_browserState);
-    self.title = l10n_util::GetNSString(IDS_IOS_SYNC_SETTING_TITLE);
-    syncer::SyncService* syncService =
-        ProfileSyncServiceFactory::GetForBrowserState(_browserState);
-    _syncObserver.reset(new SyncObserverBridge(self, syncService));
-    _identityManagerObserver.reset(new signin::IdentityManagerObserverBridge(
-        IdentityManagerFactory::GetForBrowserState(_browserState), self));
-    _avatarCache = [[ResizedAvatarCache alloc] init];
-    _identityServiceObserver.reset(
-        new ChromeIdentityServiceObserverBridge(self));
-  }
-  return self;
-}
-
-- (void)stopBrowserStateServiceObservers {
-  _syncObserver.reset();
-  _identityManagerObserver.reset();
-  _identityServiceObserver.reset();
-}
-
-- (BOOL)popViewIfSignedOut {
-  if (AuthenticationServiceFactory::GetForBrowserState(_browserState)
-          ->IsAuthenticated()) {
-    return NO;
-  }
-  if (_authenticationOperationInProgress) {
-    // The signed out state might be temporary (e.g. account switch, ...).
-    // Don't pop this view based on intermediary values.
-    return NO;
-  }
-  [self.navigationController popToViewController:self animated:NO];
-  [base::mac::ObjCCastStrict<SettingsNavigationController>(
-      self.navigationController) popViewControllerOrCloseSettingsAnimated:NO];
-  return YES;
-}
-
-#pragma mark View lifecycle
-
-- (void)viewDidLoad {
-  [super viewDidLoad];
-  self.tableView.accessibilityIdentifier = kSettingsSyncId;
-  [self loadModel];
-}
-
-- (void)viewWillAppear:(BOOL)animated {
-  [super viewWillAppear:animated];
-  [self updateEncryptionCell];
-}
-
-#pragma mark SettingsRootTableViewController
-
-- (void)loadModel {
-  [super loadModel];
-  TableViewModel* model = self.tableViewModel;
-
-  // SyncError section.
-  if ([self shouldDisplaySyncError]) {
-    [model addSectionWithIdentifier:SectionIdentifierSyncError];
-    [model addItem:[self syncErrorItem]
-        toSectionWithIdentifier:SectionIdentifierSyncError];
-  }
-
-  // Sync Section.
-  BOOL syncEnabled = _syncSetupService->IsSyncEnabled();
-  [model addSectionWithIdentifier:SectionIdentifierEnableSync];
-  [model addItem:[self syncSwitchItem:syncEnabled]
-      toSectionWithIdentifier:SectionIdentifierEnableSync];
-
-  // Sync to Section.
-  if ([self hasAccountsSection]) {
-    NSMutableDictionary<NSString*, TableViewItem*>* mutableIdentityMap =
-        [[NSMutableDictionary alloc] init];
-    // Accounts section. Cells enabled if sync is on.
-    [model addSectionWithIdentifier:SectionIdentifierSyncAccounts];
-    TableViewTextHeaderFooterItem* syncToHeader =
-        [[TableViewTextHeaderFooterItem alloc] initWithType:ItemTypeHeader];
-    syncToHeader.text = l10n_util::GetNSString(IDS_IOS_SYNC_TO_TITLE);
-    [model setHeader:syncToHeader
-        forSectionWithIdentifier:SectionIdentifierSyncAccounts];
-    auto* identity_manager =
-        IdentityManagerFactory::GetForBrowserState(_browserState);
-
-    for (const CoreAccountInfo& account :
-         identity_manager->GetAccountsWithRefreshTokens()) {
-      ChromeIdentity* identity = ios::GetChromeBrowserProvider()
-                                     ->GetChromeIdentityService()
-                                     ->GetIdentityWithGaiaID(account.gaia);
-      TableViewItem* accountItem = [self accountItem:identity];
-      [model addItem:accountItem
-          toSectionWithIdentifier:SectionIdentifierSyncAccounts];
-      [mutableIdentityMap setObject:accountItem forKey:identity.gaiaID];
-    }
-    _identityMap = mutableIdentityMap;
-  }
-
-  // Data Types to sync. Enabled if sync is on.
-  [model addSectionWithIdentifier:SectionIdentifierSyncServices];
-  TableViewTextHeaderFooterItem* syncServicesHeader =
-      [[TableViewTextHeaderFooterItem alloc] initWithType:ItemTypeHeader];
-  syncServicesHeader.text =
-      l10n_util::GetNSString(IDS_IOS_SYNC_DATA_TYPES_TITLE);
-  [model setHeader:syncServicesHeader
-      forSectionWithIdentifier:SectionIdentifierSyncServices];
-  BOOL syncEverythingEnabled = _syncSetupService->IsSyncingAllDataTypes();
-  [model addItem:[self syncEverythingSwitchItem:syncEverythingEnabled]
-      toSectionWithIdentifier:SectionIdentifierSyncServices];
-  // Specific Data Types to sync. Enabled if Sync Everything is off.
-  for (int i = 0; i < SyncSetupService::kNumberOfSyncableDatatypes; ++i) {
-    SyncSetupService::SyncableDatatype dataType =
-        static_cast<SyncSetupService::SyncableDatatype>(i);
-    [model addItem:[self switchItemForDataType:dataType]
-        toSectionWithIdentifier:SectionIdentifierSyncServices];
-  }
-  // Autofill wallet import switch.
-  [model addItem:[self switchItemForAutofillWalletImport]
-      toSectionWithIdentifier:SectionIdentifierSyncServices];
-
-  // Encryption section.  Enabled if sync is on.
-  [model addSectionWithIdentifier:SectionIdentifierEncryptionAndFooter];
-  [model addItem:[self encryptionCellItem]
-      toSectionWithIdentifier:SectionIdentifierEncryptionAndFooter];
-  [model addItem:[self manageSyncedDataItem]
-      toSectionWithIdentifier:SectionIdentifierEncryptionAndFooter];
-}
-
-#pragma mark - Model items
-
-- (TableViewItem*)syncSwitchItem:(BOOL)isOn {
-  SyncSwitchItem* syncSwitchItem = [self
-      switchItemWithType:ItemTypeSyncSwitch
-                   title:l10n_util::GetNSString(IDS_IOS_SYNC_SETTING_TITLE)
-                subTitle:l10n_util::GetNSString(
-                             IDS_IOS_SIGN_IN_TO_CHROME_SETTING_SUBTITLE)];
-  syncSwitchItem.on = isOn;
-  return syncSwitchItem;
-}
-
-- (TableViewItem*)syncErrorItem {
-  DCHECK([self shouldDisplaySyncError]);
-  TableViewAccountItem* syncErrorItem =
-      [[TableViewAccountItem alloc] initWithType:ItemTypeSyncError];
-  syncErrorItem.text = l10n_util::GetNSString(IDS_IOS_SYNC_ERROR_TITLE);
-  syncErrorItem.image = [UIImage imageNamed:@"settings_error"];
-  syncErrorItem.detailText = GetSyncErrorMessageForBrowserState(_browserState);
-  return syncErrorItem;
-}
-
-- (TableViewItem*)accountItem:(ChromeIdentity*)identity {
-  TableViewAccountItem* identityAccountItem =
-      [[TableViewAccountItem alloc] initWithType:ItemTypeAccount];
-  [self updateAccountItem:identityAccountItem withIdentity:identity];
-
-  identityAccountItem.mode = _syncSetupService->IsSyncEnabled()
-                                 ? TableViewAccountModeEnabled
-                                 : TableViewAccountModeDisabled;
-  ChromeIdentity* authenticatedIdentity =
-      AuthenticationServiceFactory::GetForBrowserState(_browserState)
-          ->GetAuthenticatedIdentity();
-  if (identity == authenticatedIdentity) {
-    identityAccountItem.accessoryType = UITableViewCellAccessoryCheckmark;
-  }
-  return identityAccountItem;
-}
-
-- (TableViewItem*)syncEverythingSwitchItem:(BOOL)isOn {
-  SyncSwitchItem* syncSwitchItem = [self
-      switchItemWithType:ItemTypeSyncEverything
-                   title:l10n_util::GetNSString(IDS_IOS_SYNC_EVERYTHING_TITLE)
-                subTitle:nil];
-  syncSwitchItem.on = isOn;
-  syncSwitchItem.enabled = [self shouldSyncEverythingItemBeEnabled];
-  return syncSwitchItem;
-}
-
-- (TableViewItem*)switchItemForDataType:
-    (SyncSetupService::SyncableDatatype)dataType {
-  syncer::ModelType modelType = _syncSetupService->GetModelType(dataType);
-  BOOL isOn = _syncSetupService->IsDataTypePreferred(modelType);
-
-  SyncSwitchItem* syncDataTypeItem =
-      [self switchItemWithType:ItemTypeSyncableDataType
-                         title:l10n_util::GetNSString(
-                                   [self titleIdForSyncableDataType:dataType])
-                      subTitle:nil];
-  syncDataTypeItem.dataType = dataType;
-  syncDataTypeItem.on = isOn;
-  syncDataTypeItem.enabled = [self shouldSyncableItemsBeEnabled];
-  return syncDataTypeItem;
-}
-
-- (TableViewItem*)switchItemForAutofillWalletImport {
-  NSString* title = l10n_util::GetNSString(
-      IDS_AUTOFILL_ENABLE_PAYMENTS_INTEGRATION_CHECKBOX_LABEL);
-  SyncSwitchItem* autofillWalletImportItem =
-      [self switchItemWithType:ItemTypeAutofillWalletImport
-                         title:title
-                      subTitle:nil];
-  autofillWalletImportItem.on = [self isAutofillWalletImportOn];
-  autofillWalletImportItem.enabled = [self isAutofillWalletImportItemEnabled];
-  return autofillWalletImportItem;
-}
-
-- (TableViewItem*)encryptionCellItem {
-  TableViewImageItem* encryptionCellItem =
-      [[TableViewImageItem alloc] initWithType:ItemTypeEncryption];
-  encryptionCellItem.title =
-      l10n_util::GetNSString(IDS_IOS_SYNC_ENCRYPTION_TITLE);
-  encryptionCellItem.accessoryType =
-      UITableViewCellAccessoryDisclosureIndicator;
-  encryptionCellItem.image = [self shouldDisplayEncryptionError]
-                                 ? [UIImage imageNamed:@"settings_error"]
-                                 : nil;
-  encryptionCellItem.enabled = [self shouldEncryptionItemBeEnabled];
-  encryptionCellItem.textColor = encryptionCellItem.enabled
-                                     ? UIColor.cr_labelColor
-                                     : UIColor.cr_secondaryLabelColor;
-  return encryptionCellItem;
-}
-
-- (TableViewItem*)manageSyncedDataItem {
-  TableViewTextItem* manageSyncedDataItem =
-      [[TableViewTextItem alloc] initWithType:ItemTypeManageSyncedData];
-  manageSyncedDataItem.text =
-      l10n_util::GetNSString(IDS_IOS_SYNC_RESET_GOOGLE_DASHBOARD_NO_LINK);
-  manageSyncedDataItem.accessibilityTraits |= UIAccessibilityTraitButton;
-  return manageSyncedDataItem;
-}
-
-#pragma mark Item Constructors
-
-- (SyncSwitchItem*)switchItemWithType:(NSInteger)type
-                                title:(NSString*)title
-                             subTitle:(NSString*)detailText {
-  SyncSwitchItem* switchItem = [[SyncSwitchItem alloc] initWithType:type];
-  switchItem.text = title;
-  switchItem.detailText = detailText;
-  return switchItem;
-}
-
-#pragma mark - UITableViewDataSource
-
-- (UITableViewCell*)tableView:(UITableView*)tableView
-        cellForRowAtIndexPath:(NSIndexPath*)indexPath {
-  UITableViewCell* cell = [super tableView:tableView
-                     cellForRowAtIndexPath:indexPath];
-  NSInteger itemType = [self.tableViewModel itemTypeForIndexPath:indexPath];
-
-  switch (itemType) {
-    case ItemTypeSyncError: {
-      TableViewAccountCell* accountCell =
-          base::mac::ObjCCastStrict<TableViewAccountCell>(cell);
-      accountCell.textLabel.textColor = UIColor.redColor;
-      accountCell.detailTextLabel.numberOfLines = 1;
-      break;
-    }
-    case ItemTypeSyncSwitch: {
-      SettingsSwitchCell* switchCell =
-          base::mac::ObjCCastStrict<SettingsSwitchCell>(cell);
-      [switchCell.switchView addTarget:self
-                                action:@selector(changeSyncStatusToOn:)
-                      forControlEvents:UIControlEventValueChanged];
-      break;
-    }
-    case ItemTypeSyncEverything: {
-      SettingsSwitchCell* switchCell =
-          base::mac::ObjCCastStrict<SettingsSwitchCell>(cell);
-      [switchCell.switchView
-                 addTarget:self
-                    action:@selector(changeSyncEverythingStatusToOn:)
-          forControlEvents:UIControlEventValueChanged];
-      break;
-    }
-    case ItemTypeSyncableDataType: {
-      SettingsSwitchCell* switchCell =
-          base::mac::ObjCCastStrict<SettingsSwitchCell>(cell);
-      [switchCell.switchView addTarget:self
-                                action:@selector(changeDataTypeSyncStatusToOn:)
-                      forControlEvents:UIControlEventValueChanged];
-      switchCell.switchView.tag = [self tagForIndexPath:indexPath];
-      break;
-    }
-    case ItemTypeAutofillWalletImport: {
-      SettingsSwitchCell* switchCell =
-          base::mac::ObjCCastStrict<SettingsSwitchCell>(cell);
-      [switchCell.switchView addTarget:self
-                                action:@selector(autofillWalletImportChanged:)
-                      forControlEvents:UIControlEventValueChanged];
-      break;
-    }
-    default:
-      break;
-  }
-  return cell;
-}
-
-#pragma mark UITableViewDelegate
-
-- (void)tableView:(UITableView*)tableView
-    didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
-  [super tableView:tableView didSelectRowAtIndexPath:indexPath];
-
-  NSInteger itemType = [self.tableViewModel itemTypeForIndexPath:indexPath];
-  switch (itemType) {
-    case ItemTypeSyncError:
-      [self fixSyncErrorIfPossible];
-      break;
-    case ItemTypeAccount: {
-      TableViewAccountItem* accountItem =
-          base::mac::ObjCCastStrict<TableViewAccountItem>(
-              [self.tableViewModel itemAtIndexPath:indexPath]);
-      if (!accountItem.accessoryType) {
-        [self startSwitchAccountForIdentity:accountItem.chromeIdentity
-                           postSignInAction:POST_SIGNIN_ACTION_NONE];
-      }
-      break;
-    }
-    case ItemTypeEncryption:
-      [self showEncryption];
-      break;
-    case ItemTypeManageSyncedData: {
-      GURL learnMoreUrl = google_util::AppendGoogleLocaleParam(
-          GURL(kSyncGoogleDashboardURL),
-          GetApplicationContext()->GetApplicationLocale());
-      OpenNewTabCommand* command =
-          [OpenNewTabCommand commandWithURLFromChrome:learnMoreUrl];
-      [self.dispatcher closeSettingsUIAndOpenURL:command];
-      break;
-    }
-    default:
-      break;
-  }
-}
-
-#pragma mark - Actions
-
-- (void)changeSyncStatusToOn:(UISwitch*)sender {
-  if (self.navigationController.topViewController != self) {
-    // Workaround for timing issue when taping on a switch and the error or
-    // encryption cells. See crbug.com/647678.
-    return;
-  }
-
-  BOOL isOn = sender.isOn;
-  BOOL wasOn = _syncSetupService->IsSyncEnabled();
-  if (wasOn == isOn)
-    return;
-
-  base::AutoReset<BOOL> autoReset(&_ignoreSyncStateChanges, YES);
-  _syncSetupService->SetSyncEnabled(isOn);
-
-  BOOL isNowOn = _syncSetupService->IsSyncEnabled();
-  if (isNowOn == wasOn) {
-    DLOG(WARNING) << "Call to SetSyncEnabled(" << (isOn ? "YES" : "NO")
-                  << ") failed.";
-    // This shouldn't happen, but in case there was an underlying sync problem,
-    // make sure the UI reflects sync's reality.
-    NSIndexPath* indexPath =
-        [self.tableViewModel indexPathForItemType:ItemTypeSyncSwitch
-                                sectionIdentifier:SectionIdentifierEnableSync];
-
-    SyncSwitchItem* item = base::mac::ObjCCastStrict<SyncSwitchItem>(
-        [self.tableViewModel itemAtIndexPath:indexPath]);
-    item.on = isNowOn;
-  }
-  [self updateTableView];
-}
-
-- (void)fixSyncErrorIfPossible {
-  if (![self isSyncErrorFixableByUserAction] || ![self shouldDisplaySyncError])
-    return;
-
-  // Unrecoverable errors are special-cased to only do the signing out and back
-  // in from the Sync settings screen (where user interaction can safely be
-  // prevented).
-  if (_syncSetupService->GetSyncServiceState() ==
-      SyncSetupService::kSyncServiceUnrecoverableError) {
-    ChromeIdentity* authenticatedIdentity =
-        AuthenticationServiceFactory::GetForBrowserState(_browserState)
-            ->GetAuthenticatedIdentity();
-    [self startSwitchAccountForIdentity:authenticatedIdentity
-                       postSignInAction:POST_SIGNIN_ACTION_START_SYNC];
-    return;
-  }
-
-  SyncSetupService::SyncServiceState syncState =
-      GetSyncStateForBrowserState(_browserState);
-  if (ShouldShowSyncSignin(syncState)) {
-    [self.dispatcher
-                showSignin:[[ShowSigninCommand alloc]
-                               initWithOperation:
-                                   AUTHENTICATION_OPERATION_REAUTHENTICATE
-                                     accessPoint:signin_metrics::AccessPoint::
-                                                     ACCESS_POINT_UNKNOWN]
-        baseViewController:self];
-  } else if (ShouldShowSyncSettings(syncState)) {
-    [self.dispatcher showGoogleServicesSettingsFromViewController:self];
-  } else if (ShouldShowSyncPassphraseSettings(syncState)) {
-    [self.dispatcher showSyncPassphraseSettingsFromViewController:self];
-  }
-}
-
-- (void)startSwitchAccountForIdentity:(ChromeIdentity*)identity
-                     postSignInAction:(PostSignInAction)postSignInAction {
-  if (!_syncSetupService->IsSyncEnabled())
-    return;
-
-  _authenticationOperationInProgress = YES;
-  [[NSNotificationCenter defaultCenter]
-      postNotificationName:kSwitchAccountWillStartNotification
-                    object:self];
-  [self preventUserInteraction];
-  DCHECK(!_authenticationFlow);
-  _authenticationFlow = [[AuthenticationFlow alloc]
-          initWithBrowserState:_browserState
-                      identity:identity
-               shouldClearData:SHOULD_CLEAR_DATA_USER_CHOICE
-              postSignInAction:postSignInAction
-      presentingViewController:self];
-  _authenticationFlow.dispatcher = self.dispatcher;
-
-  __weak SyncSettingsTableViewController* weakSelf = self;
-  [_authenticationFlow startSignInWithCompletion:^(BOOL success) {
-    [weakSelf didSwitchAccountWithSuccess:success];
-  }];
-}
-
-- (void)didSwitchAccountWithSuccess:(BOOL)success {
-  _authenticationFlow = nil;
-  [self allowUserInteraction];
-  [[NSNotificationCenter defaultCenter]
-      postNotificationName:kSwitchAccountDidFinishNotification
-                    object:self];
-  _authenticationOperationInProgress = NO;
-  if (![self popViewIfSignedOut]) {
-    // Only reload the view if it wasn't popped.
-    [self reloadData];
-  }
-}
-
-- (void)changeSyncEverythingStatusToOn:(UISwitch*)sender {
-  if (!_syncSetupService->IsSyncEnabled() ||
-      [self shouldDisableSettingsOnSyncError])
-    return;
-  BOOL isOn = sender.isOn;
-  BOOL wasOn = _syncSetupService->IsSyncingAllDataTypes();
-  if (wasOn == isOn)
-    return;
-
-  base::AutoReset<BOOL> autoReset(&_ignoreSyncStateChanges, YES);
-  _syncSetupService->SetSyncingAllDataTypes(isOn);
-
-  // Base the UI on the actual sync value, not the toggle.
-  BOOL isNowOn = _syncSetupService->IsSyncingAllDataTypes();
-  if (isNowOn == wasOn) {
-    DLOG(WARNING) << "Call to SetSyncingAllDataTypes(" << (isOn ? "YES" : "NO")
-                  << ") failed";
-    // No change - there was a sync-level problem that didn't allow the change.
-    // This really shouldn't happen, but just in case, make sure the UI reflects
-    // sync's reality.
-    NSIndexPath* indexPath = [self.tableViewModel
-        indexPathForItemType:ItemTypeSyncEverything
-           sectionIdentifier:SectionIdentifierSyncServices];
-    SyncSwitchItem* item = base::mac::ObjCCastStrict<SyncSwitchItem>(
-        [self.tableViewModel itemAtIndexPath:indexPath]);
-    item.on = isNowOn;
-  }
-  [self updateTableView];
-}
-
-- (void)changeDataTypeSyncStatusToOn:(UISwitch*)sender {
-  if (!_syncSetupService->IsSyncEnabled() ||
-      _syncSetupService->IsSyncingAllDataTypes() ||
-      [self shouldDisableSettingsOnSyncError])
-    return;
-
-  BOOL isOn = sender.isOn;
-
-  SyncSwitchItem* syncSwitchItem = base::mac::ObjCCastStrict<SyncSwitchItem>(
-      [self.tableViewModel itemAtIndexPath:[self indexPathForTag:sender.tag]]);
-  SyncSetupService::SyncableDatatype dataType =
-      (SyncSetupService::SyncableDatatype)syncSwitchItem.dataType;
-  syncer::ModelType modelType = _syncSetupService->GetModelType(dataType);
-
-  base::AutoReset<BOOL> autoReset(&_ignoreSyncStateChanges, YES);
-  _syncSetupService->SetDataTypeEnabled(modelType, isOn);
-
-  // Set value of Autofill wallet import accordingly if Autofill Sync changed.
-  if (dataType == SyncSetupService::kSyncAutofill) {
-    [self setAutofillWalletImportOn:isOn];
-    [self updateTableView];
-  }
-}
-
-- (void)autofillWalletImportChanged:(UISwitch*)sender {
-  if (![self isAutofillWalletImportItemEnabled])
-    return;
-
-  [self setAutofillWalletImportOn:sender.isOn];
-}
-
-- (void)showEncryption {
-  syncer::SyncService* syncService =
-      ProfileSyncServiceFactory::GetForBrowserState(_browserState);
-  if (!syncService->IsEngineInitialized() ||
-      !_syncSetupService->IsSyncEnabled() ||
-      [self shouldDisableSettingsOnSyncError])
-    return;
-
-  UIViewController<SettingsRootViewControlling>* controllerToPush;
-  // If there was a sync error, prompt the user to enter the passphrase.
-  // Otherwise, show the full encryption options.
-  if (syncService->GetUserSettings()->IsPassphraseRequired()) {
-    controllerToPush = [[SyncEncryptionPassphraseTableViewController alloc]
-        initWithBrowserState:_browserState];
-  } else {
-    controllerToPush = [[SyncEncryptionTableViewController alloc]
-        initWithBrowserState:_browserState];
-  }
-  controllerToPush.dispatcher = self.dispatcher;
-  [self.navigationController pushViewController:controllerToPush animated:YES];
-}
-
-#pragma mark Updates
-
-- (void)updateTableView {
-  __weak SyncSettingsTableViewController* weakSelf = self;
-  [self.tableView
-      performBatchUpdates:^{
-        [weakSelf updateTableViewInternal];
-      }
-               completion:nil];
-}
-
-- (void)updateTableViewInternal {
-  NSIndexPath* indexPath =
-      [self.tableViewModel indexPathForItemType:ItemTypeSyncSwitch
-                              sectionIdentifier:SectionIdentifierEnableSync];
-
-  SyncSwitchItem* syncItem = base::mac::ObjCCastStrict<SyncSwitchItem>(
-      [self.tableViewModel itemAtIndexPath:indexPath]);
-  syncItem.on = _syncSetupService->IsSyncEnabled();
-  [self reconfigureCellsForItems:@[ syncItem ]];
-
-  // Update Sync Accounts section.
-  if ([self hasAccountsSection]) {
-    NSInteger section = [self.tableViewModel
-        sectionForSectionIdentifier:SectionIdentifierSyncAccounts];
-    NSInteger itemsCount = [self.tableViewModel numberOfItemsInSection:section];
-    NSMutableArray* accountsToReconfigure = [[NSMutableArray alloc] init];
-    for (NSInteger item = 0; item < itemsCount; ++item) {
-      NSIndexPath* indexPath = [self.tableViewModel
-          indexPathForItemType:ItemTypeAccount
-             sectionIdentifier:SectionIdentifierSyncAccounts
-                       atIndex:item];
-      TableViewAccountItem* accountItem =
-          base::mac::ObjCCastStrict<TableViewAccountItem>(
-              [self.tableViewModel itemAtIndexPath:indexPath]);
-      accountItem.mode = _syncSetupService->IsSyncEnabled()
-                             ? TableViewAccountModeEnabled
-                             : TableViewAccountModeDisabled;
-      [accountsToReconfigure addObject:accountItem];
-    }
-    [self reconfigureCellsForItems:accountsToReconfigure];
-  }
-
-  // Update Sync Services section.
-  indexPath =
-      [self.tableViewModel indexPathForItemType:ItemTypeSyncEverything
-                              sectionIdentifier:SectionIdentifierSyncServices];
-  SyncSwitchItem* syncEverythingItem =
-      base::mac::ObjCCastStrict<SyncSwitchItem>(
-          [self.tableViewModel itemAtIndexPath:indexPath]);
-  syncEverythingItem.on = _syncSetupService->IsSyncingAllDataTypes();
-  syncEverythingItem.enabled = [self shouldSyncEverythingItemBeEnabled];
-  [self reconfigureCellsForItems:@[ syncEverythingItem ]];
-
-  // Syncable data types cells
-  NSMutableArray* switchsToReconfigure = [[NSMutableArray alloc] init];
-  for (NSInteger index = 0;
-       index < SyncSetupService::kNumberOfSyncableDatatypes; ++index) {
-    SyncSetupService::SyncableDatatype dataType =
-        static_cast<SyncSetupService::SyncableDatatype>(index);
-    NSIndexPath* indexPath =
-        [self.tableViewModel indexPathForItemType:ItemTypeSyncableDataType
-                                sectionIdentifier:SectionIdentifierSyncServices
-                                          atIndex:index];
-    SyncSwitchItem* syncSwitchItem = base::mac::ObjCCastStrict<SyncSwitchItem>(
-        [self.tableViewModel itemAtIndexPath:indexPath]);
-    DCHECK_EQ(index, syncSwitchItem.dataType);
-    syncer::ModelType modelType = _syncSetupService->GetModelType(dataType);
-    syncSwitchItem.on = _syncSetupService->IsDataTypePreferred(modelType);
-    syncSwitchItem.enabled = [self shouldSyncableItemsBeEnabled];
-    [switchsToReconfigure addObject:syncSwitchItem];
-  }
-  [self reconfigureCellsForItems:switchsToReconfigure];
-
-  // Update Autofill wallet import cell.
-  [self updateAutofillWalletImportCell];
-
-  // Update Encryption cell.
-  [self updateEncryptionCell];
-
-  // Add/Remove the Sync Error. This is the only update that can change index
-  // paths. It is done last because self.tableViewModel isn't aware of
-  // the performBatchUpdates:completion: order of update/remove/delete.
-  [self updateSyncError];
-}
-
-- (void)updateSyncError {
-  BOOL shouldDisplayError = [self shouldDisplaySyncError];
-  BOOL isDisplayingError =
-      [self.tableViewModel hasItemForItemType:ItemTypeSyncError
-                            sectionIdentifier:SectionIdentifierSyncError];
-  if (shouldDisplayError && !isDisplayingError) {
-    [self.tableViewModel insertSectionWithIdentifier:SectionIdentifierSyncError
-                                             atIndex:0];
-    [self.tableViewModel addItem:[self syncErrorItem]
-         toSectionWithIdentifier:SectionIdentifierSyncError];
-    NSInteger section = [self.tableViewModel
-        sectionForSectionIdentifier:SectionIdentifierSyncError];
-    [self.tableView insertSections:[NSIndexSet indexSetWithIndex:section]
-                  withRowAnimation:UITableViewRowAnimationAutomatic];
-  } else if (!shouldDisplayError && isDisplayingError) {
-    NSInteger section = [self.tableViewModel
-        sectionForSectionIdentifier:SectionIdentifierSyncError];
-    [self.tableViewModel
-        removeSectionWithIdentifier:SectionIdentifierSyncError];
-    [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:section]
-                  withRowAnimation:UITableViewRowAnimationAutomatic];
-  }
-}
-
-- (void)updateAutofillWalletImportCell {
-  // Force turn on Autofill wallet import if syncing everthing.
-  BOOL isSyncingEverything = _syncSetupService->IsSyncingAllDataTypes();
-  if (isSyncingEverything) {
-    [self setAutofillWalletImportOn:isSyncingEverything];
-  }
-
-  NSIndexPath* indexPath =
-      [self.tableViewModel indexPathForItemType:ItemTypeAutofillWalletImport
-                              sectionIdentifier:SectionIdentifierSyncServices];
-  SyncSwitchItem* syncSwitchItem = base::mac::ObjCCastStrict<SyncSwitchItem>(
-      [self.tableViewModel itemAtIndexPath:indexPath]);
-  syncSwitchItem.on = [self isAutofillWalletImportOn];
-  syncSwitchItem.enabled = [self isAutofillWalletImportItemEnabled];
-  [self reconfigureCellsForItems:@[ syncSwitchItem ]];
-}
-
-- (void)updateEncryptionCell {
-  BOOL shouldDisplayEncryptionError = [self shouldDisplayEncryptionError];
-  NSIndexPath* indexPath = [self.tableViewModel
-      indexPathForItemType:ItemTypeEncryption
-         sectionIdentifier:SectionIdentifierEncryptionAndFooter];
-  TableViewImageItem* item = base::mac::ObjCCastStrict<TableViewImageItem>(
-      [self.tableViewModel itemAtIndexPath:indexPath]);
-  item.image = shouldDisplayEncryptionError
-                   ? [UIImage imageNamed:@"settings_error"]
-                   : nil;
-  item.enabled = [self shouldEncryptionItemBeEnabled];
-  item.textColor =
-      item.enabled ? UIColor.cr_labelColor : UIColor.cr_secondaryLabelColor;
-  [self reconfigureCellsForItems:@[ item ]];
-}
-
-- (void)updateAccountItem:(TableViewAccountItem*)item
-             withIdentity:(ChromeIdentity*)identity {
-  item.image = [_avatarCache resizedAvatarForIdentity:identity];
-  item.text = identity.userEmail;
-  item.chromeIdentity = identity;
-}
-
-#pragma mark Helpers
-
-- (BOOL)hasAccountsSection {
-  return _allowSwitchSyncAccount &&
-         IdentityManagerFactory::GetForBrowserState(_browserState)
-                 ->GetAccountsWithRefreshTokens()
-                 .size() > 1;
-}
-
-- (BOOL)shouldDisplaySyncError {
-  SyncSetupService::SyncServiceState state =
-      _syncSetupService->GetSyncServiceState();
-  // Without unity, kSyncSettingsNotConfirmed should not be shown.
-  return state != SyncSetupService::kNoSyncServiceError &&
-         state != SyncSetupService::kSyncSettingsNotConfirmed;
-}
-
-- (BOOL)shouldDisableSettingsOnSyncError {
-  SyncSetupService::SyncServiceState state =
-      _syncSetupService->GetSyncServiceState();
-  return state != SyncSetupService::kNoSyncServiceError &&
-         state != SyncSetupService::kSyncServiceNeedsPassphrase;
-}
-
-- (BOOL)shouldDisplayEncryptionError {
-  return _syncSetupService->GetSyncServiceState() ==
-         SyncSetupService::kSyncServiceNeedsPassphrase;
-}
-
-- (BOOL)isSyncErrorFixableByUserAction {
-  SyncSetupService::SyncServiceState state =
-      _syncSetupService->GetSyncServiceState();
-  return state == SyncSetupService::kSyncServiceNeedsPassphrase ||
-         state == SyncSetupService::kSyncServiceSignInNeedsUpdate ||
-         state == SyncSetupService::kSyncServiceUnrecoverableError;
-}
-
-- (int)titleIdForSyncableDataType:(SyncSetupService::SyncableDatatype)datatype {
-  switch (datatype) {
-    case SyncSetupService::kSyncBookmarks:
-      return IDS_SYNC_DATATYPE_BOOKMARKS;
-    case SyncSetupService::kSyncOmniboxHistory:
-      return IDS_SYNC_DATATYPE_TYPED_URLS;
-    case SyncSetupService::kSyncPasswords:
-      return IDS_SYNC_DATATYPE_PASSWORDS;
-    case SyncSetupService::kSyncOpenTabs:
-      return IDS_SYNC_DATATYPE_TABS;
-    case SyncSetupService::kSyncAutofill:
-      return IDS_SYNC_DATATYPE_AUTOFILL;
-    case SyncSetupService::kSyncPreferences:
-      return IDS_SYNC_DATATYPE_PREFERENCES;
-    case SyncSetupService::kSyncReadingList:
-      return IDS_SYNC_DATATYPE_READING_LIST;
-    case SyncSetupService::kNumberOfSyncableDatatypes:
-      NOTREACHED();
-  }
-  return 0;
-}
-
-- (BOOL)shouldEncryptionItemBeEnabled {
-  syncer::SyncService* syncService =
-      ProfileSyncServiceFactory::GetForBrowserState(_browserState);
-  return (syncService->IsEngineInitialized() &&
-          _syncSetupService->IsSyncEnabled() &&
-          ![self shouldDisableSettingsOnSyncError]);
-}
-
-- (BOOL)shouldSyncEverythingItemBeEnabled {
-  return (_syncSetupService->IsSyncEnabled() &&
-          ![self shouldDisableSettingsOnSyncError]);
-}
-
-- (BOOL)shouldSyncableItemsBeEnabled {
-  return (!_syncSetupService->IsSyncingAllDataTypes() &&
-          _syncSetupService->IsSyncEnabled() &&
-          ![self shouldDisableSettingsOnSyncError]);
-}
-
-- (BOOL)isAutofillWalletImportItemEnabled {
-  syncer::ModelType autofillModelType =
-      _syncSetupService->GetModelType(SyncSetupService::kSyncAutofill);
-  BOOL isAutofillOn = _syncSetupService->IsDataTypePreferred(autofillModelType);
-  return isAutofillOn && [self shouldSyncableItemsBeEnabled];
-}
-
-- (BOOL)isAutofillWalletImportOn {
-  return autofill::prefs::IsPaymentsIntegrationEnabled(
-      _browserState->GetPrefs());
-}
-
-- (void)setAutofillWalletImportOn:(BOOL)on {
-  autofill::prefs::SetPaymentsIntegrationEnabled(_browserState->GetPrefs(), on);
-}
-
-- (NSInteger)tagForIndexPath:(NSIndexPath*)indexPath {
-  DCHECK(indexPath.section ==
-         [self.tableViewModel
-             sectionForSectionIdentifier:SectionIdentifierSyncServices]);
-  NSInteger index = [self.tableViewModel indexInItemTypeForIndexPath:indexPath];
-  return index + kTagShift;
-}
-
-- (NSIndexPath*)indexPathForTag:(NSInteger)shiftedTag {
-  NSInteger unshiftedTag = shiftedTag - kTagShift;
-  return [self.tableViewModel indexPathForItemType:ItemTypeSyncableDataType
-                                 sectionIdentifier:SectionIdentifierSyncServices
-                                           atIndex:unshiftedTag];
-}
-
-#pragma mark SyncObserverModelBridge
-
-- (void)onSyncStateChanged {
-  if (_ignoreSyncStateChanges || _authenticationOperationInProgress) {
-    return;
-  }
-  [self updateTableView];
-}
-
-#pragma mark signin::IdentityManagerObserverBridgeDelegate
-
-- (void)onEndBatchOfRefreshTokenStateChanges {
-  if (_authenticationOperationInProgress) {
-    return;
-  }
-  if (![self popViewIfSignedOut]) {
-    // Only reload the view if it wasn't popped.
-    [self reloadData];
-  }
-}
-
-#pragma mark SettingsControllerProtocol callbacks
-
-- (void)settingsWillBeDismissed {
-  [self stopBrowserStateServiceObservers];
-  [_authenticationFlow cancelAndDismiss];
-}
-
-#pragma mark - ChromeIdentityServiceObserver
-
-- (void)profileUpdate:(ChromeIdentity*)identity {
-  TableViewAccountItem* item = base::mac::ObjCCastStrict<TableViewAccountItem>(
-      [_identityMap objectForKey:identity.gaiaID]);
-  if (!item) {
-    // Ignoring unknown identity.
-    return;
-  }
-  [self updateAccountItem:item withIdentity:identity];
-  [self reconfigureCellsForItems:@[ item ]];
-}
-
-- (void)chromeIdentityServiceWillBeDestroyed {
-  _identityServiceObserver.reset();
-}
-
-@end
diff --git a/ios/chrome/browser/ui/settings/sync/sync_settings_table_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/sync/sync_settings_table_view_controller_unittest.mm
deleted file mode 100644
index 53921ee5..0000000
--- a/ios/chrome/browser/ui/settings/sync/sync_settings_table_view_controller_unittest.mm
+++ /dev/null
@@ -1,386 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/settings/sync/sync_settings_table_view_controller.h"
-
-#include <memory>
-
-#include "base/bind.h"
-#import "base/mac/foundation_util.h"
-#include "base/strings/sys_string_conversions.h"
-#include "components/autofill/core/common/autofill_prefs.h"
-#include "components/google/core/common/google_util.h"
-#include "components/strings/grit/components_strings.h"
-#include "components/sync/driver/test_sync_service.h"
-#include "components/sync_preferences/pref_service_mock_factory.h"
-#include "components/sync_preferences/pref_service_syncable.h"
-#include "components/unified_consent/feature.h"
-#include "components/unified_consent/scoped_unified_consent.h"
-#include "ios/chrome/browser/application_context.h"
-#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
-#include "ios/chrome/browser/chrome_url_constants.h"
-#include "ios/chrome/browser/prefs/browser_prefs.h"
-#include "ios/chrome/browser/sync/profile_sync_service_factory.h"
-#include "ios/chrome/browser/sync/sync_setup_service.h"
-#include "ios/chrome/browser/sync/sync_setup_service_factory.h"
-#include "ios/chrome/browser/sync/sync_setup_service_mock.h"
-#include "ios/chrome/browser/system_flags.h"
-#import "ios/chrome/browser/ui/settings/cells/sync_switch_item.h"
-#import "ios/chrome/browser/ui/settings/sync/utils/sync_util.h"
-#import "ios/chrome/browser/ui/table_view/cells/table_view_image_item.h"
-#import "ios/chrome/browser/ui/table_view/chrome_table_view_controller_test.h"
-#import "ios/chrome/browser/ui/table_view/table_view_model.h"
-#include "ios/chrome/grit/ios_strings.h"
-#include "ios/web/public/test/web_task_environment.h"
-#import "testing/gtest_mac.h"
-#include "ui/base/l10n/l10n_util.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-@interface SyncSettingsTableViewController (ExposedForTesting)
-- (int)titleIdForSyncableDataType:(SyncSetupService::SyncableDatatype)datatype;
-- (void)onSyncStateChanged;
-@end
-
-namespace {
-
-using testing::NiceMock;
-using testing::Return;
-
-std::unique_ptr<KeyedService> CreateTestSyncService(
-    web::BrowserState* context) {
-  return std::make_unique<syncer::TestSyncService>();
-}
-
-class SyncSetupServiceMockThatFails : public SyncSetupServiceMock {
- public:
-  SyncSetupServiceMockThatFails(syncer::SyncService* sync_service)
-      : SyncSetupServiceMock(sync_service) {}
-  bool IsSyncEnabled() const override { return sync_enabled_; }
-  void SetSyncEnabled(bool sync_enabled) override {}
-  bool IsSyncingAllDataTypes() const override { return sync_all_; }
-  void SetSyncingAllDataTypes(bool sync_all) override {}
-
-  static void SetSyncEnabledTestValue(bool sync_enabled) {
-    sync_enabled_ = sync_enabled;
-  }
-  static void SetSyncEverythingTestValue(bool sync_all) {
-    sync_all_ = sync_all;
-  }
-
- protected:
-  static bool sync_enabled_;
-  static bool sync_all_;
-};
-
-bool SyncSetupServiceMockThatFails::sync_enabled_ = true;
-bool SyncSetupServiceMockThatFails::sync_all_ = true;
-
-class SyncSetupServiceMockThatSucceeds : public SyncSetupServiceMockThatFails {
- public:
-  SyncSetupServiceMockThatSucceeds(syncer::SyncService* sync_service)
-      : SyncSetupServiceMockThatFails(sync_service) {}
-  void SetSyncEnabled(bool sync_enabled) override {
-    sync_enabled_ = sync_enabled;
-  }
-  void SetSyncingAllDataTypes(bool sync_all) override { sync_all_ = sync_all; }
-};
-
-class SyncSettingsTableViewControllerTest
-    : public ChromeTableViewControllerTest {
- public:
-  SyncSettingsTableViewControllerTest()
-      : unified_consent_disabled_(
-            unified_consent::UnifiedConsentFeatureState::kDisabled) {}
-
-  static std::unique_ptr<KeyedService> CreateSyncSetupService(
-      web::BrowserState* context) {
-    ios::ChromeBrowserState* chrome_browser_state =
-        ios::ChromeBrowserState::FromBrowserState(context);
-    syncer::SyncService* sync_service =
-        ProfileSyncServiceFactory::GetForBrowserState(chrome_browser_state);
-    return std::make_unique<NiceMock<SyncSetupServiceMock>>(sync_service);
-  }
-
-  static std::unique_ptr<KeyedService> CreateSucceedingSyncSetupService(
-      web::BrowserState* context) {
-    ios::ChromeBrowserState* chrome_browser_state =
-        ios::ChromeBrowserState::FromBrowserState(context);
-    syncer::SyncService* sync_service =
-        ProfileSyncServiceFactory::GetForBrowserState(chrome_browser_state);
-    return std::make_unique<NiceMock<SyncSetupServiceMockThatSucceeds>>(
-        sync_service);
-  }
-
-  static std::unique_ptr<KeyedService> CreateFailingSyncSetupService(
-      web::BrowserState* context) {
-    ios::ChromeBrowserState* chrome_browser_state =
-        ios::ChromeBrowserState::FromBrowserState(context);
-    syncer::SyncService* sync_service =
-        ProfileSyncServiceFactory::GetForBrowserState(chrome_browser_state);
-    return std::make_unique<NiceMock<SyncSetupServiceMockThatFails>>(
-        sync_service);
-  }
-
-  std::unique_ptr<sync_preferences::PrefServiceSyncable> CreatePrefService() {
-    scoped_refptr<user_prefs::PrefRegistrySyncable> registry(
-        new user_prefs::PrefRegistrySyncable);
-    RegisterBrowserStatePrefs(registry.get());
-    sync_preferences::PrefServiceMockFactory factory;
-    return factory.CreateSyncable(registry.get());
-  }
-
-  void TurnSyncOn() {
-    ON_CALL(*mock_sync_setup_service_, IsSyncEnabled())
-        .WillByDefault(Return(true));
-  }
-
-  void TurnSyncEverythingOn() {
-    ON_CALL(*mock_sync_setup_service_, IsSyncingAllDataTypes())
-        .WillByDefault(Return(true));
-  }
-
-  void SetSyncServiceState(SyncSetupService::SyncServiceState state) {
-    ON_CALL(*mock_sync_setup_service_, GetSyncServiceState())
-        .WillByDefault(Return(state));
-  }
-
-  void TurnSyncPassphraseErrorOn() {
-    SetSyncServiceState(SyncSetupService::kSyncServiceNeedsPassphrase);
-  }
-
-  void TurnSyncErrorOff() {
-    SetSyncServiceState(SyncSetupService::kNoSyncServiceError);
-  }
-
- protected:
-  void SetUp() override {
-    TestChromeBrowserState::Builder test_cbs_builder;
-    test_cbs_builder.AddTestingFactory(
-        SyncSetupServiceFactory::GetInstance(),
-        base::BindRepeating(&CreateSyncSetupService));
-    test_cbs_builder.AddTestingFactory(
-        ProfileSyncServiceFactory::GetInstance(),
-        base::BindRepeating(&CreateTestSyncService));
-    test_cbs_builder.SetPrefService(CreatePrefService());
-    chrome_browser_state_ = test_cbs_builder.Build();
-    ChromeTableViewControllerTest::SetUp();
-
-    mock_sync_setup_service_ = static_cast<NiceMock<SyncSetupServiceMock>*>(
-        SyncSetupServiceFactory::GetForBrowserState(
-            chrome_browser_state_.get()));
-    // The other mocked functions of SyncSetupServiceMock return bools, so they
-    // will by default return false.   |syncServiceState|, however, returns an
-    // enum, and thus always needs its default value set.
-    TurnSyncErrorOff();
-  }
-
-  ChromeTableViewController* InstantiateController() override {
-    return [[SyncSettingsTableViewController alloc]
-          initWithBrowserState:chrome_browser_state_.get()
-        allowSwitchSyncAccount:YES];
-  }
-
-  SyncSettingsTableViewController* CreateSyncController() {
-    CreateController();
-    CheckTitleWithId(IDS_IOS_SYNC_SETTING_TITLE);
-    return static_cast<SyncSettingsTableViewController*>(controller());
-  }
-
-  void CheckErrorIcon(BOOL expectedShouldDisplayError,
-                      NSInteger section,
-                      NSInteger item) {
-    TableViewModel* model = [controller() tableViewModel];
-    NSIndexPath* path = [NSIndexPath indexPathForItem:item inSection:section];
-
-    TableViewImageItem* errorObject =
-        base::mac::ObjCCastStrict<TableViewImageItem>(
-            [model itemAtIndexPath:path]);
-    EXPECT_TRUE(errorObject);
-    BOOL hasImage = !!errorObject.image;
-    EXPECT_EQ(expectedShouldDisplayError, hasImage);
-  }
-
-  unified_consent::ScopedUnifiedConsent unified_consent_disabled_;
-  web::WebTaskEnvironment task_environment_;
-  std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
-  // Weak, owned by |profile_|.
-  NiceMock<SyncSetupServiceMock>* mock_sync_setup_service_;
-};
-
-TEST_F(SyncSettingsTableViewControllerTest, TestModel) {
-  TurnSyncEverythingOn();
-  TurnSyncOn();
-  SyncSettingsTableViewController* sync_controller = CreateSyncController();
-
-  EXPECT_EQ(3, NumberOfSections());
-
-  EXPECT_EQ(1, NumberOfItemsInSection(0));
-  // There are two extra items, one for "Sync Everything" and another for
-  // Autofill wallet import.
-  constexpr int expected_number_of_items =
-      SyncSetupService::kNumberOfSyncableDatatypes + 2;
-  EXPECT_EQ(expected_number_of_items, NumberOfItemsInSection(1));
-  EXPECT_EQ(2, NumberOfItemsInSection(2));
-
-  SyncSwitchItem* syncItem = GetTableViewItem(0, 0);
-  EXPECT_EQ(syncItem.isOn, YES);
-  EXPECT_NSEQ(syncItem.text,
-              l10n_util::GetNSString(IDS_IOS_SYNC_SETTING_TITLE));
-  EXPECT_NSEQ(
-      syncItem.detailText,
-      l10n_util::GetNSString(IDS_IOS_SIGN_IN_TO_CHROME_SETTING_SUBTITLE));
-
-  SyncSwitchItem* syncEverythingItem = GetTableViewItem(1, 0);
-  EXPECT_EQ(syncEverythingItem.isOn, YES);
-  EXPECT_NSEQ(syncEverythingItem.text,
-              l10n_util::GetNSString(IDS_IOS_SYNC_EVERYTHING_TITLE));
-
-  int item = 1;
-  for (int i = 0; i < SyncSetupService::kNumberOfSyncableDatatypes; i++) {
-    SyncSetupService::SyncableDatatype dataType =
-        static_cast<SyncSetupService::SyncableDatatype>(i);
-    SyncSwitchItem* syncDataTypeItem = GetTableViewItem(1, item++);
-    EXPECT_NSEQ(syncDataTypeItem.text,
-                l10n_util::GetNSString(
-                    [sync_controller titleIdForSyncableDataType:dataType]));
-  }
-
-  SyncSwitchItem* autofillWalletImportItem = GetTableViewItem(1, item);
-  NSString* title = l10n_util::GetNSString(
-      IDS_AUTOFILL_ENABLE_PAYMENTS_INTEGRATION_CHECKBOX_LABEL);
-  EXPECT_NSEQ(autofillWalletImportItem.text, title);
-
-  TableViewImageItem* encryptionItem = GetTableViewItem(2, 0);
-  EXPECT_NSEQ(encryptionItem.title,
-              l10n_util::GetNSString(IDS_IOS_SYNC_ENCRYPTION_TITLE));
-  CheckErrorIcon(NO, 2, 0);
-}
-
-TEST_F(SyncSettingsTableViewControllerTest, TestEnabledCellsSyncOff) {
-  CreateSyncController();
-
-  for (int item = 0; item < NumberOfItemsInSection(1); ++item) {
-    SyncSwitchItem* object = GetTableViewItem(1, item);
-    EXPECT_FALSE(object.enabled);
-  }
-
-  TableViewImageItem* encryptionItem = GetTableViewItem(2, 0);
-  EXPECT_FALSE(encryptionItem.enabled);
-}
-
-TEST_F(SyncSettingsTableViewControllerTest, TestEnabledCellsSyncEverythingOn) {
-  TurnSyncOn();
-  TurnSyncEverythingOn();
-  CreateSyncController();
-
-  SyncSwitchItem* syncEverythingItem = GetTableViewItem(1, 0);
-  EXPECT_TRUE(syncEverythingItem.enabled);
-  for (int item = 1; item <= SyncSetupService::kNumberOfSyncableDatatypes;
-       ++item) {
-    SyncSwitchItem* object = GetTableViewItem(1, item);
-    EXPECT_FALSE(object.enabled);
-  }
-
-  SyncSwitchItem* autofillWalletImportItem =
-      GetTableViewItem(1, NumberOfItemsInSection(1) - 1);
-  EXPECT_FALSE(autofillWalletImportItem.enabled);
-
-  TableViewImageItem* encryptionItem = GetTableViewItem(2, 0);
-  EXPECT_TRUE(encryptionItem.enabled);
-}
-
-TEST_F(SyncSettingsTableViewControllerTest, TestAutofillWalletImportOff) {
-  autofill::prefs::SetPaymentsIntegrationEnabled(
-      chrome_browser_state_->GetPrefs(), false);
-
-  TurnSyncOn();
-  TurnSyncEverythingOn();
-  CreateSyncController();
-
-  SyncSwitchItem* autofillWalletImportItem =
-      GetTableViewItem(1, NumberOfItemsInSection(1) - 1);
-  EXPECT_FALSE(autofillWalletImportItem.isOn);
-}
-
-TEST_F(SyncSettingsTableViewControllerTest, TestAutofillWalletImportOn) {
-  autofill::prefs::SetPaymentsIntegrationEnabled(
-      chrome_browser_state_->GetPrefs(), true);
-
-  TurnSyncOn();
-  TurnSyncEverythingOn();
-  CreateSyncController();
-
-  SyncSwitchItem* autofillWalletImportItem =
-      GetTableViewItem(1, NumberOfItemsInSection(1) - 1);
-  EXPECT_TRUE(autofillWalletImportItem.isOn);
-}
-
-TEST_F(SyncSettingsTableViewControllerTest, TestShouldDisplayError) {
-  SyncSettingsTableViewController* sync_controller = CreateSyncController();
-  EXPECT_FALSE([sync_controller shouldDisplaySyncError]);
-  EXPECT_FALSE([sync_controller shouldDisableSettingsOnSyncError]);
-  EXPECT_FALSE([sync_controller shouldDisplayEncryptionError]);
-
-  SetSyncServiceState(SyncSetupService::kSyncServiceSignInNeedsUpdate);
-  EXPECT_TRUE([sync_controller shouldDisplaySyncError]);
-  EXPECT_TRUE([sync_controller shouldDisableSettingsOnSyncError]);
-  EXPECT_FALSE([sync_controller shouldDisplayEncryptionError]);
-
-  SetSyncServiceState(SyncSetupService::kSyncServiceCouldNotConnect);
-  EXPECT_TRUE([sync_controller shouldDisplaySyncError]);
-  EXPECT_TRUE([sync_controller shouldDisableSettingsOnSyncError]);
-  EXPECT_FALSE([sync_controller shouldDisplayEncryptionError]);
-
-  SetSyncServiceState(SyncSetupService::kSyncServiceServiceUnavailable);
-  EXPECT_TRUE([sync_controller shouldDisplaySyncError]);
-  EXPECT_TRUE([sync_controller shouldDisableSettingsOnSyncError]);
-  EXPECT_FALSE([sync_controller shouldDisplayEncryptionError]);
-
-  SetSyncServiceState(SyncSetupService::kSyncServiceNeedsPassphrase);
-  EXPECT_TRUE([sync_controller shouldDisplaySyncError]);
-  EXPECT_FALSE([sync_controller shouldDisableSettingsOnSyncError]);
-  EXPECT_TRUE([sync_controller shouldDisplayEncryptionError]);
-
-  SetSyncServiceState(SyncSetupService::kSyncServiceUnrecoverableError);
-  EXPECT_TRUE([sync_controller shouldDisplaySyncError]);
-  EXPECT_TRUE([sync_controller shouldDisableSettingsOnSyncError]);
-  EXPECT_FALSE([sync_controller shouldDisplayEncryptionError]);
-
-  SetSyncServiceState(SyncSetupService::kNoSyncServiceError);
-  EXPECT_FALSE([sync_controller shouldDisplaySyncError]);
-  EXPECT_FALSE([sync_controller shouldDisableSettingsOnSyncError]);
-  EXPECT_FALSE([sync_controller shouldDisplayEncryptionError]);
-}
-
-TEST_F(SyncSettingsTableViewControllerTest,
-       TestSyncStateChangedWithEncryptionError) {
-  TurnSyncOn();
-  TurnSyncEverythingOn();
-
-  SyncSettingsTableViewController* sync_controller = CreateSyncController();
-
-  TableViewImageItem* encryptionItem = GetTableViewItem(2, 0);
-  EXPECT_NSEQ(encryptionItem.title,
-              l10n_util::GetNSString(IDS_IOS_SYNC_ENCRYPTION_TITLE));
-  CheckErrorIcon(NO, 2, 0);
-
-  TurnSyncPassphraseErrorOn();
-  [sync_controller onSyncStateChanged];
-  encryptionItem = GetTableViewItem(3, 0);
-  EXPECT_NSEQ(encryptionItem.title,
-              l10n_util::GetNSString(IDS_IOS_SYNC_ENCRYPTION_TITLE));
-  CheckErrorIcon(YES, 3, 0);
-
-  TurnSyncErrorOff();
-  [sync_controller onSyncStateChanged];
-  encryptionItem = GetTableViewItem(2, 0);
-  EXPECT_NSEQ(encryptionItem.title,
-              l10n_util::GetNSString(IDS_IOS_SYNC_ENCRYPTION_TITLE));
-  CheckErrorIcon(NO, 2, 0);
-}
-
-}  // namespace
diff --git a/ios/chrome/browser/ui/settings/table_cell_catalog_view_controller.mm b/ios/chrome/browser/ui/settings/table_cell_catalog_view_controller.mm
index 6c144e2..39e5b1aa 100644
--- a/ios/chrome/browser/ui/settings/table_cell_catalog_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/table_cell_catalog_view_controller.mm
@@ -4,7 +4,6 @@
 
 #import "ios/chrome/browser/ui/settings/table_cell_catalog_view_controller.h"
 
-#import "ios/chrome/browser/ui/authentication/cells/account_control_item.h"
 #import "ios/chrome/browser/ui/authentication/cells/signin_promo_view_configurator.h"
 #import "ios/chrome/browser/ui/authentication/cells/table_view_account_item.h"
 #import "ios/chrome/browser/ui/authentication/cells/table_view_signin_promo_item.h"
@@ -414,29 +413,6 @@
   [model addItem:accountItemCheckMark
       toSectionWithIdentifier:SectionIdentifierAccount];
 
-  AccountControlItem* accountControlItem =
-      [[AccountControlItem alloc] initWithType:ItemTypeAccount];
-  accountControlItem.image = [UIImage imageNamed:@"settings_sync"];
-  accountControlItem.text = @"Account Sync Settings";
-  accountControlItem.detailText = @"Detail text";
-  accountControlItem.accessoryType =
-      UITableViewCellAccessoryDisclosureIndicator;
-  [model addItem:accountControlItem
-      toSectionWithIdentifier:SectionIdentifierAccount];
-
-  AccountControlItem* accountControlItemWithExtraLongText =
-      [[AccountControlItem alloc] initWithType:ItemTypeAccount];
-  accountControlItemWithExtraLongText.image = [[ChromeIcon infoIcon]
-      imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
-  accountControlItemWithExtraLongText.text =
-      @"Account Control Settings - long title";
-  accountControlItemWithExtraLongText.detailText =
-      @"Detail text detail text detail text detail text detail text.";
-  accountControlItemWithExtraLongText.accessoryType =
-      UITableViewCellAccessoryDisclosureIndicator;
-  [model addItem:accountControlItemWithExtraLongText
-      toSectionWithIdentifier:SectionIdentifierAccount];
-
   // SectionIdentifierURL.
   TableViewURLItem* item =
       [[TableViewURLItem alloc] initWithType:ItemTypeURLNoMetadata];
diff --git a/ios/chrome/test/earl_grey/chrome_matchers.h b/ios/chrome/test/earl_grey/chrome_matchers.h
index 5e420270..60a2b1a 100644
--- a/ios/chrome/test/earl_grey/chrome_matchers.h
+++ b/ios/chrome/test/earl_grey/chrome_matchers.h
@@ -225,9 +225,6 @@
 // Returns matcher for the privacy settings table view.
 id<GREYMatcher> SettingsPrivacyTableView();
 
-// Returns matcher for the Manage Synced Data button in sync setting view.
-id<GREYMatcher> SettingsSyncManageSyncedDataButton();
-
 // Returns matcher for the menu button to sync accounts.
 id<GREYMatcher> AccountsSyncButton();
 
diff --git a/ios/chrome/test/earl_grey/chrome_matchers.mm b/ios/chrome/test/earl_grey/chrome_matchers.mm
index edde7de..9c8b7019 100644
--- a/ios/chrome/test/earl_grey/chrome_matchers.mm
+++ b/ios/chrome/test/earl_grey/chrome_matchers.mm
@@ -283,10 +283,6 @@
   return [ChromeMatchersAppInterface settingsPrivacyTableView];
 }
 
-id<GREYMatcher> SettingsSyncManageSyncedDataButton() {
-  return [ChromeMatchersAppInterface settingsSyncManageSyncedDataButton];
-}
-
 id<GREYMatcher> AccountsSyncButton() {
   return [ChromeMatchersAppInterface accountsSyncButton];
 }
diff --git a/ios/chrome/test/earl_grey/chrome_matchers_app_interface.h b/ios/chrome/test/earl_grey/chrome_matchers_app_interface.h
index a86bd38..2576257 100644
--- a/ios/chrome/test/earl_grey/chrome_matchers_app_interface.h
+++ b/ios/chrome/test/earl_grey/chrome_matchers_app_interface.h
@@ -230,9 +230,6 @@
 // Returns matcher for the privacy table view.
 + (id<GREYMatcher>)settingsPrivacyTableView;
 
-// Returns matcher for the Manage Synced Data button in sync setting view.
-+ (id<GREYMatcher>)settingsSyncManageSyncedDataButton;
-
 // Returns matcher for the menu button to sync accounts.
 + (id<GREYMatcher>)accountsSyncButton;
 
diff --git a/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm b/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm
index ec05767..f14c15e 100644
--- a/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm
+++ b/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm
@@ -34,7 +34,6 @@
 #import "ios/chrome/browser/ui/settings/import_data_table_view_controller.h"
 #import "ios/chrome/browser/ui/settings/privacy_table_view_controller.h"
 #import "ios/chrome/browser/ui/settings/settings_table_view_controller.h"
-#import "ios/chrome/browser/ui/settings/sync/sync_settings_table_view_controller.h"
 #import "ios/chrome/browser/ui/static_content/static_html_view_controller.h"
 #import "ios/chrome/browser/ui/tab_grid/grid/grid_constants.h"
 #import "ios/chrome/browser/ui/tab_grid/tab_grid_constants.h"
@@ -497,10 +496,6 @@
   return grey_accessibilityID(kPrivacyTableViewId);
 }
 
-+ (id<GREYMatcher>)settingsSyncManageSyncedDataButton {
-  return grey_accessibilityID(kSettingsSyncId);
-}
-
 + (id<GREYMatcher>)accountsSyncButton {
   return grey_allOf(grey_accessibilityID(kSettingsAccountsTableViewSyncCellId),
                     grey_sufficientlyVisible(), nil);
diff --git a/ios/showcase/badges/sc_badge_coordinator.mm b/ios/showcase/badges/sc_badge_coordinator.mm
index dd0898a..429081b 100644
--- a/ios/showcase/badges/sc_badge_coordinator.mm
+++ b/ios/showcase/badges/sc_badge_coordinator.mm
@@ -65,8 +65,7 @@
   BadgeStaticItem* incognitoItem = [[BadgeStaticItem alloc]
       initWithBadgeType:BadgeType::kBadgeTypeIncognito];
   InfobarBadgeModel* passwordBadgeItem = [[InfobarBadgeModel alloc]
-      initWithInfobarType:InfobarType::kInfobarTypePasswordSave
-                 accepted:NO];
+      initWithInfobarType:InfobarType::kInfobarTypePasswordSave];
   [self.consumer setupWithDisplayedBadge:passwordBadgeItem
                          fullScreenBadge:incognitoItem];
 }
diff --git a/ios/showcase/infobars/sc_infobar_banner_coordinator_egtest.mm b/ios/showcase/infobars/sc_infobar_banner_coordinator_egtest.mm
index 7233456..c9b9246 100644
--- a/ios/showcase/infobars/sc_infobar_banner_coordinator_egtest.mm
+++ b/ios/showcase/infobars/sc_infobar_banner_coordinator_egtest.mm
@@ -73,7 +73,7 @@
       assertWithMatcher:grey_nil()];
 }
 
-// Tests that the InfobarBanner is dismissed correctly when its swiped up.
+// Tests that the InfobarBanner is dismissed correctly when is swiped up.
 - (void)testInfobarBannerDismissSwipe {
   // Check Banner was presented.
   [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
@@ -89,7 +89,7 @@
       assertWithMatcher:grey_nil()];
 }
 
-// Tests that the InfobarModal is not presented when the Banner its swiped down.
+// Tests that the InfobarModal is not presented when the Banner is swiped down.
 - (void)testInfobarBannerCantSwipeDown {
   // Check Banner was presented.
   [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
@@ -113,7 +113,7 @@
       assertWithMatcher:grey_nil()];
 }
 
-// Tests that the InfobarModal is presented when the Banner its tapped.
+// Tests that the InfobarModal is not presented when the Banner is tapped.
 - (void)testInfobarBannerTapped {
   // Check Banner was presented.
   [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
@@ -123,6 +123,32 @@
   [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
                                           kInfobarBannerViewIdentifier)]
       performAction:grey_tap()];
+  // Check the Modal is not presented.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+                                          kInfobarBannerPresentedModalLabel)]
+      assertWithMatcher:grey_nil()];
+  // Check the banner is still interactable by swiping it up.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+                                          kInfobarBannerViewIdentifier)]
+      performAction:grey_swipeFastInDirection(kGREYDirectionUp)];
+  // Check Banner was dismissed.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+                                          kInfobarBannerViewIdentifier)]
+      assertWithMatcher:grey_nil()];
+}
+
+// Tests that the InfobarModal is presented when the Open Modal button is
+// tapped.
+- (void)testInfobarBannerGearTapped {
+  // Check Banner was presented.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+                                          kInfobarBannerViewIdentifier)]
+      assertWithMatcher:grey_notNil()];
+  // Tap Gear Button.
+  [[EarlGrey
+      selectElementWithMatcher:grey_accessibilityID(
+                                   kInfobarBannerOpenModalButtonIdentifier)]
+      performAction:grey_tap()];
   // Check Modal was presented.
   [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
                                           kInfobarBannerPresentedModalLabel)]
diff --git a/ios/showcase/infobars/sc_infobar_banner_no_modal_coordinator_egtest.mm b/ios/showcase/infobars/sc_infobar_banner_no_modal_coordinator_egtest.mm
index c86a84ac..97e6da26 100644
--- a/ios/showcase/infobars/sc_infobar_banner_no_modal_coordinator_egtest.mm
+++ b/ios/showcase/infobars/sc_infobar_banner_no_modal_coordinator_egtest.mm
@@ -73,7 +73,7 @@
       assertWithMatcher:grey_nil()];
 }
 
-// Tests that the InfobarBanner is dismissed correctly when its swiped up.
+// Tests that the InfobarBanner is dismissed correctly when is swiped up.
 - (void)testInfobarBannerDismissSwipe {
   // Check Banner was presented.
   [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
@@ -89,7 +89,7 @@
       assertWithMatcher:grey_nil()];
 }
 
-// Tests that the InfobarModal is not presented when the Banner its swiped down.
+// Tests that the InfobarModal is not presented when the Banner is swiped down.
 - (void)testInfobarBannerCantSwipeDown {
   // Check Banner was presented.
   [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
@@ -113,7 +113,7 @@
       assertWithMatcher:grey_nil()];
 }
 
-// Tests that the InfobarModal is not presented when the Banner its tapped.
+// Tests that the InfobarModal is not presented when the Banner is tapped.
 - (void)testInfobarBannerTapped {
   // Check Banner was presented.
   [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
@@ -137,4 +137,22 @@
       assertWithMatcher:grey_nil()];
 }
 
+// Tests that there's no Infobar Open Modal button. Banners that don't present a
+// Modal shouldn't have one.
+- (void)testInfobarBannerNoGear {
+  // Check Banner was presented.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+                                          kInfobarBannerViewIdentifier)]
+      assertWithMatcher:grey_notNil()];
+  // Check Gear Button is not present.
+  [[EarlGrey
+      selectElementWithMatcher:grey_accessibilityID(
+                                   kInfobarBannerOpenModalButtonIdentifier)]
+      assertWithMatcher:grey_nil()];
+  // Dismiss banner.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+                                          kInfobarBannerViewIdentifier)]
+      performAction:grey_swipeFastInDirection(kGREYDirectionUp)];
+}
+
 @end
diff --git a/ios/web/public/thread/web_thread.h b/ios/web/public/thread/web_thread.h
index caaee2ef..95ba181 100644
--- a/ios/web/public/thread/web_thread.h
+++ b/ios/web/public/thread/web_thread.h
@@ -67,8 +67,13 @@
 
   // NOTE: Task posting APIs have moved to post_task.h. See web_task_traits.h.
 
-  // TODO(crbug.com/878356): Consider replacing callsites of this with
-  // base::CreateTaskRunner({id})->DeleteSoon(..).
+  // Delete/ReleaseSoon() helpers allow future deletion of an owned object on
+  // its associated thread. If you already have a task runner bound to a
+  // WebThread you should use its SequencedTaskRunner::DeleteSoon() member
+  // method. If you don't, the helpers below avoid having to do
+  // base::CreateSingleThreadTaskRunner({WebThread::ID})->DeleteSoon(...) which
+  // is equivalent.
+
   template <class T>
   static bool DeleteSoon(ID identifier,
                          const base::Location& from_here,
diff --git a/media/capture/video/win/video_capture_device_factory_win.cc b/media/capture/video/win/video_capture_device_factory_win.cc
index e843e15..f48982e 100644
--- a/media/capture/video/win/video_capture_device_factory_win.cc
+++ b/media/capture/video/win/video_capture_device_factory_win.cc
@@ -88,6 +88,8 @@
     "1943:2253",
     // Dell E5440
     "0c45:64d0", "0c45:64d2",
+    // Dell E7440
+    "1bcf:2985",
     // Lenovo Thinkpad Model 20CG0006FMZ front and rear cameras, see
     // also https://crbug.com/924528
     "04ca:7047", "04ca:7048",
diff --git a/media/gpu/test/rendering_helper.cc b/media/gpu/test/rendering_helper.cc
index e53d1417..dd54917 100644
--- a/media/gpu/test/rendering_helper.cc
+++ b/media/gpu/test/rendering_helper.cc
@@ -75,7 +75,6 @@
   ui::OzonePlatform::InitParams params;
   params.single_process = true;
   ui::OzonePlatform::InitializeForGPU(params);
-  ui::OzonePlatform::GetInstance()->AfterSandboxEntry();
 #endif
 
   if (!use_gl_) {
diff --git a/media/gpu/test/video_test_environment.cc b/media/gpu/test/video_test_environment.cc
index 4179810..773f51c 100644
--- a/media/gpu/test/video_test_environment.cc
+++ b/media/gpu/test/video_test_environment.cc
@@ -56,7 +56,6 @@
   params.single_process = true;
   ui::OzonePlatform::InitializeForUI(params);
   ui::OzonePlatform::InitializeForGPU(params);
-  ui::OzonePlatform::GetInstance()->AfterSandboxEntry();
 
   // Initialize the Ozone GPU helper. If this is not done an error will occur:
   // "Check failed: drm. No devices available for buffer allocation."
diff --git a/media/gpu/video_encode_accelerator_unittest.cc b/media/gpu/video_encode_accelerator_unittest.cc
index f0806d3..bd168d2d 100644
--- a/media/gpu/video_encode_accelerator_unittest.cc
+++ b/media/gpu/video_encode_accelerator_unittest.cc
@@ -824,7 +824,6 @@
     ui::OzonePlatform::InitParams params;
     params.single_process = true;
     ui::OzonePlatform::InitializeForGPU(params);
-    ui::OzonePlatform::GetInstance()->AfterSandboxEntry();
     done->Signal();
   }
 #endif
diff --git a/mojo/public/cpp/bindings/lib/connector.cc b/mojo/public/cpp/bindings/lib/connector.cc
index a92580b..d8bea67 100644
--- a/mojo/public/cpp/bindings/lib/connector.cc
+++ b/mojo/public/cpp/bindings/lib/connector.cc
@@ -7,7 +7,6 @@
 #include <stdint.h>
 
 #include "base/bind.h"
-#include "base/debug/dump_without_crashing.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/macros.h"
@@ -64,11 +63,6 @@
     100  // Use a 100 message quote by default.
 };
 
-const base::FeatureParam<int> kMojoRecordUnreadMessageCountCrashThreshold = {
-    &features::kMojoRecordUnreadMessageCount, "CrashThreshold",
-    0  // Set to zero to disable crash dumps by default.
-};
-
 int UnreadMessageCountQuota() {
   static const bool enabled =
       base::FeatureList::IsEnabled(features::kMojoRecordUnreadMessageCount);
@@ -83,26 +77,6 @@
   return quota;
 }
 
-void MaybeDumpWithoutCrashing(int quota_used) {
-  static const int crash_theshold =
-      kMojoRecordUnreadMessageCountCrashThreshold.Get();
-  if (crash_theshold == 0)
-    return;
-
-  static bool have_crashed = false;
-  if (have_crashed)
-    return;
-
-  // Only crash once per process/per run. Note that this is slightly racy
-  // against concurrent quota overruns on multiple threads, but that's fine.
-  have_crashed = true;
-
-  // This is happening because the user of the interface implicated on the crash
-  // stack has queued up an unreasonable number of messages, namely
-  // |quota_used|.
-  base::debug::DumpWithoutCrashing();
-}
-
 }  // namespace
 
 // Used to efficiently maintain a doubly-linked list of all Connectors
@@ -394,10 +368,8 @@
     MojoResult rv = MojoQueryQuota(message_pipe_.get().value(),
                                    MOJO_QUOTA_TYPE_UNREAD_MESSAGE_COUNT,
                                    nullptr, &limit, &usage);
-    if (rv == MOJO_RESULT_OK && usage > max_unread_message_quota_used_) {
-      MaybeDumpWithoutCrashing(usage);
+    if (rv == MOJO_RESULT_OK && usage > max_unread_message_quota_used_)
       max_unread_message_quota_used_ = usage;
-    }
   }
 
   MojoResult rv =
diff --git a/net/cookies/cookie_util.cc b/net/cookies/cookie_util.cc
index 19dafb80..4618c78 100644
--- a/net/cookies/cookie_util.cc
+++ b/net/cookies/cookie_util.cc
@@ -419,25 +419,25 @@
   //   target a top-level browsing context.
   //
   // * Include both "strict" and "lax" same-site cookies if the request is
-  //   tagged with a flag allowing it and "lax" would have been allowed had
-  //   |http_method| been safe.
+  //   tagged with a flag allowing it.
   //
   //   Note that this can be the case for requests initiated by extensions,
   //   which need to behave as though they are made by the document itself,
   //   but appear like cross-site ones.
   //
   // * Otherwise, do not include same-site cookies.
+  if (attach_same_site_cookies)
+    return CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT;
+
   CookieOptions::SameSiteCookieContext same_site_context =
       ComputeSameSiteContext(url, site_for_cookies, initiator);
+
+  // If the method is safe, the context is Lax. Otherwise, make a note that
+  // the method is unsafe.
   if (same_site_context ==
-      CookieOptions::SameSiteCookieContext::SAME_SITE_LAX) {
-    if (attach_same_site_cookies) {
-      same_site_context =
-          CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT;
-    } else if (!net::HttpUtil::IsMethodSafe(http_method)) {
-      same_site_context =
-          CookieOptions::SameSiteCookieContext::SAME_SITE_LAX_METHOD_UNSAFE;
-    }
+          CookieOptions::SameSiteCookieContext::SAME_SITE_LAX &&
+      !net::HttpUtil::IsMethodSafe(http_method)) {
+    return CookieOptions::SameSiteCookieContext::SAME_SITE_LAX_METHOD_UNSAFE;
   }
   return same_site_context;
 }
diff --git a/net/cookies/cookie_util.h b/net/cookies/cookie_util.h
index 57cc28f..1756048 100644
--- a/net/cookies/cookie_util.h
+++ b/net/cookies/cookie_util.h
@@ -97,6 +97,9 @@
 // the user directly interacting with the browser UI, e.g. entering a URL
 // or selecting a bookmark.
 //
+// If |attach_same_site_cookies| is specified, all SameSite cookies will be
+// attached.
+//
 // See also documentation for corresponding methods on net::URLRequest.
 //
 // |http_method| is used to enforce the requirement that, in a context that's
diff --git a/net/cookies/cookie_util_unittest.cc b/net/cookies/cookie_util_unittest.cc
index 10dd9c5..3f832d6 100644
--- a/net/cookies/cookie_util_unittest.cc
+++ b/net/cookies/cookie_util_unittest.cc
@@ -318,8 +318,7 @@
           "GET", GURL("http://example.com"), GURL("http://notexample.com"),
           base::nullopt /*initiator*/, false /*attach_same_site_cookies*/));
 
-  // |attach_same_site_cookies| = true bypasses method and initiator
-  // checks, but not the |site_for_cookies| one.
+  // |attach_same_site_cookies| = true bypasses all checks.
   EXPECT_EQ(CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT,
             cookie_util::ComputeSameSiteContextForRequest(
                 "GET", GURL("http://example.com"), GURL("http://example.com"),
@@ -332,7 +331,7 @@
                 url::Origin::Create(GURL("http://from-elsewhere.com")),
                 true /*attach_same_site_cookies*/));
 
-  EXPECT_EQ(CookieOptions::SameSiteCookieContext::CROSS_SITE,
+  EXPECT_EQ(CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT,
             cookie_util::ComputeSameSiteContextForRequest(
                 "GET", GURL("http://example.com"), GURL("http://question.com"),
                 url::Origin::Create(GURL("http://from-elsewhere.com")),
diff --git a/net/http/http_stream_factory_job_controller_unittest.cc b/net/http/http_stream_factory_job_controller_unittest.cc
index ff2470a..4569b74 100644
--- a/net/http/http_stream_factory_job_controller_unittest.cc
+++ b/net/http/http_stream_factory_job_controller_unittest.cc
@@ -1976,8 +1976,10 @@
   EXPECT_FALSE(job_controller_->alternative_job());
 }
 
+// TODO(https://crbug.com/1007502): Disabled because the pending task count does
+//                                  not match expectations.
 TEST_F(HttpStreamFactoryJobControllerTest,
-       ResumeMainJobImmediatelyOnStreamFailed) {
+       DISABLED_ResumeMainJobImmediatelyOnStreamFailed) {
   HttpRequestInfo request_info;
   request_info.method = "GET";
   request_info.url = GURL("https://www.google.com");
diff --git a/net/quic/quic_connection_logger.cc b/net/quic/quic_connection_logger.cc
index 268d767..ab46d82 100644
--- a/net/quic/quic_connection_logger.cc
+++ b/net/quic/quic_connection_logger.cc
@@ -289,11 +289,7 @@
       num_blocked_frames_received_(0),
       num_blocked_frames_sent_(0),
       connection_description_(connection_description),
-      socket_performance_watcher_(std::move(socket_performance_watcher)),
-      net_log_is_capturing_(net_log_.IsCapturing()) {
-  timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(1), this,
-               &QuicConnectionLogger::UpdateIsCapturing);
-}
+      socket_performance_watcher_(std::move(socket_performance_watcher)) {}
 
 QuicConnectionLogger::~QuicConnectionLogger() {
   UMA_HISTOGRAM_COUNTS_1M("Net.QuicSession.OutOfOrderPacketsReceived",
@@ -389,7 +385,7 @@
     default:
       DCHECK(false) << "Illegal frame type: " << frame.type;
   }
-  if (!net_log_is_capturing_)
+  if (!net_log_.IsCapturing())
     return;
   switch (frame.type) {
     case quic::PADDING_FRAME:
@@ -484,7 +480,7 @@
     quic::QuicPacketNumber original_packet_number,
     quic::TransmissionType transmission_type,
     quic::QuicTime sent_time) {
-  if (!net_log_is_capturing_)
+  if (!net_log_.IsCapturing())
     return;
   if (!original_packet_number.IsInitialized()) {
     net_log_.AddEvent(NetLogEventType::QUIC_SESSION_PACKET_SENT, [&] {
@@ -503,7 +499,7 @@
     quic::QuicPacketNumber lost_packet_number,
     quic::TransmissionType transmission_type,
     quic::QuicTime detection_time) {
-  if (!net_log_is_capturing_)
+  if (!net_log_.IsCapturing())
     return;
   net_log_.AddEvent(NetLogEventType::QUIC_SESSION_PACKET_LOST, [&] {
     return NetLogQuicPacketLostParams(lost_packet_number, transmission_type,
@@ -529,7 +525,7 @@
 
   previous_received_packet_size_ = last_received_packet_size_;
   last_received_packet_size_ = packet.length();
-  if (!net_log_is_capturing_)
+  if (!net_log_.IsCapturing())
     return;
   net_log_.AddEvent(NetLogEventType::QUIC_SESSION_PACKET_RECEIVED, [&] {
     return NetLogQuicPacketParams(self_address, peer_address, packet.length());
@@ -538,7 +534,7 @@
 
 void QuicConnectionLogger::OnUnauthenticatedHeader(
     const quic::QuicPacketHeader& header) {
-  if (!net_log_is_capturing_)
+  if (!net_log_.IsCapturing())
     return;
   net_log_.AddEvent(
       NetLogEventType::QUIC_SESSION_UNAUTHENTICATED_PACKET_HEADER_RECEIVED,
@@ -557,7 +553,7 @@
 void QuicConnectionLogger::OnDuplicatePacket(
     quic::QuicPacketNumber packet_number) {
   ++num_duplicate_packets_;
-  if (!net_log_is_capturing_)
+  if (!net_log_.IsCapturing())
     return;
   net_log_.AddEvent(
       NetLogEventType::QUIC_SESSION_DUPLICATE_PACKET_RECEIVED,
@@ -617,13 +613,13 @@
     no_packet_received_after_ping_ = false;
   }
   last_received_packet_number_ = header.packet_number;
-  if (!net_log_is_capturing_)
+  if (!net_log_.IsCapturing())
     return;
   net_log_.AddEvent(NetLogEventType::QUIC_SESSION_PACKET_AUTHENTICATED);
 }
 
 void QuicConnectionLogger::OnStreamFrame(const quic::QuicStreamFrame& frame) {
-  if (!net_log_is_capturing_)
+  if (!net_log_.IsCapturing())
     return;
   net_log_.AddEvent(NetLogEventType::QUIC_SESSION_STREAM_FRAME_RECEIVED,
                     [&] { return NetLogQuicStreamFrameParams(frame); });
@@ -644,7 +640,7 @@
                    first_received_packet_number_] = true;
   }
 
-  if (!net_log_is_capturing_)
+  if (!net_log_.IsCapturing())
     return;
   net_log_.AddEvent(NetLogEventType::QUIC_SESSION_ACK_FRAME_RECEIVED,
                     [&] { return NetLogQuicAckFrameParams(&frame); });
@@ -654,7 +650,7 @@
 
 void QuicConnectionLogger::OnStopWaitingFrame(
     const quic::QuicStopWaitingFrame& frame) {
-  if (!net_log_is_capturing_)
+  if (!net_log_.IsCapturing())
     return;
   net_log_.AddEvent(NetLogEventType::QUIC_SESSION_STOP_WAITING_FRAME_RECEIVED,
                     [&] { return NetLogQuicStopWaitingFrameParams(&frame); });
@@ -664,7 +660,7 @@
     const quic::QuicRstStreamFrame& frame) {
   base::UmaHistogramSparse("Net.QuicSession.RstStreamErrorCodeServer",
                            frame.error_code);
-  if (!net_log_is_capturing_)
+  if (!net_log_.IsCapturing())
     return;
   net_log_.AddEvent(NetLogEventType::QUIC_SESSION_RST_STREAM_FRAME_RECEIVED,
                     [&] { return NetLogQuicRstStreamFrameParams(&frame); });
@@ -672,7 +668,7 @@
 
 void QuicConnectionLogger::OnConnectionCloseFrame(
     const quic::QuicConnectionCloseFrame& frame) {
-  if (!net_log_is_capturing_)
+  if (!net_log_.IsCapturing())
     return;
   net_log_.AddEvent(
       NetLogEventType::QUIC_SESSION_CONNECTION_CLOSE_FRAME_RECEIVED,
@@ -682,7 +678,7 @@
 void QuicConnectionLogger::OnWindowUpdateFrame(
     const quic::QuicWindowUpdateFrame& frame,
     const quic::QuicTime& receive_time) {
-  if (!net_log_is_capturing_)
+  if (!net_log_.IsCapturing())
     return;
   net_log_.AddEvent(NetLogEventType::QUIC_SESSION_WINDOW_UPDATE_FRAME_RECEIVED,
                     [&] { return NetLogQuicWindowUpdateFrameParams(&frame); });
@@ -690,7 +686,7 @@
 
 void QuicConnectionLogger::OnBlockedFrame(const quic::QuicBlockedFrame& frame) {
   ++num_blocked_frames_received_;
-  if (!net_log_is_capturing_)
+  if (!net_log_.IsCapturing())
     return;
   net_log_.AddEvent(NetLogEventType::QUIC_SESSION_BLOCKED_FRAME_RECEIVED,
                     [&] { return NetLogQuicBlockedFrameParams(&frame); });
@@ -700,7 +696,7 @@
   UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.GoAwayReceivedForConnectionMigration",
                         frame.error_code == quic::QUIC_ERROR_MIGRATING_PORT);
 
-  if (!net_log_is_capturing_)
+  if (!net_log_.IsCapturing())
     return;
   net_log_.AddEvent(NetLogEventType::QUIC_SESSION_GOAWAY_FRAME_RECEIVED,
                     [&] { return NetLogQuicGoAwayFrameParams(&frame); });
@@ -708,7 +704,7 @@
 
 void QuicConnectionLogger::OnPingFrame(const quic::QuicPingFrame& frame) {
   // PingFrame has no contents to log, so just record that it was received.
-  if (!net_log_is_capturing_)
+  if (!net_log_.IsCapturing())
     return;
   net_log_.AddEvent(NetLogEventType::QUIC_SESSION_PING_FRAME_RECEIVED);
 }
@@ -717,7 +713,7 @@
     const quic::QuicPublicResetPacket& packet) {
   UpdatePublicResetAddressMismatchHistogram(
       local_address_from_shlo_, ToIPEndPoint(packet.client_address));
-  if (!net_log_is_capturing_)
+  if (!net_log_.IsCapturing())
     return;
   net_log_.AddEvent(NetLogEventType::QUIC_SESSION_PUBLIC_RESET_PACKET_RECEIVED,
                     [&] {
@@ -728,7 +724,7 @@
 
 void QuicConnectionLogger::OnVersionNegotiationPacket(
     const quic::QuicVersionNegotiationPacket& packet) {
-  if (!net_log_is_capturing_)
+  if (!net_log_.IsCapturing())
     return;
   net_log_.AddEvent(
       NetLogEventType::QUIC_SESSION_VERSION_NEGOTIATION_PACKET_RECEIVED,
@@ -760,7 +756,7 @@
       }
     }
   }
-  if (!net_log_is_capturing_)
+  if (!net_log_.IsCapturing())
     return;
   net_log_.AddEvent(
       NetLogEventType::QUIC_SESSION_CRYPTO_HANDSHAKE_MESSAGE_RECEIVED,
@@ -769,7 +765,7 @@
 
 void QuicConnectionLogger::OnCryptoHandshakeMessageSent(
     const quic::CryptoHandshakeMessage& message) {
-  if (!net_log_is_capturing_)
+  if (!net_log_.IsCapturing())
     return;
   net_log_.AddEvent(
       NetLogEventType::QUIC_SESSION_CRYPTO_HANDSHAKE_MESSAGE_SENT,
@@ -779,7 +775,7 @@
 void QuicConnectionLogger::OnConnectionClosed(
     const quic::QuicConnectionCloseFrame& frame,
     quic::ConnectionCloseSource source) {
-  if (!net_log_is_capturing_)
+  if (!net_log_.IsCapturing())
     return;
   net_log_.AddEvent(NetLogEventType::QUIC_SESSION_CLOSED, [&] {
     return NetLogQuicOnConnectionClosedParams(frame.quic_error_code,
@@ -789,7 +785,7 @@
 
 void QuicConnectionLogger::OnSuccessfulVersionNegotiation(
     const quic::ParsedQuicVersion& version) {
-  if (!net_log_is_capturing_)
+  if (!net_log_.IsCapturing())
     return;
   string quic_version = quic::ParsedQuicVersionToString(version);
   net_log_.AddEventWithStringParams(
@@ -810,7 +806,7 @@
 
 void QuicConnectionLogger::OnCertificateVerified(
     const CertVerifyResult& result) {
-  if (!net_log_is_capturing_)
+  if (!net_log_.IsCapturing())
     return;
   if (result.cert_status == CERT_STATUS_INVALID) {
     net_log_.AddEvent(NetLogEventType::QUIC_SESSION_CERTIFICATE_VERIFY_FAILED);
@@ -872,8 +868,4 @@
       ReceivedPacketLossRate() * 1000));
 }
 
-void QuicConnectionLogger::UpdateIsCapturing() {
-  net_log_is_capturing_ = net_log_.IsCapturing();
-}
-
 }  // namespace net
diff --git a/net/quic/quic_connection_logger.h b/net/quic/quic_connection_logger.h
index d987bf5..7c3e195 100644
--- a/net/quic/quic_connection_logger.h
+++ b/net/quic/quic_connection_logger.h
@@ -11,7 +11,6 @@
 #include <string>
 
 #include "base/macros.h"
-#include "base/timer/timer.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_export.h"
 #include "net/base/network_change_notifier.h"
@@ -111,8 +110,6 @@
   // the overall packet loss rate, and record it into a histogram.
   void RecordAggregatePacketLossRate() const;
 
-  void UpdateIsCapturing();
-
   NetLogWithSource net_log_;
   quic::QuicSpdySession* session_;  // Unowned.
   // The last packet number received.
@@ -175,10 +172,6 @@
   // Receives notifications regarding the performance of the underlying socket
   // for the QUIC connection. May be null.
   const std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher_;
-  // Lower the overhead of checking whether logging is active, by
-  // periodically polling and caching the result of net_log_.IsCapturing().
-  bool net_log_is_capturing_;
-  base::RepeatingTimer timer_;
 
   DISALLOW_COPY_AND_ASSIGN(QuicConnectionLogger);
 };
diff --git a/net/websockets/websocket_channel.cc b/net/websockets/websocket_channel.cc
index 3fb8aa1..91ec901f 100644
--- a/net/websockets/websocket_channel.cc
+++ b/net/websockets/websocket_channel.cc
@@ -597,6 +597,8 @@
     ignore_result(RespondToClosingHandshake());
   }
 
+  // TODO(crbug.com/999235): Remove this CHECK.
+  CHECK(event_interface_);
   while (!event_interface_->HasPendingDataFrames()) {
     DCHECK(stream_);
     // This use of base::Unretained is safe because this object owns the
@@ -614,6 +616,8 @@
       return CHANNEL_DELETED;
     }
     DCHECK_NE(CLOSED, state_);
+    // TODO(crbug.com/999235): Remove this CHECK.
+    CHECK(event_interface_);
   }
   return CHANNEL_ALIVE;
 }
diff --git a/ppapi/cpp/private/var_private.cc b/ppapi/cpp/private/var_private.cc
index fadd986..0dbe2dc 100644
--- a/ppapi/cpp/private/var_private.cc
+++ b/ppapi/cpp/private/var_private.cc
@@ -24,7 +24,7 @@
 
 }  // namespace
 
-using deprecated::ScriptableObject;
+using namespace deprecated;
 
 VarPrivate::VarPrivate(const InstanceHandle& instance,
                        ScriptableObject* object) {
diff --git a/services/tracing/public/cpp/trace_startup.cc b/services/tracing/public/cpp/trace_startup.cc
index 3991797..6f27245 100644
--- a/services/tracing/public/cpp/trace_startup.cc
+++ b/services/tracing/public/cpp/trace_startup.cc
@@ -13,6 +13,7 @@
 #include "components/tracing/common/tracing_switches.h"
 #include "services/tracing/public/cpp/perfetto/trace_event_data_source.h"
 #include "services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.h"
+#include "services/tracing/public/cpp/trace_event_agent.h"
 #include "services/tracing/public/cpp/tracing_features.h"
 
 namespace tracing {
@@ -85,6 +86,8 @@
   // Below are the things tracing must do once per process.
   TraceEventDataSource::GetInstance()->OnTaskSchedulerAvailable();
   if (base::FeatureList::IsEnabled(features::kEnablePerfettoSystemTracing)) {
+    // We have to ensure that we register all the data sources we care about.
+    TraceEventAgent::GetInstance();
     // To ensure System tracing connects we have to initialize the process wide
     // state. This Get() call ensures that the constructor has run.
     PerfettoTracedProcess::Get();
diff --git a/testing/buildbot/filters/bfcache.content_browsertests.filter b/testing/buildbot/filters/bfcache.content_browsertests.filter
index 3fb77ccd..0940316 100644
--- a/testing/buildbot/filters/bfcache.content_browsertests.filter
+++ b/testing/buildbot/filters/bfcache.content_browsertests.filter
@@ -52,10 +52,6 @@
 # happen when the BackForwardCache is used to store the old document.
 -RenderFrameHostManagerTest.RenderViewInitAfterNewProxyAndProcessKill
 
-# Waiting for unload handler, but they aren't executed.
--SitePerProcessBrowserTest.PartialUnloadHandler
--SitePerProcessBrowserTest.Unload_ABAB
-
 # FATAL:casting.h Security DCHECK failed: IsA<Derived>(from).
 # In content::RenderFrameProxy::OnSetFrameOwnerProperties()
 # https://crbug.com/999849
diff --git a/third_party/blink/public/mojom/frame/document_interface_broker.mojom b/third_party/blink/public/mojom/frame/document_interface_broker.mojom
index 63d012d..68d90163 100644
--- a/third_party/blink/public/mojom/frame/document_interface_broker.mojom
+++ b/third_party/blink/public/mojom/frame/document_interface_broker.mojom
@@ -6,7 +6,6 @@
 
 import "third_party/blink/public/mojom/credentialmanager/credential_manager.mojom";
 import "third_party/blink/public/mojom/frame/frame_host_test_interface.mojom";
-import "third_party/blink/public/mojom/push_messaging/push_messaging.mojom";
 import "third_party/blink/public/mojom/webauthn/authenticator.mojom";
 import "third_party/blink/public/mojom/webauthn/virtual_authenticator.mojom";
 
@@ -30,11 +29,6 @@
   GetFrameHostTestInterface(
       pending_receiver<blink.mojom.FrameHostTestInterface> receiver);
 
-  // Binds the blink.mojom.PushMessaging pending receiver to its remote
-  // implementation in the browser process, to allow subscribing, unsubscribing
-  // and retrieving subscriptions related to push notifications (see Push API).
-  GetPushMessaging(pending_receiver<blink.mojom.PushMessaging> receiver);
-
   // Binds the blink.test.mojom.VirtualAuthenticatorManager pending receiver to
   // its remote implementation in the browser process, to manage a virtual
   // environment that allows talking virtual authenticators via the WebAuth API.
diff --git a/third_party/blink/renderer/core/animation/animation.cc b/third_party/blink/renderer/core/animation/animation.cc
index 043be4d..f0b31f0 100644
--- a/third_party/blink/renderer/core/animation/animation.cc
+++ b/third_party/blink/renderer/core/animation/animation.cc
@@ -154,6 +154,7 @@
                      AnimationEffect* content)
     : ContextLifecycleObserver(execution_context),
       internal_play_state_(kIdle),
+      reported_play_state_(kIdle),
       animation_play_state_(kIdle),
       playback_rate_(1),
       start_time_(),
@@ -1449,31 +1450,8 @@
 Animation::PlayStateUpdateScope::~PlayStateUpdateScope() {
   AnimationPlayState old_play_state = initial_play_state_;
   AnimationPlayState new_play_state = animation_->CalculatePlayState();
-
-  // TODO(crbug.com/958433): Phase out internal_play_state_ in favor of the spec
-  // compliant version. At present, both are needed as the web exposed play
-  // state cannot simply be inferred from the internal play state.
   animation_->internal_play_state_ = new_play_state;
   animation_->animation_play_state_ = animation_->CalculateAnimationPlayState();
-  if (old_play_state != new_play_state) {
-    bool was_active = old_play_state == kPending || old_play_state == kRunning;
-    bool is_active = new_play_state == kPending || new_play_state == kRunning;
-    if (!was_active && is_active) {
-      TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(
-          "blink.animations,devtools.timeline,benchmark,rail", "Animation",
-          animation_, "data", inspector_animation_event::Data(*animation_));
-    } else if (was_active && !is_active) {
-      TRACE_EVENT_NESTABLE_ASYNC_END1(
-          "blink.animations,devtools.timeline,benchmark,rail", "Animation",
-          animation_, "endData",
-          inspector_animation_state_event::Data(*animation_));
-    } else {
-      TRACE_EVENT_NESTABLE_ASYNC_INSTANT1(
-          "blink.animations,devtools.timeline,benchmark,rail", "Animation",
-          animation_, "data",
-          inspector_animation_state_event::Data(*animation_));
-    }
-  }
 
   // Ordering is important, the ready promise should resolve/reject before
   // the finished promise.
@@ -1539,11 +1517,7 @@
       break;
   }
   animation_->EndUpdatingState();
-
-  if (old_play_state != new_play_state) {
-    probe::AnimationPlayStateChanged(animation_->document_, animation_,
-                                     old_play_state, new_play_state);
-  }
+  animation_->NotifyProbe();
 }
 
 void Animation::AddedEventListener(
@@ -1624,6 +1598,35 @@
   }
 }
 
+void Animation::NotifyProbe() {
+  AnimationPlayState old_play_state = reported_play_state_;
+  AnimationPlayState new_play_state =
+      pending() ? kPending : CalculateAnimationPlayState();
+
+  if (old_play_state != new_play_state) {
+    probe::AnimationPlayStateChanged(document_, this, old_play_state,
+                                     new_play_state);
+    reported_play_state_ = new_play_state;
+
+    bool was_active = old_play_state == kPending || old_play_state == kRunning;
+    bool is_active = new_play_state == kPending || new_play_state == kRunning;
+
+    if (!was_active && is_active) {
+      TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(
+          "blink.animations,devtools.timeline,benchmark,rail", "Animation",
+          this, "data", inspector_animation_event::Data(*this));
+    } else if (was_active && !is_active) {
+      TRACE_EVENT_NESTABLE_ASYNC_END1(
+          "blink.animations,devtools.timeline,benchmark,rail", "Animation",
+          this, "endData", inspector_animation_state_event::Data(*this));
+    } else {
+      TRACE_EVENT_NESTABLE_ASYNC_INSTANT1(
+          "blink.animations,devtools.timeline,benchmark,rail", "Animation",
+          this, "data", inspector_animation_state_event::Data(*this));
+    }
+  }
+}
+
 void Animation::Trace(blink::Visitor* visitor) {
   visitor->Trace(content_);
   visitor->Trace(document_);
diff --git a/third_party/blink/renderer/core/animation/animation.h b/third_party/blink/renderer/core/animation/animation.h
index 313f50c7..7980dd8 100644
--- a/third_party/blink/renderer/core/animation/animation.h
+++ b/third_party/blink/renderer/core/animation/animation.h
@@ -322,11 +322,20 @@
   double TimelineTime() const;
   DocumentTimeline& TickingTimeline();
 
+  // Tracking the state of animations in dev tools.
+  void NotifyProbe();
+
   String id_;
 
   // Extended play state with additional pending state for managing timing of
   // micro-tasks.
+  // TODO(crbug.com/958433): Phase out this version of the play state. Should
+  // just need the reported play state.
   AnimationPlayState internal_play_state_;
+  // Extended play state reported to dev tools. This play state has an
+  // additional pending state that is not part of the spec by expected by dev
+  // tools.
+  AnimationPlayState reported_play_state_;
   // Web exposed play state, which does not have pending state.
   AnimationPlayState animation_play_state_;
   double playback_rate_;
diff --git a/third_party/blink/renderer/core/animation/effect_input.cc b/third_party/blink/renderer/core/animation/effect_input.cc
index b832673a..50bdcf3 100644
--- a/third_party/blink/renderer/core/animation/effect_input.cc
+++ b/third_party/blink/renderer/core/animation/effect_input.cc
@@ -228,8 +228,8 @@
 
   v8::TryCatch try_catch(isolate);
   for (const auto& property : keyframe_properties) {
-    if (property == "offset" || property == "composite" ||
-        property == "easing") {
+    if (property == "offset" || property == "float" ||
+        property == "composite" || property == "easing") {
       continue;
     }
 
@@ -490,8 +490,8 @@
             WTF::CodeUnitCompareLessThan);
 
   for (const auto& property : keyframe_properties) {
-    if (property == "offset" || property == "composite" ||
-        property == "easing") {
+    if (property == "offset" || property == "float" ||
+        property == "composite" || property == "easing") {
       continue;
     }
 
diff --git a/third_party/blink/renderer/core/animation/keyframe_effect.cc b/third_party/blink/renderer/core/animation/keyframe_effect.cc
index 09beef4..36c2d0c 100644
--- a/third_party/blink/renderer/core/animation/keyframe_effect.cc
+++ b/third_party/blink/renderer/core/animation/keyframe_effect.cc
@@ -140,6 +140,9 @@
 void KeyframeEffect::setComposite(String composite_string) {
   Model()->SetComposite(
       EffectModel::StringToCompositeOperation(composite_string).value());
+
+  ClearEffects();
+  InvalidateAndNotifyOwner();
 }
 
 HeapVector<ScriptValue> KeyframeEffect::getKeyframes(
diff --git a/third_party/blink/renderer/core/animation/keyframe_effect_model.cc b/third_party/blink/renderer/core/animation/keyframe_effect_model.cc
index 5c4d32e..ef9b74ee 100644
--- a/third_party/blink/renderer/core/animation/keyframe_effect_model.cc
+++ b/third_party/blink/renderer/core/animation/keyframe_effect_model.cc
@@ -62,11 +62,8 @@
 void KeyframeEffectModelBase::SetFrames(HeapVector<K>& keyframes) {
   // TODO(samli): Should also notify/invalidate the animation
   keyframes_.clear();
-  keyframe_groups_ = nullptr;
-  interpolation_effect_->Clear();
-  last_fraction_ = std::numeric_limits<double>::quiet_NaN();
   keyframes_.AppendVector(keyframes);
-  needs_compositor_keyframes_snapshot_ = true;
+  ClearCachedData();
 }
 
 template CORE_EXPORT void KeyframeEffectModelBase::SetFrames(
@@ -74,6 +71,11 @@
 template CORE_EXPORT void KeyframeEffectModelBase::SetFrames(
     HeapVector<Member<StringKeyframe>>& keyframes);
 
+void KeyframeEffectModelBase::SetComposite(CompositeOperation composite) {
+  composite_ = composite;
+  ClearCachedData();
+}
+
 bool KeyframeEffectModelBase::Sample(
     int iteration,
     double fraction,
@@ -391,6 +393,13 @@
   interpolation_effect_->SetPopulated();
 }
 
+void KeyframeEffectModelBase::ClearCachedData() {
+  keyframe_groups_ = nullptr;
+  interpolation_effect_->Clear();
+  last_fraction_ = std::numeric_limits<double>::quiet_NaN();
+  needs_compositor_keyframes_snapshot_ = true;
+}
+
 bool KeyframeEffectModelBase::IsReplaceOnly() const {
   EnsureKeyframeGroups();
   for (const auto& entry : *keyframe_groups_) {
diff --git a/third_party/blink/renderer/core/animation/keyframe_effect_model.h b/third_party/blink/renderer/core/animation/keyframe_effect_model.h
index 2d2a2e60..54224d1 100644
--- a/third_party/blink/renderer/core/animation/keyframe_effect_model.h
+++ b/third_party/blink/renderer/core/animation/keyframe_effect_model.h
@@ -91,7 +91,7 @@
   void SetFrames(HeapVector<K>& keyframes);
 
   CompositeOperation Composite() const { return composite_; }
-  void SetComposite(CompositeOperation composite) { composite_ = composite; }
+  void SetComposite(CompositeOperation composite);
 
   const PropertySpecificKeyframeVector* GetPropertySpecificKeyframes(
       const PropertyHandle& property) const {
@@ -170,6 +170,9 @@
   void EnsureKeyframeGroups() const;
   void EnsureInterpolationEffectPopulated() const;
 
+  // Clears the various bits of cached data that this class has.
+  void ClearCachedData();
+
   using ShouldSnapshotPropertyCallback =
       std::function<bool(const PropertyHandle&)>;
   using ShouldSnapshotKeyframeCallback =
diff --git a/third_party/blink/renderer/core/animation/timing.cc b/third_party/blink/renderer/core/animation/timing.cc
index 63c25d4a..ade75c7 100644
--- a/third_party/blink/renderer/core/animation/timing.cc
+++ b/third_party/blink/renderer/core/animation/timing.cc
@@ -223,7 +223,9 @@
   // https://drafts.csswg.org/web-animations-1/#current
   calculated.is_current = calculated.is_in_play ||
                           (playback_rate.has_value() && playback_rate > 0 &&
-                           calculated.phase == Timing::kPhaseBefore);
+                           calculated.phase == Timing::kPhaseBefore) ||
+                          (playback_rate.has_value() && playback_rate < 0 &&
+                           calculated.phase == Timing::kPhaseAfter);
   calculated.local_time = local_time;
   calculated.time_to_next_iteration = time_to_next_iteration;
 
diff --git a/third_party/blink/renderer/core/css/parser/sizes_calc_parser.cc b/third_party/blink/renderer/core/css/parser/sizes_calc_parser.cc
index ab825e8..b1f26458 100644
--- a/third_party/blink/renderer/core/css/parser/sizes_calc_parser.cc
+++ b/third_party/blink/renderer/core/css/parser/sizes_calc_parser.cc
@@ -94,6 +94,16 @@
     return !comma_count;
   }
 
+  if (left_side.FunctionId() == CSSValueID::kClamp) {
+    if (comma_count != 2)
+      return false;
+    // Convert clamp(MIN, VAL, MAX) into max(MIN, min(VAL, MAX))
+    // https://www.w3.org/TR/css-values-4/#calc-notation
+    value_list_.emplace_back(CSSMathOperator::kMin);
+    value_list_.emplace_back(CSSMathOperator::kMax);
+    return true;
+  }
+
   // Break variadic min/max() into binary operations to fit in the reverse
   // polish notation.
   CSSMathOperator op = left_side.FunctionId() == CSSValueID::kMin
@@ -170,8 +180,8 @@
       case kFunctionToken:
         if (RuntimeEnabledFeatures::CSSComparisonFunctionsEnabled()) {
           if (token.FunctionId() == CSSValueID::kMin ||
-              token.FunctionId() == CSSValueID::kMax) {
-            // TODO(crbug.com/825895): Add clamp() when min/max are done.
+              token.FunctionId() == CSSValueID::kMax ||
+              token.FunctionId() == CSSValueID::kClamp) {
             stack.push_back(token);
             break;
           }
diff --git a/third_party/blink/renderer/core/css/parser/sizes_calc_parser_test.cc b/third_party/blink/renderer/core/css/parser/sizes_calc_parser_test.cc
index c3601511..328daf6 100644
--- a/third_party/blink/renderer/core/css/parser/sizes_calc_parser_test.cc
+++ b/third_party/blink/renderer/core/css/parser/sizes_calc_parser_test.cc
@@ -151,6 +151,22 @@
       {"calc(min(100px, 200px) / max(3, 4, 5))", 20, true, false},
       {"max(10px, min(20px, 1em))", 16, true, false},
       {"min(20px, max(10px, 1em))", 16, true, false},
+      {"clamp(10px, 20px, 30px)", 20, true, false},
+      {"clamp(10px, 5px, 30px)", 10, true, false},
+      {"clamp(10px, 35px, 30px)", 30, true, false},
+      {"clamp(30px, 20px, 10px)", 30, true, false},
+      {"clamp(10px, 20px, clamp(20px, 30px, 40px))", 20, true, false},
+      {"clamp()", 0, false, false},
+      {"clamp( )", 0, false, false},
+      {"clamp(,)", 0, false, false},
+      {"clamp(1px, )", 0, false, false},
+      {"clamp(, 1px)", 0, false, false},
+      {"clamp(1px, 1px)", 0, false, false},
+      {"clamp(1px, , 1px)", 0, false, false},
+      {"clamp(, 1px, 1px)", 0, false, false},
+      {"clamp(1px, 1px, )", 0, false, false},
+      {"clamp(1px, 1px, 1px, )", 0, false, false},
+      {"clamp(1px 1px 1px)", 0, false, false},
       {nullptr, 0, true, false}  // Do not remove the terminator line.
   };
 
diff --git a/third_party/blink/renderer/core/css/properties/computed_style_utils.cc b/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
index 322d2b4..20ea659 100644
--- a/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
+++ b/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
@@ -13,6 +13,7 @@
 #include "third_party/blink/renderer/core/css/css_font_family_value.h"
 #include "third_party/blink/renderer/core/css/css_font_style_range_value.h"
 #include "third_party/blink/renderer/core/css/css_function_value.h"
+#include "third_party/blink/renderer/core/css/css_grid_auto_repeat_value.h"
 #include "third_party/blink/renderer/core/css/css_grid_line_names_value.h"
 #include "third_party/blink/renderer/core/css/css_initial_value.h"
 #include "third_party/blink/renderer/core/css/css_numeric_literal_value.h"
@@ -1128,15 +1129,47 @@
   STACK_ALLOCATED();
 
  public:
-  OrderedNamedLinesCollector(const ComputedStyle& style,
-                             bool is_row_axis,
-                             size_t auto_repeat_tracks_count)
+  OrderedNamedLinesCollector(const ComputedStyle& style, bool is_row_axis)
       : ordered_named_grid_lines_(is_row_axis
                                       ? style.OrderedNamedGridColumnLines()
                                       : style.OrderedNamedGridRowLines()),
         ordered_named_auto_repeat_grid_lines_(
             is_row_axis ? style.AutoRepeatOrderedNamedGridColumnLines()
-                        : style.AutoRepeatOrderedNamedGridRowLines()),
+                        : style.AutoRepeatOrderedNamedGridRowLines()) {}
+
+  bool IsEmpty() const {
+    return ordered_named_grid_lines_.IsEmpty() &&
+           ordered_named_auto_repeat_grid_lines_.IsEmpty();
+  }
+  virtual void CollectLineNamesForIndex(CSSGridLineNamesValue&,
+                                        size_t index) const;
+
+ protected:
+  enum NamedLinesType { kNamedLines, kAutoRepeatNamedLines };
+  void AppendLines(CSSGridLineNamesValue&, size_t index, NamedLinesType) const;
+
+  const OrderedNamedGridLines& ordered_named_grid_lines_;
+  const OrderedNamedGridLines& ordered_named_auto_repeat_grid_lines_;
+  DISALLOW_COPY_AND_ASSIGN(OrderedNamedLinesCollector);
+};
+
+class OrderedNamedLinesCollectorInsideRepeat
+    : public OrderedNamedLinesCollector {
+ public:
+  OrderedNamedLinesCollectorInsideRepeat(const ComputedStyle& style,
+                                         bool is_row_axis)
+      : OrderedNamedLinesCollector(style, is_row_axis) {}
+  void CollectLineNamesForIndex(CSSGridLineNamesValue&,
+                                size_t index) const override;
+};
+
+class OrderedNamedLinesCollectorInGridLayout
+    : public OrderedNamedLinesCollector {
+ public:
+  OrderedNamedLinesCollectorInGridLayout(const ComputedStyle& style,
+                                         bool is_row_axis,
+                                         size_t auto_repeat_tracks_count)
+      : OrderedNamedLinesCollector(style, is_row_axis),
         insertion_point_(is_row_axis
                              ? style.GridAutoRepeatColumnsInsertionPoint()
                              : style.GridAutoRepeatRowsInsertionPoint()),
@@ -1144,23 +1177,13 @@
         auto_repeat_track_list_length_(
             is_row_axis ? style.GridAutoRepeatColumns().size()
                         : style.GridAutoRepeatRows().size()) {}
-
-  bool IsEmpty() const {
-    return ordered_named_grid_lines_.IsEmpty() &&
-           ordered_named_auto_repeat_grid_lines_.IsEmpty();
-  }
-  void CollectLineNamesForIndex(CSSGridLineNamesValue&, size_t index) const;
+  void CollectLineNamesForIndex(CSSGridLineNamesValue&,
+                                size_t index) const override;
 
  private:
-  enum NamedLinesType { kNamedLines, kAutoRepeatNamedLines };
-  void AppendLines(CSSGridLineNamesValue&, size_t index, NamedLinesType) const;
-
-  const OrderedNamedGridLines& ordered_named_grid_lines_;
-  const OrderedNamedGridLines& ordered_named_auto_repeat_grid_lines_;
   size_t insertion_point_;
   size_t auto_repeat_total_tracks_;
   size_t auto_repeat_track_list_length_;
-  DISALLOW_COPY_AND_ASSIGN(OrderedNamedLinesCollector);
 };
 
 // RJW
@@ -1183,11 +1206,25 @@
   }
 }
 
-// RJW
 void OrderedNamedLinesCollector::CollectLineNamesForIndex(
     CSSGridLineNamesValue& line_names_value,
     size_t i) const {
   DCHECK(!IsEmpty());
+  AppendLines(line_names_value, i, kNamedLines);
+}
+
+void OrderedNamedLinesCollectorInsideRepeat::CollectLineNamesForIndex(
+    CSSGridLineNamesValue& line_names_value,
+    size_t i) const {
+  DCHECK(!IsEmpty());
+  AppendLines(line_names_value, i, kAutoRepeatNamedLines);
+}
+
+// RJW
+void OrderedNamedLinesCollectorInGridLayout::CollectLineNamesForIndex(
+    CSSGridLineNamesValue& line_names_value,
+    size_t i) const {
+  DCHECK(!IsEmpty());
   if (ordered_named_auto_repeat_grid_lines_.IsEmpty() || i < insertion_point_) {
     AppendLines(line_names_value, i, kNamedLines);
     return;
@@ -1249,6 +1286,31 @@
   return list;
 }
 
+template <typename T, typename F>
+void PopulateGridTrackList(CSSValueList* list,
+                           OrderedNamedLinesCollector& collector,
+                           const Vector<T>& tracks,
+                           F getTrackSize,
+                           wtf_size_t start,
+                           wtf_size_t end,
+                           size_t offset = 0) {
+  DCHECK_LE(end, tracks.size());
+  for (wtf_size_t i = start; i < end; ++i) {
+    AddValuesForNamedGridLinesAtIndex(collector, i + offset, *list);
+    list->Append(*getTrackSize(tracks[i]));
+  }
+  AddValuesForNamedGridLinesAtIndex(collector, end + offset, *list);
+}
+
+template <typename T, typename F>
+void PopulateGridTrackList(CSSValueList* list,
+                           OrderedNamedLinesCollector& collector,
+                           const Vector<T>& tracks,
+                           F getTrackSize) {
+  PopulateGridTrackList<T>(list, collector, tracks, getTrackSize, 0,
+                           tracks.size());
+}
+
 CSSValue* ComputedStyleUtils::ValueForGridTrackList(
     GridTrackSizingDirection direction,
     const LayoutObject* layout_object,
@@ -1275,36 +1337,54 @@
   if (track_list_is_empty)
     return CSSIdentifierValue::Create(CSSValueID::kNone);
 
-  size_t auto_repeat_total_tracks =
-      is_layout_grid
-          ? ToLayoutGrid(layout_object)->AutoRepeatCountForDirection(direction)
-          : 0;
-  OrderedNamedLinesCollector collector(style, is_row_axis,
-                                       auto_repeat_total_tracks);
   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
-  wtf_size_t insertion_index;
+
+  // If the element is a grid container, the resolved value is the used value,
+  // specifying track sizes in pixels and expanding the repeat() notation.
   if (is_layout_grid) {
     const auto* grid = ToLayoutGrid(layout_object);
-    Vector<LayoutUnit> computed_track_sizes =
-        grid->TrackSizesForComputedStyle(direction);
-    wtf_size_t num_tracks = computed_track_sizes.size();
-
-    for (wtf_size_t i = 0; i < num_tracks; ++i) {
-      AddValuesForNamedGridLinesAtIndex(collector, i, *list);
-      list->Append(*ZoomAdjustedPixelValue(computed_track_sizes[i], style));
-    }
-    AddValuesForNamedGridLinesAtIndex(collector, num_tracks + 1, *list);
-
-    insertion_index = num_tracks;
-  } else {
-    for (wtf_size_t i = 0; i < track_sizes.size(); ++i) {
-      AddValuesForNamedGridLinesAtIndex(collector, i, *list);
-      list->Append(*SpecifiedValueForGridTrackSize(track_sizes[i], style));
-    }
-    insertion_index = track_sizes.size();
+    OrderedNamedLinesCollectorInGridLayout collector(
+        style, is_row_axis, grid->AutoRepeatCountForDirection(direction));
+    PopulateGridTrackList(
+        list, collector, grid->TrackSizesForComputedStyle(direction),
+        [&](const LayoutUnit& v) { return ZoomAdjustedPixelValue(v, style); });
+    return list;
   }
-  // Those are the trailing <string>* allowed in the syntax.
-  AddValuesForNamedGridLinesAtIndex(collector, insertion_index, *list);
+
+  // Otherwise, the resolved value is the computed value, preserving repeat().
+  OrderedNamedLinesCollector collector(style, is_row_axis);
+  auto getTrackSize = [&](const GridTrackSize& v) {
+    return SpecifiedValueForGridTrackSize(v, style);
+  };
+
+  if (auto_repeat_track_sizes.IsEmpty()) {
+    // If there's no auto repeat(), just add all the line names and track sizes.
+    PopulateGridTrackList(list, collector, track_sizes, getTrackSize);
+    return list;
+  }
+
+  // Add the line names and track sizes that precede the auto repeat().
+  size_t auto_repeat_insertion_point =
+      is_row_axis ? style.GridAutoRepeatColumnsInsertionPoint()
+                  : style.GridAutoRepeatRowsInsertionPoint();
+  PopulateGridTrackList(list, collector, track_sizes, getTrackSize, 0,
+                        auto_repeat_insertion_point);
+
+  // Add a CSSGridAutoRepeatValue with the contents of the auto repeat().
+  AutoRepeatType auto_repeat_type = is_row_axis
+                                        ? style.GridAutoRepeatColumnsType()
+                                        : style.GridAutoRepeatRowsType();
+  CSSValueList* repeated_values = MakeGarbageCollected<CSSGridAutoRepeatValue>(
+      auto_repeat_type == AutoRepeatType::kAutoFill ? CSSValueID::kAutoFill
+                                                    : CSSValueID::kAutoFit);
+  OrderedNamedLinesCollectorInsideRepeat repeat_collector(style, is_row_axis);
+  PopulateGridTrackList(repeated_values, repeat_collector,
+                        auto_repeat_track_sizes, getTrackSize);
+  list->Append(*repeated_values);
+
+  // Add the line names and track sizes that follow the auto repeat().
+  PopulateGridTrackList(list, collector, track_sizes, getTrackSize,
+                        auto_repeat_insertion_point, track_sizes.size(), 1);
   return list;
 }
 
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_budget_test.cc b/third_party/blink/renderer/core/display_lock/display_lock_budget_test.cc
index 45601b5..630370d 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_budget_test.cc
+++ b/third_party/blink/renderer/core/display_lock/display_lock_budget_test.cc
@@ -485,7 +485,7 @@
   {
     auto* script_state = ToScriptStateForMainWorld(GetDocument().GetFrame());
     ScriptState::Scope scope(script_state);
-    element->getDisplayLockForBindings()->update(script_state);
+    element->getDisplayLockForBindings()->UpdateRendering(script_state);
     ResetBudget(std::move(budget_owned), element->GetDisplayLockContext());
   }
 
@@ -579,7 +579,7 @@
   {
     auto* script_state = ToScriptStateForMainWorld(GetDocument().GetFrame());
     ScriptState::Scope scope(script_state);
-    element->getDisplayLockForBindings()->update(script_state);
+    element->getDisplayLockForBindings()->UpdateRendering(script_state);
     ResetBudget(std::move(budget_owned), element->GetDisplayLockContext());
   }
 
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 0e6b6cb..3d2b4c0 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
@@ -36,7 +36,6 @@
 double kDefaultLockTimeoutMs = 1000.;
 
 namespace rejection_names {
-const char* kElementIsUnlocked = "Element is unlocked.";
 const char* kExecutionContextDestroyed = "Execution context destroyed.";
 const char* kContainmentNotSatisfied =
     "Containment requirement is not satisfied.";
@@ -262,13 +261,11 @@
   MarkPaintLayerNeedsRepaint();
 }
 
-ScriptPromise DisplayLockContext::update(ScriptState* script_state) {
-  TRACE_EVENT0("blink", "DisplayLockContext::update()");
-  // Reject if we're unlocked or disconnected.
-  if (state_ == kUnlocked || !ConnectedToView()) {
-    return GetRejectedPromise(script_state,
-                              rejection_names::kElementIsUnlocked);
-  }
+ScriptPromise DisplayLockContext::UpdateRendering(ScriptState* script_state) {
+  TRACE_EVENT0("blink", "DisplayLockContext::UpdateRendering");
+  // Immediately resolve if we're unlocked or disconnected.
+  if (state_ == kUnlocked || !ConnectedToView())
+    return GetResolvedPromise(script_state);
 
   // If we have a resolver, then we're at least updating already, just return
   // the same promise.
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.h b/third_party/blink/renderer/core/display_lock/display_lock_context.h
index 1a38b2af..0a330de 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context.h
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context.h
@@ -103,7 +103,6 @@
   // JavaScript interface implementation. See display_lock_context.idl for
   // description.
   ScriptPromise acquire(ScriptState*, DisplayLockOptions*);
-  ScriptPromise update(ScriptState*);
   ScriptPromise commit(ScriptState*);
   ScriptPromise updateAndCommit(ScriptState*);
 
@@ -113,6 +112,8 @@
   void StartAcquire();
   // Initiate a commit.
   void StartCommit();
+  // Update rendering of the subtree.
+  ScriptPromise UpdateRendering(ScriptState*);
 
   // Lifecycle observation / state functions.
   bool ShouldStyle(DisplayLockLifecycleTarget) const;
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.idl b/third_party/blink/renderer/core/display_lock/display_lock_context.idl
index 00e9ceb..60cad13 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context.idl
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context.idl
@@ -8,10 +8,6 @@
   // Returns a promise that resolves when the lock is acquired.
   [CallWith=ScriptState] Promise<any> acquire(optional DisplayLockOptions options);
 
-  // Causes co-operative updates to happen on the locked subtree.
-  // Returns a promise that resolves when the update is finished.
-  [CallWith=ScriptState] Promise<any> update();
-
   // Commits the locked subtree, which releases the lock and updates any
   // necessary lifecycle phases.
   // Returns a promise that resolves when the commit is finished.
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 bf1a0f1..e92b576 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
@@ -1581,7 +1581,7 @@
   auto* script_state = ToScriptStateForMainWorld(GetDocument().GetFrame());
   {
     ScriptState::Scope scope(script_state);
-    container->GetDisplayLockContext()->update(script_state);
+    container->GetDisplayLockContext()->UpdateRendering(script_state);
   }
   auto budget = base::WrapUnique(
       new StrictYieldingDisplayLockBudget(container->GetDisplayLockContext()));
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index e34f541..2fad6d0 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -32,6 +32,7 @@
 #include "cc/input/snap_selection_strategy.h"
 #include "third_party/blink/public/platform/web_scroll_into_view_params.h"
 #include "third_party/blink/renderer/bindings/core/v8/dictionary.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/bindings/core/v8/scroll_into_view_options_or_boolean.h"
 #include "third_party/blink/renderer/bindings/core/v8/string_or_trusted_html.h"
 #include "third_party/blink/renderer/bindings/core/v8/string_or_trusted_html_or_trusted_script_or_trusted_script_url_or_trusted_url.h"
@@ -4525,6 +4526,16 @@
       this, GetExecutionContext());
 }
 
+ScriptPromise Element::updateRendering(ScriptState* script_state) {
+  auto* context = GetDisplayLockContext();
+  if (context)
+    return context->UpdateRendering(script_state);
+  auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+  auto promise = resolver->Promise();
+  resolver->Resolve();
+  return promise;
+}
+
 // Step 1 of http://domparsing.spec.whatwg.org/#insertadjacenthtml()
 static Element* ContextElementForInsertion(const String& where,
                                            Element* element,
diff --git a/third_party/blink/renderer/core/dom/element.h b/third_party/blink/renderer/core/dom/element.h
index af7ec18..16b8e929 100644
--- a/third_party/blink/renderer/core/dom/element.h
+++ b/third_party/blink/renderer/core/dom/element.h
@@ -77,6 +77,7 @@
 class PseudoElementStyleRequest;
 class ResizeObservation;
 class ResizeObserver;
+class ScriptPromise;
 class ScrollIntoViewOptions;
 class ScrollIntoViewOptionsOrBoolean;
 class ScrollToOptions;
@@ -932,6 +933,8 @@
   DisplayLockContext* GetDisplayLockContext() const;
   DisplayLockContext& EnsureDisplayLockContext();
 
+  ScriptPromise updateRendering(ScriptState*);
+
   bool StyleRecalcBlockedByDisplayLock(DisplayLockLifecycleTarget) const;
 
   // Activates all activatable locked ancestors for this element. Return true if
diff --git a/third_party/blink/renderer/core/dom/element.idl b/third_party/blink/renderer/core/dom/element.idl
index 700ae6a..64f8140f 100644
--- a/third_party/blink/renderer/core/dom/element.idl
+++ b/third_party/blink/renderer/core/dom/element.idl
@@ -147,6 +147,7 @@
     [RuntimeEnabled=DisplayLocking, ImplementedAs=getDisplayLockForBindings] readonly attribute DisplayLockContext displayLock;
     // Declarative display locking.
     [RuntimeEnabled=DisplayLocking, CEReactions, CustomElementCallbacks, Reflect] attribute DOMString renderSubtree;
+    [RuntimeEnabled=DisplayLocking, CallWith=ScriptState] Promise<any> updateRendering();
 
     // Element Timing
     [RuntimeEnabled=ElementTiming, Affects=Nothing, CEReactions, Reflect=elementtiming] attribute DOMString elementTiming;
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
index 90c057be..3000be8 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
@@ -950,6 +950,9 @@
       case ContentSecurityPolicy::kTrustedTypesViolation:
         init->setBlockedURI("trusted-types");
         break;
+      case ContentSecurityPolicy::kTrustedTypesPolicyViolation:
+        init->setBlockedURI("trusted-types-policy");
+        break;
     }
   }
 
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy.h b/third_party/blink/renderer/core/frame/csp/content_security_policy.h
index ff796d4..833641f 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy.h
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy.h
@@ -137,11 +137,15 @@
   // https://w3c.github.io/webappsec-csp/#violation-resource. By the time we
   // generate a report, we're guaranteed that the value isn't 'null', so we
   // don't need that state in this enum.
+  //
+  // Trusted Types violation's 'resource' values are defined in
+  // https://wicg.github.io/trusted-types/dist/spec/#csp-violation-object-hdr.
   enum ViolationType {
     kInlineViolation,
     kEvalViolation,
     kURLViolation,
-    kTrustedTypesViolation
+    kTrustedTypesViolation,
+    kTrustedTypesPolicyViolation
   };
 
   // The |type| argument given to inline checks, e.g.:
diff --git a/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc b/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc
index ea30233..5a15d80 100644
--- a/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc
+++ b/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc
@@ -872,7 +872,8 @@
           "\"%s\".",
           policy_name.Utf8().c_str(),
           trusted_types_.Get()->GetText().Utf8().c_str()),
-      KURL(), RedirectStatus::kNoRedirect);
+      KURL(), RedirectStatus::kNoRedirect,
+      ContentSecurityPolicy::kTrustedTypesPolicyViolation, policy_name);
 
   return DenyIfEnforcingPolicy();
 }
diff --git a/third_party/blink/renderer/core/layout/layout_block.cc b/third_party/blink/renderer/core/layout/layout_block.cc
index c8a3e46..961f989 100644
--- a/third_party/blink/renderer/core/layout/layout_block.cc
+++ b/third_party/blink/renderer/core/layout/layout_block.cc
@@ -470,6 +470,9 @@
 }
 
 void LayoutBlock::AddVisualOverflowFromChildren() {
+  if (LayoutBlockedByDisplayLock(DisplayLockLifecycleTarget::kChildren))
+    return;
+
   if (ChildrenInline())
     To<LayoutBlockFlow>(this)->AddVisualOverflowFromInlineChildren();
   else
@@ -477,7 +480,7 @@
 }
 
 void LayoutBlock::AddLayoutOverflowFromChildren() {
-  if (DisplayLockInducesSizeContainment())
+  if (LayoutBlockedByDisplayLock(DisplayLockLifecycleTarget::kChildren))
     return;
 
   if (ChildrenInline())
@@ -571,6 +574,9 @@
 }
 
 void LayoutBlock::AddLayoutOverflowFromPositionedObjects() {
+  if (LayoutBlockedByDisplayLock(DisplayLockLifecycleTarget::kChildren))
+    return;
+
   TrackedLayoutBoxListHashSet* positioned_descendants = PositionedObjects();
   if (!positioned_descendants)
     return;
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow_line.cc b/third_party/blink/renderer/core/layout/layout_block_flow_line.cc
index 0c2558a..60ae999 100644
--- a/third_party/blink/renderer/core/layout/layout_block_flow_line.cc
+++ b/third_party/blink/renderer/core/layout/layout_block_flow_line.cc
@@ -2033,8 +2033,12 @@
       // |LayoutIfNeeded| should not mark itself and its ancestors to
       // |NeedsLayout|.
       for (const LayoutObject* parent = atomic_inline_child;
-           parent && parent != this; parent = parent->Parent())
-        DCHECK(!parent->NeedsLayout());
+           parent && parent != this; parent = parent->Parent()) {
+        DCHECK(!parent->SelfNeedsLayout());
+        DCHECK(!parent->NeedsLayout() ||
+               parent->LayoutBlockedByDisplayLock(
+                   DisplayLockLifecycleTarget::kChildren));
+      }
 #endif
     }
 
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index d76005f..6d21c1ba8 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -5542,6 +5542,8 @@
 DISABLE_CFI_PERF
 void LayoutBox::AddLayoutOverflowFromChild(const LayoutBox& child,
                                            const LayoutSize& delta) {
+  DCHECK(!LayoutBlockedByDisplayLock(DisplayLockLifecycleTarget::kChildren));
+
   // Never allow flow threads to propagate overflow up to a parent.
   if (child.IsLayoutFlowThread())
     return;
diff --git a/third_party/blink/renderer/core/layout/layout_multi_column_set.cc b/third_party/blink/renderer/core/layout/layout_multi_column_set.cc
index e351e069..924dd0e 100644
--- a/third_party/blink/renderer/core/layout/layout_multi_column_set.cc
+++ b/third_party/blink/renderer/core/layout/layout_multi_column_set.cc
@@ -540,6 +540,9 @@
 }
 
 void LayoutMultiColumnSet::AddVisualOverflowFromChildren() {
+  if (LayoutBlockedByDisplayLock(DisplayLockLifecycleTarget::kChildren))
+    return;
+
   // It's useless to calculate overflow if we haven't determined the page
   // logical height yet.
   if (!IsPageLogicalHeightKnown())
@@ -554,6 +557,9 @@
 }
 
 void LayoutMultiColumnSet::AddLayoutOverflowFromChildren() {
+  if (LayoutBlockedByDisplayLock(DisplayLockLifecycleTarget::kChildren))
+    return;
+
   // It's useless to calculate overflow if we haven't determined the page
   // logical height yet.
   if (!IsPageLogicalHeightKnown())
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc
index 4d591a9..06a9ac7 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc
@@ -86,6 +86,9 @@
 
 template <typename Base>
 void LayoutNGBlockFlowMixin<Base>::AddLayoutOverflowFromChildren() {
+  if (Base::LayoutBlockedByDisplayLock(DisplayLockLifecycleTarget::kChildren))
+    return;
+
   // |ComputeOverflow()| calls this, which is called from
   // |CopyFragmentDataToLayoutBox()| and |RecalcOverflow()|.
   // Add overflow from the last layout cycle.
diff --git a/third_party/blink/renderer/core/paint/nine_piece_image_painter.cc b/third_party/blink/renderer/core/paint/nine_piece_image_painter.cc
index 3d26d5c..9a4b67f7 100644
--- a/third_party/blink/renderer/core/paint/nine_piece_image_painter.cc
+++ b/third_party/blink/renderer/core/paint/nine_piece_image_painter.cc
@@ -181,6 +181,8 @@
       document, 1, border_image_rect.size.ToLayoutSize()));
   scoped_refptr<Image> image =
       style_image->GetImage(observer, document, style, FloatSize(image_size));
+  if (!image)
+    return true;
 
   TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "PaintImage",
                "data",
diff --git a/third_party/blink/renderer/core/paint/theme_painter_default.cc b/third_party/blink/renderer/core/paint/theme_painter_default.cc
index 1557e5d..da53fcb 100644
--- a/third_party/blink/renderer/core/paint/theme_painter_default.cc
+++ b/third_party/blink/renderer/core/paint/theme_painter_default.cc
@@ -334,7 +334,7 @@
   } else {
     // TODO(tkent): This should be 7.0 to match scroll bar buttons.
     float arrow_size =
-        (RuntimeEnabledFeatures::FormControlsRefreshEnabled() ? 12.0 : 6.0) *
+        (RuntimeEnabledFeatures::FormControlsRefreshEnabled() ? 8.0 : 6.0) *
         arrow_scale_factor;
     // Put the arrow at the center of paddingForArrow area.
     // |arrowX| is the left position for Aura theme engine.
diff --git a/third_party/blink/renderer/devtools/BUILD.gn b/third_party/blink/renderer/devtools/BUILD.gn
index f95ebbf..c5386b70 100644
--- a/third_party/blink/renderer/devtools/BUILD.gn
+++ b/third_party/blink/renderer/devtools/BUILD.gn
@@ -139,7 +139,25 @@
   "front_end/color_picker/module.json",
   "front_end/color_picker/spectrum.css",
   "front_end/color_picker/Spectrum.js",
+  "front_end/common/CharacterIdMap.js",
+  "front_end/common/Color.js",
+  "front_end/common/Console.js",
+  "front_end/common/ContentProvider.js",
   "front_end/common/module.json",
+  "front_end/common/ModuleExtensionInterfaces.js",
+  "front_end/common/Object.js",
+  "front_end/common/OutputStream.js",
+  "front_end/common/ParsedURL.js",
+  "front_end/common/Progress.js",
+  "front_end/common/ResourceType.js",
+  "front_end/common/SegmentedRange.js",
+  "front_end/common/Settings.js",
+  "front_end/common/StaticContentProvider.js",
+  "front_end/common/TextDictionary.js",
+  "front_end/common/Throttler.js",
+  "front_end/common/Trie.js",
+  "front_end/common/UIString.js",
+  "front_end/common/Worker.js",
   "front_end/components/DockController.js",
   "front_end/components/ImagePreview.js",
   "front_end/components/imagePreview.css",
@@ -943,32 +961,6 @@
   "front_end/root.js",
   "front_end/ui/ARIAUtils.js",
   "front_end/ui/ui.js",
-  "front_end/common/common.js",
-  "front_end/common/App.js",
-  "front_end/common/AppProvider.js",
-  "front_end/common/CharacterIdMap.js",
-  "front_end/common/Color.js",
-  "front_end/common/ContentProvider.js",
-  "front_end/common/EventTarget.js",
-  "front_end/common/JavaScriptMetaData.js",
-  "front_end/common/Linkifier.js",
-  "front_end/common/Object.js",
-  "front_end/common/Console.js",
-  "front_end/common/ParsedURL.js",
-  "front_end/common/Progress.js",
-  "front_end/common/QueryParamHandler.js",
-  "front_end/common/ResourceType.js",
-  "front_end/common/Revealer.js",
-  "front_end/common/Runnable.js",
-  "front_end/common/SegmentedRange.js",
-  "front_end/common/Settings.js",
-  "front_end/common/StaticContentProvider.js",
-  "front_end/common/StringOutputStream.js",
-  "front_end/common/TextDictionary.js",
-  "front_end/common/Throttler.js",
-  "front_end/common/Trie.js",
-  "front_end/common/UIString.js",
-  "front_end/common/Worker.js",
 ]
 
 devtools_test_files = [
@@ -1166,32 +1158,6 @@
   "$resources_out_dir/root.js",
   "$resources_out_dir/ui/ARIAUtils.js",
   "$resources_out_dir/ui/ui.js",
-  "$resources_out_dir/common/common.js",
-  "$resources_out_dir/common/App.js",
-  "$resources_out_dir/common/AppProvider.js",
-  "$resources_out_dir/common/CharacterIdMap.js",
-  "$resources_out_dir/common/Color.js",
-  "$resources_out_dir/common/ContentProvider.js",
-  "$resources_out_dir/common/EventTarget.js",
-  "$resources_out_dir/common/JavaScriptMetaData.js",
-  "$resources_out_dir/common/Linkifier.js",
-  "$resources_out_dir/common/Object.js",
-  "$resources_out_dir/common/Console.js",
-  "$resources_out_dir/common/ParsedURL.js",
-  "$resources_out_dir/common/Progress.js",
-  "$resources_out_dir/common/QueryParamHandler.js",
-  "$resources_out_dir/common/ResourceType.js",
-  "$resources_out_dir/common/Revealer.js",
-  "$resources_out_dir/common/Runnable.js",
-  "$resources_out_dir/common/SegmentedRange.js",
-  "$resources_out_dir/common/Settings.js",
-  "$resources_out_dir/common/StaticContentProvider.js",
-  "$resources_out_dir/common/StringOutputStream.js",
-  "$resources_out_dir/common/TextDictionary.js",
-  "$resources_out_dir/common/Throttler.js",
-  "$resources_out_dir/common/Trie.js",
-  "$resources_out_dir/common/UIString.js",
-  "$resources_out_dir/common/Worker.js",
 ]
 
 generated_applications = [
diff --git a/third_party/blink/renderer/devtools/front_end/audits/AuditsReportSelector.js b/third_party/blink/renderer/devtools/front_end/audits/AuditsReportSelector.js
index 43f959a7b..2af39a1 100644
--- a/third_party/blink/renderer/devtools/front_end/audits/AuditsReportSelector.js
+++ b/third_party/blink/renderer/devtools/front_end/audits/AuditsReportSelector.js
@@ -6,8 +6,7 @@
   constructor(renderNewAuditView) {
     this._renderNewAuditView = renderNewAuditView;
     this._newAuditItem = createElement('option');
-    this._comboBox = new UI.ToolbarComboBox(this._handleChange.bind(this), 'audits-report');
-    this._comboBox.setTitle(ls`Reports`);
+    this._comboBox = new UI.ToolbarComboBox(this._handleChange.bind(this), ls`Reports`, 'audits-report');
     this._comboBox.setMaxWidth(180);
     this._comboBox.setMinWidth(140);
     this._itemByOptionElement = new Map();
diff --git a/third_party/blink/renderer/devtools/front_end/common/App.js b/third_party/blink/renderer/devtools/front_end/common/App.js
deleted file mode 100644
index f09920f..0000000
--- a/third_party/blink/renderer/devtools/front_end/common/App.js
+++ /dev/null
@@ -1,23 +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.
-
-/**
- * @interface
- */
-export default class App {
-  /**
-   * @param {!Document} document
-   */
-  presentUI(document) {
-  }
-}
-
-/* Legacy exported object */
-self.Common = self.Common || {};
-Common = Common || {};
-
-/**
- * @interface
- */
-Common.App = App;
diff --git a/third_party/blink/renderer/devtools/front_end/common/AppProvider.js b/third_party/blink/renderer/devtools/front_end/common/AppProvider.js
deleted file mode 100644
index 77c20ca..0000000
--- a/third_party/blink/renderer/devtools/front_end/common/AppProvider.js
+++ /dev/null
@@ -1,23 +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.
-
-/**
- * @interface
- */
-export default class AppProvider {
-  /**
-   * @return {!Common.App}
-   */
-  createApp() {
-  }
-}
-
-/* Legacy exported object */
-self.Common = self.Common || {};
-Common = Common || {};
-
-/**
- * @interface
- */
-Common.AppProvider = AppProvider;
diff --git a/third_party/blink/renderer/devtools/front_end/common/CharacterIdMap.js b/third_party/blink/renderer/devtools/front_end/common/CharacterIdMap.js
index 5241062..627df76 100644
--- a/third_party/blink/renderer/devtools/front_end/common/CharacterIdMap.js
+++ b/third_party/blink/renderer/devtools/front_end/common/CharacterIdMap.js
@@ -5,7 +5,7 @@
  * @template T
  * @unrestricted
  */
-export default class CharacterIdMap {
+Common.CharacterIdMap = class {
   constructor() {
     /** @type {!Map<T, string>} */
     this._elementToCharacter = new Map();
@@ -40,13 +40,4 @@
       return null;
     return object;
   }
-}
-
-/* Legacy exported object */
-self.Common = self.Common || {};
-Common = Common || {};
-
-/**
- * @constructor
- */
-Common.CharacterIdMap = CharacterIdMap;
+};
diff --git a/third_party/blink/renderer/devtools/front_end/common/Color.js b/third_party/blink/renderer/devtools/front_end/common/Color.js
index e45868c..1fa43f22 100644
--- a/third_party/blink/renderer/devtools/front_end/common/Color.js
+++ b/third_party/blink/renderer/devtools/front_end/common/Color.js
@@ -30,10 +30,10 @@
 /**
  * @unrestricted
  */
-export default class Color {
+Common.Color = class {
   /**
    * @param {!Array.<number>} rgba
-   * @param {!Format} format
+   * @param {!Common.Color.Format} format
    * @param {string=} originalText
    */
   constructor(rgba, format, originalText) {
@@ -58,7 +58,7 @@
 
   /**
    * @param {string} text
-   * @return {?Color}
+   * @return {?Common.Color}
    */
   static parse(text) {
     // Simple - #hex, nickname
@@ -70,16 +70,16 @@
         let hex = match[1].toLowerCase();
         let format;
         if (hex.length === 3) {
-          format = Format.ShortHEX;
+          format = Common.Color.Format.ShortHEX;
           hex = hex.charAt(0) + hex.charAt(0) + hex.charAt(1) + hex.charAt(1) + hex.charAt(2) + hex.charAt(2);
         } else if (hex.length === 4) {
-          format = Format.ShortHEXA;
+          format = Common.Color.Format.ShortHEXA;
           hex = hex.charAt(0) + hex.charAt(0) + hex.charAt(1) + hex.charAt(1) + hex.charAt(2) + hex.charAt(2) +
               hex.charAt(3) + hex.charAt(3);
         } else if (hex.length === 6) {
-          format = Format.HEX;
+          format = Common.Color.Format.HEX;
         } else {
-          format = Format.HEXA;
+          format = Common.Color.Format.HEXA;
         }
         const r = parseInt(hex.substring(0, 2), 16);
         const g = parseInt(hex.substring(2, 4), 16);
@@ -87,15 +87,15 @@
         let a = 1;
         if (hex.length === 8)
           a = parseInt(hex.substring(6, 8), 16) / 255;
-        return new Color([r / 255, g / 255, b / 255, a], format, text);
+        return new Common.Color([r / 255, g / 255, b / 255, a], format, text);
       }
 
       if (match[2]) {  // nickname
         const nickname = match[2].toLowerCase();
-        if (nickname in Nicknames) {
-          const rgba = Nicknames[nickname];
-          const color = Color.fromRGBA(rgba);
-          color._format = Format.Nickname;
+        if (nickname in Common.Color.Nicknames) {
+          const rgba = Common.Color.Nicknames[nickname];
+          const color = Common.Color.fromRGBA(rgba);
+          color._format = Common.Color.Format.Nickname;
           color._originalText = text;
           return color;
         }
@@ -130,24 +130,24 @@
 
       if (match[1]) {  // rgb/rgba
         const rgba = [
-          Color._parseRgbNumeric(values[0]), Color._parseRgbNumeric(values[1]), Color._parseRgbNumeric(values[2]),
-          hasAlpha ? Color._parseAlphaNumeric(values[3]) : 1
+          Common.Color._parseRgbNumeric(values[0]), Common.Color._parseRgbNumeric(values[1]),
+          Common.Color._parseRgbNumeric(values[2]), hasAlpha ? Common.Color._parseAlphaNumeric(values[3]) : 1
         ];
         if (rgba.indexOf(null) > -1)
           return null;
-        return new Color(rgba, hasAlpha ? Format.RGBA : Format.RGB, text);
+        return new Common.Color(rgba, hasAlpha ? Common.Color.Format.RGBA : Common.Color.Format.RGB, text);
       }
 
       if (match[2]) {  // hsl/hsla
         const hsla = [
-          Color._parseHueNumeric(values[0]), Color._parseSatLightNumeric(values[1]),
-          Color._parseSatLightNumeric(values[2]), hasAlpha ? Color._parseAlphaNumeric(values[3]) : 1
+          Common.Color._parseHueNumeric(values[0]), Common.Color._parseSatLightNumeric(values[1]),
+          Common.Color._parseSatLightNumeric(values[2]), hasAlpha ? Common.Color._parseAlphaNumeric(values[3]) : 1
         ];
         if (hsla.indexOf(null) > -1)
           return null;
         const rgba = [];
-        Color.hsl2rgb(hsla, rgba);
-        return new Color(rgba, hasAlpha ? Format.HSLA : Format.HSL, text);
+        Common.Color.hsl2rgb(hsla, rgba);
+        return new Common.Color(rgba, hasAlpha ? Common.Color.Format.HSLA : Common.Color.Format.HSL, text);
       }
     }
 
@@ -156,20 +156,20 @@
 
   /**
    * @param {!Array.<number>} rgba
-   * @return {!Color}
+   * @return {!Common.Color}
    */
   static fromRGBA(rgba) {
-    return new Color([rgba[0] / 255, rgba[1] / 255, rgba[2] / 255, rgba[3]], Format.RGBA);
+    return new Common.Color([rgba[0] / 255, rgba[1] / 255, rgba[2] / 255, rgba[3]], Common.Color.Format.RGBA);
   }
 
   /**
    * @param {!Array.<number>} hsva
-   * @return {!Color}
+   * @return {!Common.Color}
    */
   static fromHSVA(hsva) {
     const rgba = [];
-    Color.hsva2rgba(hsva, rgba);
-    return new Color(rgba, Format.HSLA);
+    Common.Color.hsva2rgba(hsva, rgba);
+    return new Common.Color(rgba, Common.Color.Format.HSLA);
   }
 
   /**
@@ -194,7 +194,7 @@
    * return {number}
    */
   static _parseRgbNumeric(value) {
-    const parsed = Color._parsePercentOrNumber(value);
+    const parsed = Common.Color._parsePercentOrNumber(value);
     if (parsed === null)
       return null;
 
@@ -238,7 +238,7 @@
    * return {number}
    */
   static _parseAlphaNumeric(value) {
-    return Color._parsePercentOrNumber(value);
+    return Common.Color._parsePercentOrNumber(value);
   }
 
   /**
@@ -313,11 +313,11 @@
    * @param {!Array<number>} out_rgba
    */
   static hsva2rgba(hsva, out_rgba) {
-    Color._hsva2hsla(hsva, Color.hsva2rgba._tmpHSLA);
-    Color.hsl2rgb(Color.hsva2rgba._tmpHSLA, out_rgba);
+    Common.Color._hsva2hsla(hsva, Common.Color.hsva2rgba._tmpHSLA);
+    Common.Color.hsl2rgb(Common.Color.hsva2rgba._tmpHSLA, out_rgba);
 
-    for (let i = 0; i < Color.hsva2rgba._tmpHSLA.length; i++)
-      Color.hsva2rgba._tmpHSLA[i] = 0;
+    for (let i = 0; i < Common.Color.hsva2rgba._tmpHSLA.length; i++)
+      Common.Color.hsva2rgba._tmpHSLA[i] = 0;
   }
 
   /**
@@ -362,14 +362,14 @@
    * @return {number}
    */
   static calculateContrastRatio(fgRGBA, bgRGBA) {
-    Color.blendColors(fgRGBA, bgRGBA, Color.calculateContrastRatio._blendedFg);
+    Common.Color.blendColors(fgRGBA, bgRGBA, Common.Color.calculateContrastRatio._blendedFg);
 
-    const fgLuminance = Color.luminance(Color.calculateContrastRatio._blendedFg);
-    const bgLuminance = Color.luminance(bgRGBA);
+    const fgLuminance = Common.Color.luminance(Common.Color.calculateContrastRatio._blendedFg);
+    const bgLuminance = Common.Color.luminance(bgRGBA);
     const contrastRatio = (Math.max(fgLuminance, bgLuminance) + 0.05) / (Math.min(fgLuminance, bgLuminance) + 0.05);
 
-    for (let i = 0; i < Color.calculateContrastRatio._blendedFg.length; i++)
-      Color.calculateContrastRatio._blendedFg[i] = 0;
+    for (let i = 0; i < Common.Color.calculateContrastRatio._blendedFg.length; i++)
+      Common.Color.calculateContrastRatio._blendedFg[i] = 0;
 
     return contrastRatio;
   }
@@ -401,11 +401,11 @@
   }
 
   /**
-   * @param {!Color} color
-   * @return {!Format}
+   * @param {!Common.Color} color
+   * @return {!Common.Color.Format}
    */
   static detectColorFormat(color) {
-    const cf = Format;
+    const cf = Common.Color.Format;
     let format;
     const formatSetting = Common.moduleSetting('colorFormat').get();
     if (formatSetting === cf.Original)
@@ -423,7 +423,7 @@
   }
 
   /**
-   * @return {!Format}
+   * @return {!Common.Color.Format}
    */
   format() {
     return this._format;
@@ -498,7 +498,7 @@
   }
 
   /**
-   * @return {!Format}
+   * @return {!Common.Color.Format}
    */
   detectHEXFormat() {
     let canBeShort = true;
@@ -511,7 +511,7 @@
     }
 
     const hasAlpha = this.hasAlpha();
-    const cf = Format;
+    const cf = Common.Color.Format;
     if (canBeShort)
       return hasAlpha ? cf.ShortHEXA : cf.ShortHEX;
     return hasAlpha ? cf.HEXA : cf.HEX;
@@ -553,60 +553,60 @@
     }
 
     switch (format) {
-      case Format.Original:
+      case Common.Color.Format.Original:
         return this._originalText;
-      case Format.RGB:
+      case Common.Color.Format.RGB:
         if (this.hasAlpha())
           return null;
         return String.sprintf(
             'rgb(%d, %d, %d)', toRgbValue(this._rgba[0]), toRgbValue(this._rgba[1]), toRgbValue(this._rgba[2]));
-      case Format.RGBA:
+      case Common.Color.Format.RGBA:
         return String.sprintf(
             'rgba(%d, %d, %d, %f)', toRgbValue(this._rgba[0]), toRgbValue(this._rgba[1]), toRgbValue(this._rgba[2]),
             this._rgba[3]);
-      case Format.HSL:
+      case Common.Color.Format.HSL:
         if (this.hasAlpha())
           return null;
         const hsl = this.hsla();
         return String.sprintf(
             'hsl(%d, %d%, %d%)', Math.round(hsl[0] * 360), Math.round(hsl[1] * 100), Math.round(hsl[2] * 100));
-      case Format.HSLA:
+      case Common.Color.Format.HSLA:
         const hsla = this.hsla();
         return String.sprintf(
             'hsla(%d, %d%, %d%, %f)', Math.round(hsla[0] * 360), Math.round(hsla[1] * 100), Math.round(hsla[2] * 100),
             hsla[3]);
-      case Format.HEXA:
+      case Common.Color.Format.HEXA:
         return String
             .sprintf(
                 '#%s%s%s%s', toHexValue(this._rgba[0]), toHexValue(this._rgba[1]), toHexValue(this._rgba[2]),
                 toHexValue(this._rgba[3]))
             .toLowerCase();
-      case Format.HEX:
+      case Common.Color.Format.HEX:
         if (this.hasAlpha())
           return null;
         return String
             .sprintf('#%s%s%s', toHexValue(this._rgba[0]), toHexValue(this._rgba[1]), toHexValue(this._rgba[2]))
             .toLowerCase();
-      case Format.ShortHEXA:
+      case Common.Color.Format.ShortHEXA:
         const hexFormat = this.detectHEXFormat();
-        if (hexFormat !== Format.ShortHEXA && hexFormat !== Format.ShortHEX)
+        if (hexFormat !== Common.Color.Format.ShortHEXA && hexFormat !== Common.Color.Format.ShortHEX)
           return null;
         return String
             .sprintf(
                 '#%s%s%s%s', toShortHexValue(this._rgba[0]), toShortHexValue(this._rgba[1]),
                 toShortHexValue(this._rgba[2]), toShortHexValue(this._rgba[3]))
             .toLowerCase();
-      case Format.ShortHEX:
+      case Common.Color.Format.ShortHEX:
         if (this.hasAlpha())
           return null;
-        if (this.detectHEXFormat() !== Format.ShortHEX)
+        if (this.detectHEXFormat() !== Common.Color.Format.ShortHEX)
           return null;
         return String
             .sprintf(
                 '#%s%s%s', toShortHexValue(this._rgba[0]), toShortHexValue(this._rgba[1]),
                 toShortHexValue(this._rgba[2]))
             .toLowerCase();
-      case Format.Nickname:
+      case Common.Color.Format.Nickname:
         return this.nickname();
     }
 
@@ -635,17 +635,17 @@
    * @return {?string} nickname
    */
   nickname() {
-    if (!Color._rgbaToNickname) {
-      Color._rgbaToNickname = {};
-      for (const nickname in Nicknames) {
-        let rgba = Nicknames[nickname];
+    if (!Common.Color._rgbaToNickname) {
+      Common.Color._rgbaToNickname = {};
+      for (const nickname in Common.Color.Nicknames) {
+        let rgba = Common.Color.Nicknames[nickname];
         if (rgba.length !== 4)
           rgba = rgba.concat(1);
-        Color._rgbaToNickname[rgba] = nickname;
+        Common.Color._rgbaToNickname[rgba] = nickname;
       }
     }
 
-    return Color._rgbaToNickname[this.canonicalRGBA()] || null;
+    return Common.Color._rgbaToNickname[this.canonicalRGBA()] || null;
   }
 
   /**
@@ -660,7 +660,7 @@
   }
 
   /**
-   * @return {!Color}
+   * @return {!Common.Color}
    */
   invert() {
     const rgba = [];
@@ -668,37 +668,37 @@
     rgba[1] = 1 - this._rgba[1];
     rgba[2] = 1 - this._rgba[2];
     rgba[3] = this._rgba[3];
-    return new Color(rgba, Format.RGBA);
+    return new Common.Color(rgba, Common.Color.Format.RGBA);
   }
 
   /**
    * @param {number} alpha
-   * @return {!Color}
+   * @return {!Common.Color}
    */
   setAlpha(alpha) {
     const rgba = this._rgba.slice();
     rgba[3] = alpha;
-    return new Color(rgba, Format.RGBA);
+    return new Common.Color(rgba, Common.Color.Format.RGBA);
   }
 
   /**
-   * @param {!Color} fgColor
-   * @return {!Color}
+   * @param {!Common.Color} fgColor
+   * @return {!Common.Color}
    */
   blendWith(fgColor) {
     const rgba = [];
-    Color.blendColors(fgColor._rgba, this._rgba, rgba);
-    return new Color(rgba, Format.RGBA);
+    Common.Color.blendColors(fgColor._rgba, this._rgba, rgba);
+    return new Common.Color(rgba, Common.Color.Format.RGBA);
   }
-}
+};
 
 /** @type {!RegExp} */
-export const Regex = /((?:rgb|hsl)a?\([^)]+\)|#[0-9a-fA-F]{8}|#[0-9a-fA-F]{6}|#[0-9a-fA-F]{3,4}|\b[a-zA-Z]+\b(?!-))/g;
+Common.Color.Regex = /((?:rgb|hsl)a?\([^)]+\)|#[0-9a-fA-F]{8}|#[0-9a-fA-F]{6}|#[0-9a-fA-F]{3,4}|\b[a-zA-Z]+\b(?!-))/g;
 
 /**
  * @enum {string}
  */
-export const Format = {
+Common.Color.Format = {
   Original: 'original',
   Nickname: 'nickname',
   HEX: 'hex',
@@ -711,7 +711,15 @@
   HSLA: 'hsla'
 };
 
-export const Nicknames = {
+
+/** @type {!Array<number>} */
+Common.Color.hsva2rgba._tmpHSLA = [0, 0, 0, 0];
+
+
+Common.Color.calculateContrastRatio._blendedFg = [0, 0, 0, 0];
+
+
+Common.Color.Nicknames = {
   'aliceblue': [240, 248, 255],
   'antiquewhite': [250, 235, 215],
   'aqua': [0, 255, 255],
@@ -863,23 +871,23 @@
   'transparent': [0, 0, 0, 0],
 };
 
-export const PageHighlight = {
-  Content: Color.fromRGBA([111, 168, 220, .66]),
-  ContentLight: Color.fromRGBA([111, 168, 220, .5]),
-  ContentOutline: Color.fromRGBA([9, 83, 148]),
-  Padding: Color.fromRGBA([147, 196, 125, .55]),
-  PaddingLight: Color.fromRGBA([147, 196, 125, .4]),
-  Border: Color.fromRGBA([255, 229, 153, .66]),
-  BorderLight: Color.fromRGBA([255, 229, 153, .5]),
-  Margin: Color.fromRGBA([246, 178, 107, .66]),
-  MarginLight: Color.fromRGBA([246, 178, 107, .5]),
-  EventTarget: Color.fromRGBA([255, 196, 196, .66]),
-  Shape: Color.fromRGBA([96, 82, 177, 0.8]),
-  ShapeMargin: Color.fromRGBA([96, 82, 127, .6]),
-  CssGrid: Color.fromRGBA([0x4b, 0, 0x82, 1])
+Common.Color.PageHighlight = {
+  Content: Common.Color.fromRGBA([111, 168, 220, .66]),
+  ContentLight: Common.Color.fromRGBA([111, 168, 220, .5]),
+  ContentOutline: Common.Color.fromRGBA([9, 83, 148]),
+  Padding: Common.Color.fromRGBA([147, 196, 125, .55]),
+  PaddingLight: Common.Color.fromRGBA([147, 196, 125, .4]),
+  Border: Common.Color.fromRGBA([255, 229, 153, .66]),
+  BorderLight: Common.Color.fromRGBA([255, 229, 153, .5]),
+  Margin: Common.Color.fromRGBA([246, 178, 107, .66]),
+  MarginLight: Common.Color.fromRGBA([246, 178, 107, .5]),
+  EventTarget: Common.Color.fromRGBA([255, 196, 196, .66]),
+  Shape: Common.Color.fromRGBA([96, 82, 177, 0.8]),
+  ShapeMargin: Common.Color.fromRGBA([96, 82, 127, .6]),
+  CssGrid: Common.Color.fromRGBA([0x4b, 0, 0x82, 1])
 };
 
-export class Generator {
+Common.Color.Generator = class {
   /**
    * @param {!{min: number, max: number}|number=} hueSpace
    * @param {!{min: number, max: number, count: (number|undefined)}|number=} satSpace
@@ -941,32 +949,4 @@
     index %= count;
     return space.min + Math.floor(index / (count - 1) * (space.max - space.min));
   }
-}
-
-/** @type {!Array<number>} */
-Color.hsva2rgba._tmpHSLA = [0, 0, 0, 0];
-
-Color.calculateContrastRatio._blendedFg = [0, 0, 0, 0];
-
-/* Legacy exported object */
-self.Common = self.Common || {};
-Common = Common || {};
-
-/**
- * @constructor
- */
-Common.Color = Color;
-
-Common.Color.Regex = Regex;
-
-/**
- * @enum {string}
- */
-Common.Color.Format = Format;
-Common.Color.Nicknames = Nicknames;
-Common.Color.PageHighlight = PageHighlight;
-
-/**
- * @constructor
- */
-Common.Color.Generator = Generator;
+};
diff --git a/third_party/blink/renderer/devtools/front_end/common/Console.js b/third_party/blink/renderer/devtools/front_end/common/Console.js
index 9695527..71350cb1 100644
--- a/third_party/blink/renderer/devtools/front_end/common/Console.js
+++ b/third_party/blink/renderer/devtools/front_end/common/Console.js
@@ -4,7 +4,7 @@
 /**
  * @unrestricted
  */
-export default class Console extends Common.Object {
+Common.Console = class extends Common.Object {
   constructor() {
     super();
     /** @type {!Array.<!Common.Console.Message>} */
@@ -61,17 +61,17 @@
   showPromise() {
     return Common.Revealer.reveal(this);
   }
-}
+};
 
 /** @enum {symbol} */
-export const Events = {
+Common.Console.Events = {
   MessageAdded: Symbol('messageAdded')
 };
 
 /**
  * @enum {string}
  */
-export const MessageLevel = {
+Common.Console.MessageLevel = {
   Info: 'info',
   Warning: 'warning',
   Error: 'error'
@@ -80,7 +80,7 @@
 /**
  * @unrestricted
  */
-export class Message {
+Common.Console.Message = class {
   /**
    * @param {string} text
    * @param {!Common.Console.MessageLevel} level
@@ -93,28 +93,6 @@
     this.timestamp = (typeof timestamp === 'number') ? timestamp : Date.now();
     this.show = show;
   }
-}
+};
 
-/* Legacy exported object */
-self.Common = self.Common || {};
-Common = Common || {};
-
-Common.console = new Console();
-
-/**
- * @constructor
- */
-Common.Console = Console;
-
-/** @enum {symbol} */
-Common.Console.Events = Events;
-
-/**
- * @enum {string}
- */
-Common.Console.MessageLevel = MessageLevel;
-
-/**
- * @constructor
- */
-Common.Console.Message = Message;
+Common.console = new Common.Console();
diff --git a/third_party/blink/renderer/devtools/front_end/common/ContentProvider.js b/third_party/blink/renderer/devtools/front_end/common/ContentProvider.js
index adb72086..349adfe 100644
--- a/third_party/blink/renderer/devtools/front_end/common/ContentProvider.js
+++ b/third_party/blink/renderer/devtools/front_end/common/ContentProvider.js
@@ -30,30 +30,28 @@
 /**
  * @interface
  */
-export default class ContentProvider {
+Common.ContentProvider = function() {};
+
+Common.ContentProvider.prototype = {
   /**
    * @return {string}
    */
-  contentURL() {
-  }
+  contentURL() {},
 
   /**
    * @return {!Common.ResourceType}
    */
-  contentType() {
-  }
+  contentType() {},
 
   /**
    * @return {!Promise<boolean>}
    */
-  contentEncoded() {
-  }
+  contentEncoded() {},
 
   /**
    * @return {!Promise<string>}
    */
-  requestContent() {
-  }
+  requestContent() {},
 
   /**
    * @param {string} query
@@ -62,12 +60,12 @@
    * @return {!Promise<!Array<!Common.ContentProvider.SearchMatch>>}
    */
   searchInContent(query, caseSensitive, isRegex) {}
-}
+};
 
 /**
  * @unrestricted
  */
-export class SearchMatch {
+Common.ContentProvider.SearchMatch = class {
   /**
    * @param {number} lineNumber
    * @param {string} lineContent
@@ -76,7 +74,7 @@
     this.lineNumber = lineNumber;
     this.lineContent = lineContent;
   }
-}
+};
 
 /**
  * @param {string} content
@@ -85,7 +83,7 @@
  * @param {boolean} isRegex
  * @return {!Array.<!Common.ContentProvider.SearchMatch>}
  */
-export const performSearchInContent = function(content, query, caseSensitive, isRegex) {
+Common.ContentProvider.performSearchInContent = function(content, query, caseSensitive, isRegex) {
   const regex = createSearchRegex(query, caseSensitive, isRegex);
 
   const text = new TextUtils.Text(content);
@@ -106,7 +104,7 @@
  * @param {?string=} charset
  * @return {?string}
  */
-export const contentAsDataURL = function(content, mimeType, contentEncoded, charset) {
+Common.ContentProvider.contentAsDataURL = function(content, mimeType, contentEncoded, charset) {
   const maxDataUrlSize = 1024 * 1024;
   if (content === null || content.length > maxDataUrlSize)
     return null;
@@ -114,19 +112,3 @@
   return 'data:' + mimeType + (charset ? ';charset=' + charset : '') + (contentEncoded ? ';base64' : '') + ',' +
       content;
 };
-
-/* Legacy exported object */
-self.Common = self.Common || {};
-Common = Common || {};
-
-/**
- * @interface
- */
-Common.ContentProvider = ContentProvider;
-
-/**
- * @constructor
- */
-Common.ContentProvider.SearchMatch = SearchMatch;
-Common.ContentProvider.performSearchInContent = performSearchInContent;
-Common.ContentProvider.contentAsDataURL = contentAsDataURL;
diff --git a/third_party/blink/renderer/devtools/front_end/common/EventTarget.js b/third_party/blink/renderer/devtools/front_end/common/EventTarget.js
deleted file mode 100644
index 61f4719..0000000
--- a/third_party/blink/renderer/devtools/front_end/common/EventTarget.js
+++ /dev/null
@@ -1,77 +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.
-
-/**
- * @param {!Array<!Common.EventTarget.EventDescriptor>} eventList
- */
-export function removeEventListeners(eventList) {
-  for (const eventInfo of eventList)
-    eventInfo.eventTarget.removeEventListener(eventInfo.eventType, eventInfo.listener, eventInfo.thisObject);
-  // Do not hold references on unused event descriptors.
-  eventList.splice(0);
-}
-
-/**
- * @interface
- */
-export default class EventTarget {
-  /**
-   * @param {symbol} eventType
-   * @param {function(!Common.Event)} listener
-   * @param {!Object=} thisObject
-   * @return {!Common.EventTarget.EventDescriptor}
-   */
-  addEventListener(eventType, listener, thisObject) {
-  }
-
-  /**
-   * @param {symbol} eventType
-   * @return {!Promise<*>}
-   */
-  once(eventType) {
-  }
-
-  /**
-   * @param {string|symbol} eventType
-   * @param {function(!Common.Event)} listener
-   * @param {!Object=} thisObject
-   */
-  removeEventListener(eventType, listener, thisObject) {
-  }
-
-  /**
-   * @param {symbol} eventType
-   * @return {boolean}
-   */
-  hasEventListeners(eventType) {
-  }
-
-  /**
-   * @param {symbol} eventType
-   * @param {*=} eventData
-   */
-  dispatchEventToListeners(eventType, eventData) {
-  }
-}
-
-/* Legacy exported object */
-self.Common = self.Common || {};
-Common = Common || {};
-
-/**
- * @typedef {!{data: *}}
- */
-Common.Event;
-
-/**
- * @interface
- */
-Common.EventTarget = EventTarget;
-
-EventTarget.removeEventListeners = removeEventListeners;
-
-/**
- * @typedef {!{eventTarget: !Common.EventTarget, eventType: (string|symbol), thisObject: (!Object|undefined), listener: function(!Common.Event)}}
- */
-Common.EventTarget.EventDescriptor;
diff --git a/third_party/blink/renderer/devtools/front_end/common/JavaScriptMetaData.js b/third_party/blink/renderer/devtools/front_end/common/JavaScriptMetaData.js
deleted file mode 100644
index 9e3eda83..0000000
--- a/third_party/blink/renderer/devtools/front_end/common/JavaScriptMetaData.js
+++ /dev/null
@@ -1,40 +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.
-
-/**
- * @interface
- */
-export default class JavaScriptMetadata {
-  /**
-   * @param {string} name
-   * @return {?Array<!Array<string>>}
-   */
-  signaturesForNativeFunction(name) {
-  }
-
-  /**
-   * @param {string} name
-   * @param {string} receiverClassName
-   * @return {?Array<!Array<string>>}
-   */
-  signaturesForInstanceMethod(name, receiverClassName) {
-  }
-
-  /**
-   * @param {string} name
-   * @param {string} receiverConstructorName
-   * @return {?Array<!Array<string>>}
-   */
-  signaturesForStaticMethod(name, receiverConstructorName) {
-  }
-}
-
-/* Legacy exported object */
-self.Common = self.Common || {};
-Common = Common || {};
-
-/**
- * @interface
- */
-Common.JavaScriptMetadata = JavaScriptMetadata;
diff --git a/third_party/blink/renderer/devtools/front_end/common/Linkifier.js b/third_party/blink/renderer/devtools/front_end/common/Linkifier.js
deleted file mode 100644
index 14c161b..0000000
--- a/third_party/blink/renderer/devtools/front_end/common/Linkifier.js
+++ /dev/null
@@ -1,42 +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.
-
-/**
- * @interface
- */
-export default class Linkifier {
-  /**
-   * @param {!Object} object
-   * @param {!Common.Linkifier.Options=} options
-   * @return {!Node}
-   */
-  linkify(object, options) {
-  }
-}
-
-/**
- * @param {?Object} object
- * @param {!Common.Linkifier.Options=} options
- * @return {!Promise<!Node>}
- */
-export function linkify(object, options) {
-  if (!object)
-    return Promise.reject(new Error('Can\'t linkify ' + object));
-  return self.runtime.extension(Common.Linkifier, object)
-      .instance()
-      .then(linkifier => linkifier.linkify(object, options));
-}
-
-/* Legacy exported object */
-self.Common = self.Common || {};
-Common = Common || {};
-
-/**
- * @interface
- */
-Common.Linkifier = Linkifier;
-Common.Linkifier.linkify = linkify;
-
-/** @typedef {{tooltip: (string|undefined), preventKeyboardFocus: (boolean|undefined)}} */
-Common.Linkifier.Options;
diff --git a/third_party/blink/renderer/devtools/front_end/common/ModuleExtensionInterfaces.js b/third_party/blink/renderer/devtools/front_end/common/ModuleExtensionInterfaces.js
new file mode 100644
index 0000000..5120202
--- /dev/null
+++ b/third_party/blink/renderer/devtools/front_end/common/ModuleExtensionInterfaces.js
@@ -0,0 +1,155 @@
+// 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.
+
+/**
+ * @interface
+ */
+Common.Revealer = function() {};
+
+/**
+ * @param {?Object} revealable
+ * @param {boolean=} omitFocus
+ * @return {!Promise.<undefined>}
+ */
+Common.Revealer.reveal = function(revealable, omitFocus) {
+  if (!revealable)
+    return Promise.reject(new Error('Can\'t reveal ' + revealable));
+  return self.runtime.allInstances(Common.Revealer, revealable).then(reveal);
+
+  /**
+   * @param {!Array.<!Common.Revealer>} revealers
+   * @return {!Promise.<undefined>}
+   */
+  function reveal(revealers) {
+    const promises = [];
+    for (let i = 0; i < revealers.length; ++i)
+      promises.push(revealers[i].reveal(/** @type {!Object} */ (revealable), omitFocus));
+    return Promise.race(promises);
+  }
+};
+
+/**
+ * @param {?Object} revealable
+ * @return {?string}
+ */
+Common.Revealer.revealDestination = function(revealable) {
+  const extension = self.runtime.extension(Common.Revealer, revealable);
+  if (!extension)
+    return null;
+  return extension.descriptor()['destination'];
+};
+
+Common.Revealer.prototype = {
+  /**
+   * @param {!Object} object
+   * @param {boolean=} omitFocus
+   * @return {!Promise}
+   */
+  reveal(object, omitFocus) {}
+};
+
+/**
+ * @interface
+ */
+Common.App = function() {};
+
+Common.App.prototype = {
+  /**
+   * @param {!Document} document
+   */
+  presentUI(document) {}
+};
+
+/**
+ * @interface
+ */
+Common.AppProvider = function() {};
+
+Common.AppProvider.prototype = {
+  /**
+   * @return {!Common.App}
+   */
+  createApp() {}
+};
+
+/**
+ * @interface
+ */
+Common.QueryParamHandler = function() {};
+
+Common.QueryParamHandler.prototype = {
+  /**
+   * @param {string} value
+   */
+  handleQueryParam(value) {}
+};
+
+/**
+ * @interface
+ */
+Common.Runnable = function() {};
+
+Common.Runnable.prototype = {
+  /**
+   * @return {!Promise}
+   */
+  run() {}
+};
+
+/**
+ * @interface
+ */
+Common.Linkifier = function() {};
+
+Common.Linkifier.prototype = {
+  /**
+   * @param {!Object} object
+   * @param {!Common.Linkifier.Options=} options
+   * @return {!Node}
+   */
+  linkify(object, options) {}
+};
+
+/**
+ * @param {?Object} object
+ * @param {!Common.Linkifier.Options=} options
+ * @return {!Promise<!Node>}
+ */
+Common.Linkifier.linkify = function(object, options) {
+  if (!object)
+    return Promise.reject(new Error('Can\'t linkify ' + object));
+  return self.runtime.extension(Common.Linkifier, object)
+      .instance()
+      .then(linkifier => linkifier.linkify(object, options));
+};
+
+/** @typedef {{tooltip: (string|undefined), preventKeyboardFocus: (boolean|undefined)}} */
+Common.Linkifier.Options;
+
+/**
+ * @interface
+ */
+Common.JavaScriptMetadata = function() {};
+Common.JavaScriptMetadata.prototype = {
+
+  /**
+   * @param {string} name
+   * @return {?Array<!Array<string>>}
+   */
+  signaturesForNativeFunction(name) {},
+
+  /**
+   * @param {string} name
+   * @param {string} receiverClassName
+   * @return {?Array<!Array<string>>}
+   */
+  signaturesForInstanceMethod(name, receiverClassName) {},
+
+  /**
+   * @param {string} name
+   * @param {string} receiverConstructorName
+   * @return {?Array<!Array<string>>}
+   */
+  signaturesForStaticMethod(name, receiverConstructorName) {}
+};
diff --git a/third_party/blink/renderer/devtools/front_end/common/Object.js b/third_party/blink/renderer/devtools/front_end/common/Object.js
index fa618cbc..9f5e522 100644
--- a/third_party/blink/renderer/devtools/front_end/common/Object.js
+++ b/third_party/blink/renderer/devtools/front_end/common/Object.js
@@ -27,7 +27,7 @@
  * @implements {Common.EventTarget}
  * @unrestricted
  */
-export default class ObjectWrapper {
+Common.Object = class {
   constructor() {
     /** @type {(!Map<string|symbol, !Array<!Common.Object._listenerCallbackTuple>>|undefined)} */
     this._listeners;
@@ -115,18 +115,69 @@
         listeners[i].listener.call(listeners[i].thisObject, event);
     }
   }
-}
-
-/* Legacy exported object */
-self.Common = self.Common || {};
-Common = Common || {};
+};
 
 /**
- * @constructor
+ * @typedef {!{data: *}}
  */
-Common.Object = ObjectWrapper;
+Common.Event;
 
 /**
  * @typedef {!{thisObject: (!Object|undefined), listener: function(!Common.Event), disposed: (boolean|undefined)}}
  */
 Common.Object._listenerCallbackTuple;
+
+/**
+ * @interface
+ */
+Common.EventTarget = function() {};
+
+/**
+ * @typedef {!{eventTarget: !Common.EventTarget, eventType: (string|symbol), thisObject: (!Object|undefined), listener: function(!Common.Event)}}
+ */
+Common.EventTarget.EventDescriptor;
+
+/**
+ * @param {!Array<!Common.EventTarget.EventDescriptor>} eventList
+ */
+Common.EventTarget.removeEventListeners = function(eventList) {
+  for (const eventInfo of eventList)
+    eventInfo.eventTarget.removeEventListener(eventInfo.eventType, eventInfo.listener, eventInfo.thisObject);
+  // Do not hold references on unused event descriptors.
+  eventList.splice(0);
+};
+
+Common.EventTarget.prototype = {
+  /**
+   * @param {symbol} eventType
+   * @param {function(!Common.Event)} listener
+   * @param {!Object=} thisObject
+   * @return {!Common.EventTarget.EventDescriptor}
+   */
+  addEventListener(eventType, listener, thisObject) {},
+
+  /**
+   * @param {symbol} eventType
+   * @return {!Promise<*>}
+   */
+  once(eventType) {},
+
+  /**
+   * @param {string|symbol} eventType
+   * @param {function(!Common.Event)} listener
+   * @param {!Object=} thisObject
+   */
+  removeEventListener(eventType, listener, thisObject) {},
+
+  /**
+   * @param {symbol} eventType
+   * @return {boolean}
+   */
+  hasEventListeners(eventType) {},
+
+  /**
+   * @param {symbol} eventType
+   * @param {*=} eventData
+   */
+  dispatchEventToListeners(eventType, eventData) {},
+};
diff --git a/third_party/blink/renderer/devtools/front_end/common/StringOutputStream.js b/third_party/blink/renderer/devtools/front_end/common/OutputStream.js
similarity index 65%
rename from third_party/blink/renderer/devtools/front_end/common/StringOutputStream.js
rename to third_party/blink/renderer/devtools/front_end/common/OutputStream.js
index abd6b49..1e72025 100644
--- a/third_party/blink/renderer/devtools/front_end/common/StringOutputStream.js
+++ b/third_party/blink/renderer/devtools/front_end/common/OutputStream.js
@@ -5,25 +5,25 @@
 /**
  * @interface
  */
-export class OutputStream {
+Common.OutputStream = function() {};
+
+Common.OutputStream.prototype = {
   /**
    * @param {string} data
    * @return {!Promise}
    */
-  async write(data) {
-  }
+  write(data) {},
 
   /**
    * @return {!Promise}
    */
-  async close() {
-  }
-}
+  close() {}
+};
 
 /**
  * @implements {Common.OutputStream}
  */
-export default class StringOutputStream {
+Common.StringOutputStream = class {
   constructor() {
     this._data = '';
   }
@@ -40,7 +40,7 @@
   /**
    * @override
    */
-  async close() {
+  close() {
   }
 
   /**
@@ -49,14 +49,4 @@
   data() {
     return this._data;
   }
-}
-
-/* Legacy exported object */
-self.Common = self.Common || {};
-Common = Common || {};
-
-/**
- * @interface
- */
-Common.OutputStream = OutputStream;
-Common.StringOutputStream = StringOutputStream;
+};
diff --git a/third_party/blink/renderer/devtools/front_end/common/ParsedURL.js b/third_party/blink/renderer/devtools/front_end/common/ParsedURL.js
index 26dedde..9bdc4692 100644
--- a/third_party/blink/renderer/devtools/front_end/common/ParsedURL.js
+++ b/third_party/blink/renderer/devtools/front_end/common/ParsedURL.js
@@ -29,7 +29,7 @@
 /**
  * @unrestricted
  */
-export default class ParsedURL {
+Common.ParsedURL = class {
   /**
    * @param {string} url
    */
@@ -388,7 +388,8 @@
       return this.url.substring(this.scheme.length + 3);
     return this.url;
   }
-}
+};
+
 
 /**
  * @return {?Common.ParsedURL}
@@ -399,12 +400,3 @@
     return parsedURL;
   return null;
 };
-
-/* Legacy exported object */
-self.Common = self.Common || {};
-Common = Common || {};
-
-/**
- * @constructor
- */
-Common.ParsedURL = ParsedURL;
diff --git a/third_party/blink/renderer/devtools/front_end/common/Progress.js b/third_party/blink/renderer/devtools/front_end/common/Progress.js
index 2f24102..669ecf0 100644
--- a/third_party/blink/renderer/devtools/front_end/common/Progress.js
+++ b/third_party/blink/renderer/devtools/front_end/common/Progress.js
@@ -27,51 +27,47 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-
 /**
  * @interface
  */
-export default class Progress {
+Common.Progress = function() {};
+
+Common.Progress.prototype = {
   /**
    * @param {number} totalWork
    */
-  setTotalWork(totalWork) {
-  }
+  setTotalWork(totalWork) {},
 
   /**
    * @param {string} title
    */
-  setTitle(title) {
-  }
+  setTitle(title) {},
 
   /**
    * @param {number} worked
    * @param {string=} title
    */
-  setWorked(worked, title) {
-  }
+  setWorked(worked, title) {},
 
   /**
    * @param {number=} worked
    */
-  worked(worked) {
-  }
+  worked(worked) {},
 
-  done() {
-  }
+  done() {},
 
   /**
    * @return {boolean}
    */
   isCanceled() {
     return false;
-  }
-}
+  },
+};
 
 /**
  * @unrestricted
  */
-export class CompositeProgress {
+Common.CompositeProgress = class {
   /**
    * @param {!Common.Progress} parent
    */
@@ -111,13 +107,13 @@
     }
     this._parent.setWorked(done / totalWeights);
   }
-}
+};
 
 /**
  * @implements {Common.Progress}
  * @unrestricted
  */
-export class SubProgress {
+Common.SubProgress = class {
   /**
    * @param {!Common.CompositeProgress} composite
    * @param {number=} weight
@@ -180,13 +176,13 @@
   worked(worked) {
     this.setWorked(this._worked + (worked || 1));
   }
-}
+};
 
 /**
  * @implements {Common.Progress}
  * @unrestricted
  */
-export class ProgressProxy {
+Common.ProgressProxy = class {
   /**
    * @param {?Common.Progress} delegate
    * @param {function()=} doneCallback
@@ -250,28 +246,4 @@
     if (this._delegate)
       this._delegate.worked(worked);
   }
-}
-
-/* Legacy exported object */
-self.Common = self.Common || {};
-Common = Common || {};
-
-/**
- * @interface
- */
-Common.Progress = Progress;
-
-/**
- * @constructor
- */
-Common.CompositeProgress = CompositeProgress;
-
-/**
- * @constructor
- */
-Common.SubProgress = SubProgress;
-
-/**
- * @constructor
- */
-Common.ProgressProxy = ProgressProxy;
+};
diff --git a/third_party/blink/renderer/devtools/front_end/common/QueryParamHandler.js b/third_party/blink/renderer/devtools/front_end/common/QueryParamHandler.js
deleted file mode 100644
index 60a1036..0000000
--- a/third_party/blink/renderer/devtools/front_end/common/QueryParamHandler.js
+++ /dev/null
@@ -1,23 +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.
-
-/**
- * @interface
- */
-export default class QueryParamHandler {
-  /**
-   * @param {string} value
-   */
-  handleQueryParam(value) {
-  }
-}
-
-/* Legacy exported object */
-self.Common = self.Common || {};
-Common = Common || {};
-
-/**
- * @interface
- */
-Common.QueryParamHandler = QueryParamHandler;
diff --git a/third_party/blink/renderer/devtools/front_end/common/ResourceType.js b/third_party/blink/renderer/devtools/front_end/common/ResourceType.js
index 068df21f..5a69005e 100644
--- a/third_party/blink/renderer/devtools/front_end/common/ResourceType.js
+++ b/third_party/blink/renderer/devtools/front_end/common/ResourceType.js
@@ -30,11 +30,11 @@
 /**
  * @unrestricted
  */
-export default class ResourceType {
+Common.ResourceType = class {
   /**
    * @param {string} name
    * @param {string} title
-   * @param {!ResourceCategory} category
+   * @param {!Common.ResourceCategory} category
    * @param {boolean} isTextType
    */
   constructor(name, title, category, isTextType) {
@@ -46,45 +46,45 @@
 
   /**
    * @param {string} mimeType
-   * @return {!ResourceType}
+   * @return {!Common.ResourceType}
    */
   static fromMimeType(mimeType) {
     if (mimeType.startsWith('text/html'))
-      return resourceTypes.Document;
+      return Common.resourceTypes.Document;
     if (mimeType.startsWith('text/css'))
-      return resourceTypes.Stylesheet;
+      return Common.resourceTypes.Stylesheet;
     if (mimeType.startsWith('image/'))
-      return resourceTypes.Image;
+      return Common.resourceTypes.Image;
     if (mimeType.startsWith('text/'))
-      return resourceTypes.Script;
+      return Common.resourceTypes.Script;
 
     if (mimeType.includes('font'))
-      return resourceTypes.Font;
+      return Common.resourceTypes.Font;
     if (mimeType.includes('script'))
-      return resourceTypes.Script;
+      return Common.resourceTypes.Script;
     if (mimeType.includes('octet'))
-      return resourceTypes.Other;
+      return Common.resourceTypes.Other;
     if (mimeType.includes('application'))
-      return resourceTypes.Script;
+      return Common.resourceTypes.Script;
 
-    return resourceTypes.Other;
+    return Common.resourceTypes.Other;
   }
 
   /**
    * @param {string} url
-   * @return {?ResourceType}
+   * @return {?Common.ResourceType}
    */
   static fromURL(url) {
-    return ResourceType._resourceTypeByExtension.get(Common.ParsedURL.extractExtension(url)) || null;
+    return Common.ResourceType._resourceTypeByExtension.get(Common.ParsedURL.extractExtension(url)) || null;
   }
 
   /**
    * @param {string} name
-   * @return {?ResourceType}
+   * @return {?Common.ResourceType}
    */
   static fromName(name) {
-    for (const resourceTypeId in resourceTypes) {
-      const resourceType = resourceTypes[resourceTypeId];
+    for (const resourceTypeId in Common.resourceTypes) {
+      const resourceType = Common.resourceTypes[resourceTypeId];
       if (resourceType.name() === name)
         return resourceType;
     }
@@ -97,11 +97,11 @@
    */
   static mimeFromURL(url) {
     const name = Common.ParsedURL.extractName(url);
-    if (ResourceType._mimeTypeByName.has(name))
-      return ResourceType._mimeTypeByName.get(name);
+    if (Common.ResourceType._mimeTypeByName.has(name))
+      return Common.ResourceType._mimeTypeByName.get(name);
 
     const ext = Common.ParsedURL.extractExtension(url).toLowerCase();
-    return ResourceType._mimeTypeByExtension.get(ext);
+    return Common.ResourceType._mimeTypeByExtension.get(ext);
   }
 
   /**
@@ -109,7 +109,7 @@
    * @return {string|undefined}
    */
   static mimeFromExtension(ext) {
-    return ResourceType._mimeTypeByExtension.get(ext);
+    return Common.ResourceType._mimeTypeByExtension.get(ext);
   }
 
   /**
@@ -127,7 +127,7 @@
   }
 
   /**
-   * @return {!ResourceCategory}
+   * @return {!Common.ResourceCategory}
    */
   category() {
     return this._category;
@@ -202,12 +202,12 @@
       return 'text/css';
     return '';
   }
-}
+};
 
 /**
  * @unrestricted
  */
-export class ResourceCategory {
+Common.ResourceCategory = class {
   /**
    * @param {string} title
    * @param {string} shortTitle
@@ -216,68 +216,67 @@
     this.title = title;
     this.shortTitle = shortTitle;
   }
-}
+};
 
-/**
- * @enum {!ResourceCategory}
- */
-export const resourceCategories = {
-  XHR: new ResourceCategory('XHR and Fetch', 'XHR'),
-  Script: new ResourceCategory('Scripts', 'JS'),
-  Stylesheet: new ResourceCategory('Stylesheets', 'CSS'),
-  Image: new ResourceCategory('Images', 'Img'),
-  Media: new ResourceCategory('Media', 'Media'),
-  Font: new ResourceCategory('Fonts', 'Font'),
-  Document: new ResourceCategory('Documents', 'Doc'),
-  WebSocket: new ResourceCategory('WebSockets', 'WS'),
-  Manifest: new ResourceCategory('Manifest', 'Manifest'),
-  Other: new ResourceCategory('Other', 'Other')
+Common.resourceCategories = {
+  XHR: new Common.ResourceCategory('XHR and Fetch', 'XHR'),
+  Script: new Common.ResourceCategory('Scripts', 'JS'),
+  Stylesheet: new Common.ResourceCategory('Stylesheets', 'CSS'),
+  Image: new Common.ResourceCategory('Images', 'Img'),
+  Media: new Common.ResourceCategory('Media', 'Media'),
+  Font: new Common.ResourceCategory('Fonts', 'Font'),
+  Document: new Common.ResourceCategory('Documents', 'Doc'),
+  WebSocket: new Common.ResourceCategory('WebSockets', 'WS'),
+  Manifest: new Common.ResourceCategory('Manifest', 'Manifest'),
+  Other: new Common.ResourceCategory('Other', 'Other')
 };
 
 /**
  * Keep these in sync with WebCore::InspectorPageAgent::resourceTypeJson
- * @enum {!ResourceType}
+ * @enum {!Common.ResourceType}
  */
-export const resourceTypes = {
-  XHR: new ResourceType('xhr', 'XHR', resourceCategories.XHR, true),
-  Fetch: new ResourceType('fetch', 'Fetch', resourceCategories.XHR, true),
-  EventSource: new ResourceType('eventsource', 'EventSource', resourceCategories.XHR, true),
-  Script: new ResourceType('script', 'Script', resourceCategories.Script, true),
-  Stylesheet: new ResourceType('stylesheet', 'Stylesheet', resourceCategories.Stylesheet, true),
-  Image: new ResourceType('image', 'Image', resourceCategories.Image, false),
-  Media: new ResourceType('media', 'Media', resourceCategories.Media, false),
-  Font: new ResourceType('font', 'Font', resourceCategories.Font, false),
-  Document: new ResourceType('document', 'Document', resourceCategories.Document, true),
-  TextTrack: new ResourceType('texttrack', 'TextTrack', resourceCategories.Other, true),
-  WebSocket: new ResourceType('websocket', 'WebSocket', resourceCategories.WebSocket, false),
-  Other: new ResourceType('other', 'Other', resourceCategories.Other, false),
-  SourceMapScript: new ResourceType('sm-script', 'Script', resourceCategories.Script, true),
-  SourceMapStyleSheet: new ResourceType('sm-stylesheet', 'Stylesheet', resourceCategories.Stylesheet, true),
-  Manifest: new ResourceType('manifest', 'Manifest', resourceCategories.Manifest, true),
-  SignedExchange: new ResourceType('signed-exchange', 'SignedExchange', resourceCategories.Other, false),
+Common.resourceTypes = {
+  XHR: new Common.ResourceType('xhr', 'XHR', Common.resourceCategories.XHR, true),
+  Fetch: new Common.ResourceType('fetch', 'Fetch', Common.resourceCategories.XHR, true),
+  EventSource: new Common.ResourceType('eventsource', 'EventSource', Common.resourceCategories.XHR, true),
+  Script: new Common.ResourceType('script', 'Script', Common.resourceCategories.Script, true),
+  Stylesheet: new Common.ResourceType('stylesheet', 'Stylesheet', Common.resourceCategories.Stylesheet, true),
+  Image: new Common.ResourceType('image', 'Image', Common.resourceCategories.Image, false),
+  Media: new Common.ResourceType('media', 'Media', Common.resourceCategories.Media, false),
+  Font: new Common.ResourceType('font', 'Font', Common.resourceCategories.Font, false),
+  Document: new Common.ResourceType('document', 'Document', Common.resourceCategories.Document, true),
+  TextTrack: new Common.ResourceType('texttrack', 'TextTrack', Common.resourceCategories.Other, true),
+  WebSocket: new Common.ResourceType('websocket', 'WebSocket', Common.resourceCategories.WebSocket, false),
+  Other: new Common.ResourceType('other', 'Other', Common.resourceCategories.Other, false),
+  SourceMapScript: new Common.ResourceType('sm-script', 'Script', Common.resourceCategories.Script, true),
+  SourceMapStyleSheet:
+      new Common.ResourceType('sm-stylesheet', 'Stylesheet', Common.resourceCategories.Stylesheet, true),
+  Manifest: new Common.ResourceType('manifest', 'Manifest', Common.resourceCategories.Manifest, true),
+  SignedExchange: new Common.ResourceType('signed-exchange', 'SignedExchange', Common.resourceCategories.Other, false),
 };
 
 
-export const _mimeTypeByName = new Map([
+Common.ResourceType._mimeTypeByName = new Map([
   // CoffeeScript
   ['Cakefile', 'text/x-coffeescript']
 ]);
 
-export const _resourceTypeByExtension = new Map([
-  ['js', resourceTypes.Script], ['mjs', resourceTypes.Script],
+Common.ResourceType._resourceTypeByExtension = new Map([
+  ['js', Common.resourceTypes.Script], ['mjs', Common.resourceTypes.Script],
 
-  ['css', resourceTypes.Stylesheet], ['xsl', resourceTypes.Stylesheet],
+  ['css', Common.resourceTypes.Stylesheet], ['xsl', Common.resourceTypes.Stylesheet],
 
-  ['jpeg', resourceTypes.Image], ['jpg', resourceTypes.Image], ['svg', resourceTypes.Image],
-  ['gif', resourceTypes.Image], ['png', resourceTypes.Image], ['ico', resourceTypes.Image],
-  ['tiff', resourceTypes.Image], ['tif', resourceTypes.Image], ['bmp', resourceTypes.Image],
+  ['jpeg', Common.resourceTypes.Image], ['jpg', Common.resourceTypes.Image], ['svg', Common.resourceTypes.Image],
+  ['gif', Common.resourceTypes.Image], ['png', Common.resourceTypes.Image], ['ico', Common.resourceTypes.Image],
+  ['tiff', Common.resourceTypes.Image], ['tif', Common.resourceTypes.Image], ['bmp', Common.resourceTypes.Image],
 
-  ['webp', resourceTypes.Media],
+  ['webp', Common.resourceTypes.Media],
 
-  ['ttf', resourceTypes.Font], ['otf', resourceTypes.Font], ['ttc', resourceTypes.Font], ['woff', resourceTypes.Font]
+  ['ttf', Common.resourceTypes.Font], ['otf', Common.resourceTypes.Font], ['ttc', Common.resourceTypes.Font],
+  ['woff', Common.resourceTypes.Font]
 ]);
 
-export const _mimeTypeByExtension = new Map([
+Common.ResourceType._mimeTypeByExtension = new Map([
   // Web extensions
   ['js', 'text/javascript'], ['mjs', 'text/javascript'], ['css', 'text/css'], ['html', 'text/html'],
   ['htm', 'text/html'], ['xml', 'application/xml'], ['xsl', 'application/xml'],
@@ -347,31 +346,3 @@
   // Font
   ['ttf', 'font/opentype'], ['otf', 'font/opentype'], ['ttc', 'font/opentype'], ['woff', 'application/font-woff']
 ]);
-
-/* Legacy exported object */
-self.Common = self.Common || {};
-Common = Common || {};
-
-/**
- * @enum {!ResourceType}
- */
-Common.resourceTypes = resourceTypes;
-
-/**
- * @enum {!ResourceCategory}
- */
-Common.resourceCategories = resourceCategories;
-
-/**
- * @constructor
- */
-Common.ResourceCategory = ResourceCategory;
-
-/**
- * @constructor
- */
-Common.ResourceType = ResourceType;
-
-Common.ResourceType._mimeTypeByName = _mimeTypeByName;
-Common.ResourceType._resourceTypeByExtension = _resourceTypeByExtension;
-Common.ResourceType._mimeTypeByExtension = _mimeTypeByExtension;
diff --git a/third_party/blink/renderer/devtools/front_end/common/Revealer.js b/third_party/blink/renderer/devtools/front_end/common/Revealer.js
deleted file mode 100644
index 467c6e5..0000000
--- a/third_party/blink/renderer/devtools/front_end/common/Revealer.js
+++ /dev/null
@@ -1,60 +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.
-
-/**
- * @interface
- */
-export default class Revealer {
-  /**
-   * @param {!Object} object
-   * @param {boolean=} omitFocus
-   * @return {!Promise}
-   */
-  reveal(object, omitFocus) {
-  }
-}
-
-/**
- * @param {?Object} revealable
- * @param {boolean=} omitFocus
- * @return {!Promise.<undefined>}
- */
-export const reveal = function(revealable, omitFocus) {
-  if (!revealable)
-    return Promise.reject(new Error('Can\'t reveal ' + revealable));
-  return self.runtime.allInstances(Common.Revealer, revealable).then(reveal);
-
-  /**
-   * @param {!Array.<!Common.Revealer>} revealers
-   * @return {!Promise.<undefined>}
-   */
-  function reveal(revealers) {
-    const promises = [];
-    for (let i = 0; i < revealers.length; ++i)
-      promises.push(revealers[i].reveal(/** @type {!Object} */ (revealable), omitFocus));
-    return Promise.race(promises);
-  }
-};
-
-/**
- * @param {?Object} revealable
- * @return {?string}
- */
-export const revealDestination = function(revealable) {
-  const extension = self.runtime.extension(Common.Revealer, revealable);
-  if (!extension)
-    return null;
-  return extension.descriptor()['destination'];
-};
-
-/* Legacy exported object */
-self.Common = self.Common || {};
-Common = Common || {};
-
-/**
- * @interface
- */
-Common.Revealer = Revealer;
-Common.Revealer.reveal = reveal;
-Common.Revealer.revealDestination = revealDestination;
diff --git a/third_party/blink/renderer/devtools/front_end/common/Runnable.js b/third_party/blink/renderer/devtools/front_end/common/Runnable.js
deleted file mode 100644
index 5edda69..0000000
--- a/third_party/blink/renderer/devtools/front_end/common/Runnable.js
+++ /dev/null
@@ -1,23 +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.
-
-/**
- * @interface
- */
-export default class Runnable {
-  /**
-   * @return {!Promise}
-   */
-  run() {
-  }
-}
-
-/* Legacy exported object */
-self.Common = self.Common || {};
-Common = Common || {};
-
-/**
- * @interface
- */
-Common.Runnable = Runnable;
diff --git a/third_party/blink/renderer/devtools/front_end/common/SegmentedRange.js b/third_party/blink/renderer/devtools/front_end/common/SegmentedRange.js
index 9436ba1..ddb66da 100644
--- a/third_party/blink/renderer/devtools/front_end/common/SegmentedRange.js
+++ b/third_party/blink/renderer/devtools/front_end/common/SegmentedRange.js
@@ -4,7 +4,7 @@
 /**
  * @unrestricted
  */
-export class Segment {
+Common.Segment = class {
   /**
    * @param {number} begin
    * @param {number} end
@@ -25,12 +25,12 @@
   intersects(that) {
     return this.begin < that.end && that.begin < this.end;
   }
-}
+};
 
 /**
  * @unrestricted
  */
-export default class SegmentedRange {
+Common.SegmentedRange = class {
   /**
    * @param {(function(!Common.Segment, !Common.Segment): ?Common.Segment)=} mergeCallback
    */
@@ -108,18 +108,4 @@
     merged.end = Math.max(first.end, second.end);
     return merged;
   }
-}
-
-/* Legacy exported object */
-self.Common = self.Common || {};
-Common = Common || {};
-
-/**
- * @constructor
- */
-Common.Segment = Segment;
-
-/**
- * @constructor
- */
-Common.SegmentedRange = SegmentedRange;
+};
diff --git a/third_party/blink/renderer/devtools/front_end/common/Settings.js b/third_party/blink/renderer/devtools/front_end/common/Settings.js
index ede3af62..2c1e9844 100644
--- a/third_party/blink/renderer/devtools/front_end/common/Settings.js
+++ b/third_party/blink/renderer/devtools/front_end/common/Settings.js
@@ -31,7 +31,7 @@
 /**
  * @unrestricted
  */
-export default class Settings {
+Common.Settings = class {
   /**
    * @param {!Common.SettingsStorage} globalStorage
    * @param {!Common.SettingsStorage} localStorage
@@ -164,12 +164,12 @@
     }
     return this._globalStorage;
   }
-}
+};
 
 /**
  * @unrestricted
  */
-export class SettingsStorage {
+Common.SettingsStorage = class {
   /**
    * @param {!Object} object
    * @param {function(string, string)=} setCallback
@@ -244,13 +244,13 @@
     for (let i = 0; i < 10 && i < keys.length; ++i)
       Common.console.log('Setting: \'' + keys[i] + '\', size: ' + sizes[keys[i]]);
   }
-}
+};
 
 /**
  * @template V
  * @unrestricted
  */
-export class Setting {
+Common.Setting = class {
   /**
    * @param {!Common.Settings} settings
    * @param {string} name
@@ -376,12 +376,12 @@
     Common.console.error(errorMessage);
     this._storage._dumpSizes();
   }
-}
+};
 
 /**
  * @unrestricted
  */
-export class RegExpSetting extends Setting {
+Common.RegExpSetting = class extends Common.Setting {
   /**
    * @param {!Common.Settings} settings
    * @param {string} name
@@ -448,12 +448,12 @@
     }
     return this._regex;
   }
-}
+};
 
 /**
  * @unrestricted
  */
-export class VersionController {
+Common.VersionController = class {
   updateVersion() {
     const localStorageVersion =
         window.localStorage ? window.localStorage[Common.VersionController._currentVersionName] : 0;
@@ -877,12 +877,20 @@
     if (breakpointsSetting.get().length > maxBreakpointsCount)
       breakpointsSetting.set([]);
   }
-}
+};
+
+Common.VersionController._currentVersionName = 'inspectorVersion';
+Common.VersionController.currentVersion = 28;
+
+/**
+ * @type {!Common.Settings}
+ */
+Common.settings;
 
 /**
  * @enum {symbol}
  */
-export const SettingStorageType = {
+Common.SettingStorageType = {
   Global: Symbol('Global'),
   Local: Symbol('Local'),
   Session: Symbol('Session')
@@ -892,58 +900,14 @@
  * @param {string} settingName
  * @return {!Common.Setting}
  */
-export function moduleSetting(settingName) {
+Common.moduleSetting = function(settingName) {
   return Common.settings.moduleSetting(settingName);
-}
+};
 
 /**
  * @param {string} settingName
  * @return {!Common.Setting}
  */
-export function settingForTest(settingName) {
+Common.settingForTest = function(settingName) {
   return Common.settings.settingForTest(settingName);
-}
-
-/* Legacy exported object */
-self.Common = self.Common || {};
-Common = Common || {};
-
-/**
- * @constructor
- */
-Common.Settings = Settings;
-
-/**
- * @constructor
- */
-Common.SettingsStorage = SettingsStorage;
-
-/**
- * @constructor
- */
-Common.Setting = Setting;
-
-/**
- * @constructor
- */
-Common.RegExpSetting = RegExpSetting;
-Common.settingForTest = settingForTest;
-
-/**
- * @constructor
- */
-Common.VersionController = VersionController;
-Common.moduleSetting = moduleSetting;
-
-/**
- * @enum {symbol}
- */
-Common.SettingStorageType = SettingStorageType;
-
-Common.VersionController._currentVersionName = 'inspectorVersion';
-Common.VersionController.currentVersion = 28;
-
-/**
- * @type {!Common.Settings}
- */
-Common.settings;
+};
diff --git a/third_party/blink/renderer/devtools/front_end/common/StaticContentProvider.js b/third_party/blink/renderer/devtools/front_end/common/StaticContentProvider.js
index 9575a9a..96fd157 100644
--- a/third_party/blink/renderer/devtools/front_end/common/StaticContentProvider.js
+++ b/third_party/blink/renderer/devtools/front_end/common/StaticContentProvider.js
@@ -5,7 +5,7 @@
  * @implements {Common.ContentProvider}
  * @unrestricted
  */
-export default class StaticContentProvider {
+Common.StaticContentProvider = class {
   /**
    * @param {string} contentURL
    * @param {!Common.ResourceType} contentType
@@ -71,13 +71,4 @@
     const content = await this._lazyContent();
     return content ? Common.ContentProvider.performSearchInContent(content, query, caseSensitive, isRegex) : [];
   }
-}
-
-/* Legacy exported object */
-self.Common = self.Common || {};
-Common = Common || {};
-
-/**
- * @constructor
- */
-Common.StaticContentProvider = StaticContentProvider;
+};
diff --git a/third_party/blink/renderer/devtools/front_end/common/TextDictionary.js b/third_party/blink/renderer/devtools/front_end/common/TextDictionary.js
index e190f39..9c555b2 100644
--- a/third_party/blink/renderer/devtools/front_end/common/TextDictionary.js
+++ b/third_party/blink/renderer/devtools/front_end/common/TextDictionary.js
@@ -31,7 +31,7 @@
 /**
  * @unrestricted
  */
-export default class TextDictionary {
+Common.TextDictionary = class {
   constructor() {
     /** @type {!Map<string, number>} */
     this._words = new Map();
@@ -92,10 +92,4 @@
     this._words.clear();
     this._index.clear();
   }
-}
-
-/* Legacy exported object */
-self.Common = self.Common || {};
-Common = Common || {};
-
-Common.TextDictionary = TextDictionary;
+};
diff --git a/third_party/blink/renderer/devtools/front_end/common/Throttler.js b/third_party/blink/renderer/devtools/front_end/common/Throttler.js
index 21c5f797..a88e78f5 100644
--- a/third_party/blink/renderer/devtools/front_end/common/Throttler.js
+++ b/third_party/blink/renderer/devtools/front_end/common/Throttler.js
@@ -1,11 +1,10 @@
 // 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.
-
 /**
  * @unrestricted
  */
-export default class Throttler {
+Common.Throttler = class {
   /**
    * @param {number} timeout
    */
@@ -109,13 +108,7 @@
   _getTime() {
     return window.performance.now();
   }
-}
-
-/* Legacy exported object */
-self.Common = self.Common || {};
-Common = Common || {};
-
-Common.Throttler = Throttler;
+};
 
 /** @typedef {function(!Error=)} */
 Common.Throttler.FinishCallback;
diff --git a/third_party/blink/renderer/devtools/front_end/common/Trie.js b/third_party/blink/renderer/devtools/front_end/common/Trie.js
index 22afde9f..98291c50 100644
--- a/third_party/blink/renderer/devtools/front_end/common/Trie.js
+++ b/third_party/blink/renderer/devtools/front_end/common/Trie.js
@@ -4,7 +4,7 @@
 /**
  * @unrestricted
  */
-export default class Trie {
+Common.Trie = class {
   constructor() {
     this.clear();
   }
@@ -132,10 +132,4 @@
     /** @type {!Array<number>} */
     this._freeNodes = [];
   }
-}
-
-/* Legacy exported object */
-self.Common = self.Common || {};
-Common = Common || {};
-
-Common.Trie = Trie;
+};
diff --git a/third_party/blink/renderer/devtools/front_end/common/UIString.js b/third_party/blink/renderer/devtools/front_end/common/UIString.js
index 64b1fcc..cd5f7d08e 100644
--- a/third_party/blink/renderer/devtools/front_end/common/UIString.js
+++ b/third_party/blink/renderer/devtools/front_end/common/UIString.js
@@ -29,55 +29,57 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+self['Common'] = self['Common'] || {};
+
 /**
  * @param {string} string
  * @param {...*} vararg
  * @return {string}
  */
-export default function UIString(string, vararg) {
+Common.UIString = function(string, vararg) {
   return String.vsprintf(Common.localize(string), Array.prototype.slice.call(arguments, 1));
-}
+};
 
 /**
  * @param {string} string
  * @param {?ArrayLike} values
  * @return {string}
  */
-export function serializeUIString(string, values = []) {
+Common.serializeUIString = function(string, values = []) {
   const messageParts = [string];
   const serializedMessage = {messageParts, values};
   return JSON.stringify(serializedMessage);
-}
+};
 
 /**
  * @param {string} serializedMessage
  * @return {*}
  */
-export function deserializeUIString(serializedMessage) {
+Common.deserializeUIString = function(serializedMessage) {
   if (!serializedMessage)
     return {};
 
   return JSON.parse(serializedMessage);
-}
+};
 
 /**
  * @param {string} string
  * @return {string}
  */
-export function localize(string) {
+Common.localize = function(string) {
   return string;
-}
+};
 
 /**
  * @unrestricted
  */
-export class UIStringFormat {
+Common.UIStringFormat = class {
   /**
    * @param {string} format
    */
   constructor(format) {
     /** @type {string} */
-    this._localizedFormat = localize(format);
+    this._localizedFormat = Common.localize(format);
     /** @type {!Array.<!Object>} */
     this._tokenizedFormat = String.tokenizeFormatString(this._localizedFormat, String.standardFormatters);
   }
@@ -102,7 +104,10 @@
             this._tokenizedFormat)
         .formattedResult;
   }
-}
+};
+
+/** @type {!WeakMap<!Array<string>, string>} */
+Common._substitutionStrings = new WeakMap();
 
 /**
  * @param {!Array<string>|string} strings
@@ -119,20 +124,3 @@
   }
   return Common.UIString(substitutionString, ...Array.prototype.slice.call(arguments, 1));
 };
-
-/* Legacy exported object */
-self.Common = self.Common || {};
-Common = Common || {};
-
-/**
- * @constructor
- */
-Common.UIStringFormat = UIStringFormat;
-
-Common.UIString = UIString;
-Common.serializeUIString = serializeUIString;
-Common.deserializeUIString = deserializeUIString;
-Common.localize = localize;
-
-/** @type {!WeakMap<!Array<string>, string>} */
-Common._substitutionStrings = new WeakMap();
diff --git a/third_party/blink/renderer/devtools/front_end/common/Worker.js b/third_party/blink/renderer/devtools/front_end/common/Worker.js
index a9c31a6..5bdaced 100644
--- a/third_party/blink/renderer/devtools/front_end/common/Worker.js
+++ b/third_party/blink/renderer/devtools/front_end/common/Worker.js
@@ -31,7 +31,7 @@
 /**
  * @unrestricted
  */
-export default class WorkerWrapper {
+Common.Worker = class {
   /**
    * @param {string} appName
    */
@@ -91,13 +91,4 @@
   set onerror(listener) {
     this._workerPromise.then(worker => worker.onerror = listener);
   }
-}
-
-/* Legacy exported object */
-self.Common = self.Common || {};
-Common = Common || {};
-
-/**
- * @constructor
- */
-Common.Worker = WorkerWrapper;
+};
diff --git a/third_party/blink/renderer/devtools/front_end/common/common.js b/third_party/blink/renderer/devtools/front_end/common/common.js
deleted file mode 100644
index fe28919..0000000
--- a/third_party/blink/renderer/devtools/front_end/common/common.js
+++ /dev/null
@@ -1,62 +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 './EventTarget.js';
-import './Object.js';
-
-// Do not reorder these imports as it breaks dependencies.
-
-import * as App from './App.js';
-import * as AppProvider from './AppProvider.js';
-import * as CharacterIdMap from './CharacterIdMap.js';
-import * as Color from './Color.js';
-import * as Console from './Console.js';
-import * as ContentProvider from './ContentProvider.js';
-import * as EventTarget from './EventTarget.js';
-import * as JavaScriptMetaData from './JavaScriptMetaData.js';
-import * as Linkifier from './Linkifier.js';
-import * as Object from './Object.js';
-import * as ParsedURL from './ParsedURL.js';
-import * as Progress from './Progress.js';
-import * as QueryParamHandler from './QueryParamHandler.js';
-import * as ResourceType from './ResourceType.js';
-import * as Revealer from './Revealer.js';
-import * as Runnable from './Runnable.js';
-import * as SegmentedRange from './SegmentedRange.js';
-import * as Settings from './Settings.js';
-import * as StaticContentProvider from './StaticContentProvider.js';
-import * as StringOutputStream from './StringOutputStream.js';
-import * as TextDictionary from './TextDictionary.js';
-import * as Throttler from './Throttler.js';
-import * as Trie from './Trie.js';
-import * as UIString from './UIString.js';
-import * as Worker from './Worker.js';
-
-export {
-  App,
-  AppProvider,
-  CharacterIdMap,
-  Color,
-  Console,
-  ContentProvider,
-  EventTarget,
-  JavaScriptMetaData,
-  Linkifier,
-  Object,
-  ParsedURL,
-  Progress,
-  QueryParamHandler,
-  ResourceType,
-  Revealer,
-  Runnable,
-  SegmentedRange,
-  Settings,
-  StaticContentProvider,
-  StringOutputStream,
-  TextDictionary,
-  Throttler,
-  Trie,
-  UIString,
-  Worker,
-};
diff --git a/third_party/blink/renderer/devtools/front_end/common/module.json b/third_party/blink/renderer/devtools/front_end/common/module.json
index e685577..99b5427 100644
--- a/third_party/blink/renderer/devtools/front_end/common/module.json
+++ b/third_party/blink/renderer/devtools/front_end/common/module.json
@@ -3,12 +3,10 @@
         "text_utils",
         "platform"
     ],
-    "modules": [
-        "common.js",
-        "EventTarget.js",
-        "Object.js",
+    "scripts": [
         "Worker.js",
         "TextDictionary.js",
+        "Object.js",
         "Color.js",
         "Console.js",
         "ContentProvider.js",
@@ -17,20 +15,12 @@
         "ResourceType.js",
         "Settings.js",
         "StaticContentProvider.js",
+        "OutputStream.js",
         "SegmentedRange.js",
         "Throttler.js",
         "Trie.js",
         "UIString.js",
-        "Revealer.js",
-        "App.js",
-        "AppProvider.js",
-        "JavaScriptMetaData.js",
-        "Linkifier.js",
-        "QueryParamHandler.js",
-        "Revealer.js",
-        "Runnable.js",
-        "StringOutputStream.js",
+        "ModuleExtensionInterfaces.js",
         "CharacterIdMap.js"
-    ],
-    "scripts": []
+    ]
 }
diff --git a/third_party/blink/renderer/devtools/front_end/elements/EventListenersWidget.js b/third_party/blink/renderer/devtools/front_end/elements/EventListenersWidget.js
index 1f94f5ad..3b861ffc 100644
--- a/third_party/blink/renderer/devtools/front_end/elements/EventListenersWidget.js
+++ b/third_party/blink/renderer/devtools/front_end/elements/EventListenersWidget.js
@@ -54,8 +54,8 @@
     this._toolbarItems.push(new UI.ToolbarSettingCheckbox(
         this._showForAncestorsSetting, Common.UIString('Show listeners on the ancestors'),
         Common.UIString('Ancestors')));
-    const dispatchFilter = new UI.ToolbarComboBox(this._onDispatchFilterTypeChanged.bind(this));
-    dispatchFilter.setTitle(ls`Event listeners category`);
+    const dispatchFilter =
+        new UI.ToolbarComboBox(this._onDispatchFilterTypeChanged.bind(this), ls`Event listeners category`);
 
     /**
      * @param {string} name
diff --git a/third_party/blink/renderer/devtools/front_end/heap_snapshot_worker.js b/third_party/blink/renderer/devtools/front_end/heap_snapshot_worker.js
index 7750502..44b9b2e 100644
--- a/third_party/blink/renderer/devtools/front_end/heap_snapshot_worker.js
+++ b/third_party/blink/renderer/devtools/front_end/heap_snapshot_worker.js
@@ -2,13 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 // Release build has Runtime.js bundled.
-
-// FIXME(http://crbug.com/1007254)
-const __import = path => {
-  const relativePath = new URL(path, self.location.href);
-  return eval(`import('${relativePath}')`);
-};
-
 if (!self.Runtime)
   self.importScripts('Runtime.js');
-__import('./common/common.js').then(_ => Runtime.startWorker('heap_snapshot_worker'));
+Runtime.startWorker('heap_snapshot_worker');
diff --git a/third_party/blink/renderer/devtools/front_end/javascript_metadata/JavaScriptMetadata.js b/third_party/blink/renderer/devtools/front_end/javascript_metadata/JavaScriptMetadata.js
index 4002240..022a911 100644
--- a/third_party/blink/renderer/devtools/front_end/javascript_metadata/JavaScriptMetadata.js
+++ b/third_party/blink/renderer/devtools/front_end/javascript_metadata/JavaScriptMetadata.js
@@ -71,4 +71,4 @@
  *  receiver: (string|undefined),
  * }>}
  */
-JavaScriptMetadata.NativeFunctions;
+JavaScriptMetadata.NativeFunctions;
\ No newline at end of file
diff --git a/third_party/blink/renderer/devtools/front_end/langpacks/shared_strings.grdp b/third_party/blink/renderer/devtools/front_end/langpacks/shared_strings.grdp
index f8b16f8..0fc5d67 100644
--- a/third_party/blink/renderer/devtools/front_end/langpacks/shared_strings.grdp
+++ b/third_party/blink/renderer/devtools/front_end/langpacks/shared_strings.grdp
@@ -4,6 +4,9 @@
   <message name="IDS_DEVTOOLS_007c41a9025be2c8e14b496ed3ee00f8" desc="Text to save an item">
     Save…
   </message>
+  <message name="IDS_DEVTOOLS_040c4b52a3c06c6067fac76c4c7c3a2c" desc="Title of the 'Network conditions' tool in the bottom drawer">
+    Network conditions
+  </message>
   <message name="IDS_DEVTOOLS_0511551e6cf7d61acd9b62f9304efa93" desc="Tooltip text that appears on the setting to preserve log when hovering over the item">
     Do not clear log on page reload / navigation
   </message>
diff --git a/third_party/blink/renderer/devtools/front_end/mobile_throttling/ThrottlingManager.js b/third_party/blink/renderer/devtools/front_end/mobile_throttling/ThrottlingManager.js
index c2f0faa8..e5559cf 100644
--- a/third_party/blink/renderer/devtools/front_end/mobile_throttling/ThrottlingManager.js
+++ b/third_party/blink/renderer/devtools/front_end/mobile_throttling/ThrottlingManager.js
@@ -215,7 +215,7 @@
    */
   createCPUThrottlingSelector() {
     const control = new UI.ToolbarComboBox(
-        event => this.setCPUThrottlingRate(this._cpuThrottlingRates[event.target.selectedIndex]));
+        event => this.setCPUThrottlingRate(this._cpuThrottlingRates[event.target.selectedIndex]), ls`CPU throttling`);
     this._cpuThrottlingControls.add(control);
     const currentRate = this._cpuThrottlingRate;
 
diff --git a/third_party/blink/renderer/devtools/front_end/mobile_throttling/mobile_throttling_strings.grdp b/third_party/blink/renderer/devtools/front_end/mobile_throttling/mobile_throttling_strings.grdp
index b1d7b68..dd04e53 100644
--- a/third_party/blink/renderer/devtools/front_end/mobile_throttling/mobile_throttling_strings.grdp
+++ b/third_party/blink/renderer/devtools/front_end/mobile_throttling/mobile_throttling_strings.grdp
@@ -24,6 +24,9 @@
   <message name="IDS_DEVTOOLS_38c8cb828795cd6ff1cddda9b4ffcfa8" desc="Text in Throttling Settings Tab of the Network panel">
     <ph name="THROUGHPUTINKBPS___________">$1d<ex>25</ex></ph><ph name="DELIMITER">$2s<ex>''' '''</ex></ph>Mb/s
   </message>
+  <message name="IDS_DEVTOOLS_4121424dddde880a0e380f82c57e9944" desc="Screen reader label for a select box that chooses the CPU throttling speed in the Performance panel">
+    CPU throttling
+  </message>
   <message name="IDS_DEVTOOLS_4fafba98ddd8a8663d8775a928f2450e" desc="Icon title in Network Panel Indicator of the Network panel">
     Requests may be blocked
   </message>
diff --git a/third_party/blink/renderer/devtools/front_end/network/BinaryResourceView.js b/third_party/blink/renderer/devtools/front_end/network/BinaryResourceView.js
index 879387c..cfb20db 100644
--- a/third_party/blink/renderer/devtools/front_end/network/BinaryResourceView.js
+++ b/third_party/blink/renderer/devtools/front_end/network/BinaryResourceView.js
@@ -40,7 +40,7 @@
           this._binaryResourceViewFactory.utf8.bind(this._binaryResourceViewFactory)),
     ];
     this._binaryViewTypeSetting = Common.settings.createSetting('binaryViewType', 'hex');
-    this._binaryViewTypeCombobox = new UI.ToolbarComboBox(this._binaryViewTypeChanged.bind(this));
+    this._binaryViewTypeCombobox = new UI.ToolbarComboBox(this._binaryViewTypeChanged.bind(this), ls`Binary view type`);
     for (const viewObject of this._binaryViewObjects) {
       this._binaryViewTypeCombobox.addOption(
           this._binaryViewTypeCombobox.createOption(viewObject.label, viewObject.type));
diff --git a/third_party/blink/renderer/devtools/front_end/network/NetworkPanel.js b/third_party/blink/renderer/devtools/front_end/network/NetworkPanel.js
index afc839c..bca2026 100644
--- a/third_party/blink/renderer/devtools/front_end/network/NetworkPanel.js
+++ b/third_party/blink/renderer/devtools/front_end/network/NetworkPanel.js
@@ -260,8 +260,7 @@
    * @return {!UI.ToolbarComboBox}
    */
   _createThrottlingConditionsSelect() {
-    const toolbarItem = new UI.ToolbarComboBox(null);
-    toolbarItem.setTitle(ls`Throttling`);
+    const toolbarItem = new UI.ToolbarComboBox(null, ls`Throttling`);
     toolbarItem.setMaxWidth(160);
     MobileThrottling.throttlingManager().decorateSelectWithNetworkThrottling(toolbarItem.selectElement());
     return toolbarItem;
diff --git a/third_party/blink/renderer/devtools/front_end/network/ResourceWebSocketFrameView.js b/third_party/blink/renderer/devtools/front_end/network/ResourceWebSocketFrameView.js
index f8160fa1..4474597 100644
--- a/third_party/blink/renderer/devtools/front_end/network/ResourceWebSocketFrameView.js
+++ b/third_party/blink/renderer/devtools/front_end/network/ResourceWebSocketFrameView.js
@@ -64,7 +64,7 @@
     this._clearAllButton.addEventListener(UI.ToolbarButton.Events.Click, this._clearFrames, this);
     this._mainToolbar.appendToolbarItem(this._clearAllButton);
 
-    this._filterTypeCombobox = new UI.ToolbarComboBox(this._updateFilterSetting.bind(this));
+    this._filterTypeCombobox = new UI.ToolbarComboBox(this._updateFilterSetting.bind(this), ls`Filter`);
     for (const filterItem of Network.ResourceWebSocketFrameView._filterTypes) {
       const option = this._filterTypeCombobox.createOption(filterItem.label, filterItem.name);
       this._filterTypeCombobox.addOption(option);
diff --git a/third_party/blink/renderer/devtools/front_end/network/network_strings.grdp b/third_party/blink/renderer/devtools/front_end/network/network_strings.grdp
index ef3f966..08cff50 100644
--- a/third_party/blink/renderer/devtools/front_end/network/network_strings.grdp
+++ b/third_party/blink/renderer/devtools/front_end/network/network_strings.grdp
@@ -15,9 +15,6 @@
   <message name="IDS_DEVTOOLS_0382c94481db9197dd5a72ea4bdd2ff0" desc="A tag of Network Conditions tool that can be searched in the command menu">
     disk cache
   </message>
-  <message name="IDS_DEVTOOLS_040c4b52a3c06c6067fac76c4c7c3a2c" desc="Title of the 'Network conditions' tool in the bottom drawer">
-    Network conditions
-  </message>
   <message name="IDS_DEVTOOLS_059f48d76d79fe0727740d75dc81fa94" desc="Text in Network Log View of the Network panel">
     <ph name="SELECTEDTRANSFERSIZE">$1s<ex>25</ex></ph> B / <ph name="TRANSFERSIZE">$2s<ex>25</ex></ph> B transferred
   </message>
@@ -180,6 +177,9 @@
   <message name="IDS_DEVTOOLS_3b83f6ae91bb21147fd97b8b8229287f" desc="Text in Signed Exchange Info View of the Network panel">
     Certificate URL
   </message>
+  <message name="IDS_DEVTOOLS_3b8fa30c5cdb1ef67ffdd3bf7ba9ff4b" desc="Screen reader label for a select box that chooses how to display binary data in the Network panel">
+    Binary view type
+  </message>
   <message name="IDS_DEVTOOLS_3c06899dae839e1ca3051475a2b8fa05" desc="Text in Request Preview View of the Network panel">
     Preview not available
   </message>
diff --git a/third_party/blink/renderer/devtools/front_end/profiler/HeapSnapshotView.js b/third_party/blink/renderer/devtools/front_end/profiler/HeapSnapshotView.js
index e15f102..03f523e 100644
--- a/third_party/blink/renderer/devtools/front_end/profiler/HeapSnapshotView.js
+++ b/third_party/blink/renderer/devtools/front_end/profiler/HeapSnapshotView.js
@@ -133,14 +133,14 @@
       this._perspectives.push(new Profiler.HeapSnapshotView.AllocationPerspective());
     this._perspectives.push(new Profiler.HeapSnapshotView.StatisticsPerspective());
 
-    this._perspectiveSelect = new UI.ToolbarComboBox(this._onSelectedPerspectiveChanged.bind(this));
+    this._perspectiveSelect = new UI.ToolbarComboBox(this._onSelectedPerspectiveChanged.bind(this), ls`Perspective`);
     this._updatePerspectiveOptions();
 
-    this._baseSelect = new UI.ToolbarComboBox(this._changeBase.bind(this));
+    this._baseSelect = new UI.ToolbarComboBox(this._changeBase.bind(this), ls`Base snapshot`);
     this._baseSelect.setVisible(false);
     this._updateBaseOptions();
 
-    this._filterSelect = new UI.ToolbarComboBox(this._changeFilter.bind(this));
+    this._filterSelect = new UI.ToolbarComboBox(this._changeFilter.bind(this), ls`Filter`);
     this._filterSelect.setVisible(false);
     this._updateFilterOptions();
 
diff --git a/third_party/blink/renderer/devtools/front_end/profiler/ProfileView.js b/third_party/blink/renderer/devtools/front_end/profiler/ProfileView.js
index 38f6a6e..008c196 100644
--- a/third_party/blink/renderer/devtools/front_end/profiler/ProfileView.js
+++ b/third_party/blink/renderer/devtools/front_end/profiler/ProfileView.js
@@ -33,8 +33,7 @@
     this.dataGrid.addEventListener(DataGrid.DataGrid.Events.SelectedNode, this._nodeSelected.bind(this, true));
     this.dataGrid.addEventListener(DataGrid.DataGrid.Events.DeselectedNode, this._nodeSelected.bind(this, false));
 
-    this.viewSelectComboBox = new UI.ToolbarComboBox(this._changeView.bind(this));
-    this.viewSelectComboBox.setTitle(ls`Profile view mode`);
+    this.viewSelectComboBox = new UI.ToolbarComboBox(this._changeView.bind(this), ls`Profile view mode`);
 
     this.focusButton = new UI.ToolbarButton(Common.UIString('Focus selected function'), 'largeicon-visibility');
     this.focusButton.setEnabled(false);
diff --git a/third_party/blink/renderer/devtools/front_end/profiler/profiler_strings.grdp b/third_party/blink/renderer/devtools/front_end/profiler/profiler_strings.grdp
index 574fbcda..bf670e1 100644
--- a/third_party/blink/renderer/devtools/front_end/profiler/profiler_strings.grdp
+++ b/third_party/blink/renderer/devtools/front_end/profiler/profiler_strings.grdp
@@ -66,6 +66,9 @@
   <message name="IDS_DEVTOOLS_2f318b400ebcb22420251535452efef0" desc="Text in Heap Snapshot View of a profiler tool">
     Containment
   </message>
+  <message name="IDS_DEVTOOLS_2f31c2eec148687f0ae649ecf35af762" desc="Screen reader label for a select box that chooses the snapshot to use as a base in the Memory panel when vieweing a Heap Snapshot">
+    Base snapshot
+  </message>
   <message name="IDS_DEVTOOLS_30f4a219667bb46c6fc92f3d665a866c" desc="aria label for javascript VM instances target list in heap profiler">
     JavaScript VM instances
   </message>
@@ -282,6 +285,9 @@
   <message name="IDS_DEVTOOLS_a7bd935a88c629dc11c52e0c16c2a8a0" desc="Text in Heap Snapshot Grid Nodes of a profiler tool">
     <ph name="DISTANCE">$1d<ex>2</ex></ph>
   </message>
+  <message name="IDS_DEVTOOLS_a80420eef88d11f77532f1b9cb467fa3" desc="Screen reader label for a select box that chooses the perspective in the Memory panel when vieweing a Heap Snapshot">
+    Perspective
+  </message>
   <message name="IDS_DEVTOOLS_a8445619abd08f3ba0ebfcb31183f7f9" desc="Text in Heap Snapshot Grid Nodes of a profiler tool">

   </message>
diff --git a/third_party/blink/renderer/devtools/front_end/protocol/InspectorBackend.js b/third_party/blink/renderer/devtools/front_end/protocol/InspectorBackend.js
index df6ad0b..54c6cb5 100644
--- a/third_party/blink/renderer/devtools/front_end/protocol/InspectorBackend.js
+++ b/third_party/blink/renderer/devtools/front_end/protocol/InspectorBackend.js
@@ -28,10 +28,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/**
- * @typedef {string}
- * @suppress {checkTypes}
- */
+/** @typedef {string} */
 Protocol.Error = Symbol('Protocol.Error');
 
 /**
diff --git a/third_party/blink/renderer/devtools/front_end/root.js b/third_party/blink/renderer/devtools/front_end/root.js
index 022ced9..4590c37c 100644
--- a/third_party/blink/renderer/devtools/front_end/root.js
+++ b/third_party/blink/renderer/devtools/front_end/root.js
@@ -2,5 +2,4 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import './common/common.js';
 import './ui/ui.js';
diff --git a/third_party/blink/renderer/devtools/front_end/sources/BreakpointEditDialog.js b/third_party/blink/renderer/devtools/front_end/sources/BreakpointEditDialog.js
index b3197e44..f675a4b 100644
--- a/third_party/blink/renderer/devtools/front_end/sources/BreakpointEditDialog.js
+++ b/third_party/blink/renderer/devtools/front_end/sources/BreakpointEditDialog.js
@@ -31,7 +31,7 @@
     const toolbar = new UI.Toolbar('source-frame-breakpoint-toolbar', this.contentElement);
     toolbar.appendText(`Line ${editorLineNumber + 1}:`);
 
-    this._typeSelector = new UI.ToolbarComboBox(this._onTypeChanged.bind(this));
+    this._typeSelector = new UI.ToolbarComboBox(this._onTypeChanged.bind(this), ls`Breakpoint type`);
     this._typeSelector.createOption(ls`Breakpoint`, Sources.BreakpointEditDialog.BreakpointType.Breakpoint);
     const conditionalOption = this._typeSelector.createOption(
         ls`Conditional breakpoint`, Sources.BreakpointEditDialog.BreakpointType.Conditional);
diff --git a/third_party/blink/renderer/devtools/front_end/sources/sources_strings.grdp b/third_party/blink/renderer/devtools/front_end/sources/sources_strings.grdp
index 4b6ad4e..5eb40451 100644
--- a/third_party/blink/renderer/devtools/front_end/sources/sources_strings.grdp
+++ b/third_party/blink/renderer/devtools/front_end/sources/sources_strings.grdp
@@ -63,6 +63,9 @@
   <message name="IDS_DEVTOOLS_1f15646f60fc3c1dea747963f02d51ac" desc="Text in Sources Panel of the Sources panel">
     Group by folder
   </message>
+  <message name="IDS_DEVTOOLS_1fbbb6684f67ee895ff5dc2e429697ce" desc="Screen reader label for a select box that chooses the breakpoint type in the Sources panel when editing a breakpoint">
+    Breakpoint type
+  </message>
   <message name="IDS_DEVTOOLS_216a9080bf22a993b2d7f9331d34cc68" desc="Text in Sources Panel of the Sources panel">
     Don&apos;t pause on exceptions
   </message>
diff --git a/third_party/blink/renderer/devtools/front_end/timeline/EventsTimelineTreeView.js b/third_party/blink/renderer/devtools/front_end/timeline/EventsTimelineTreeView.js
index 9a3e6ff..b36a3158 100644
--- a/third_party/blink/renderer/devtools/front_end/timeline/EventsTimelineTreeView.js
+++ b/third_party/blink/renderer/devtools/front_end/timeline/EventsTimelineTreeView.js
@@ -167,13 +167,12 @@
    * @param {!UI.Toolbar} toolbar
    */
   populateToolbar(toolbar) {
-    const durationFilterUI = new UI.ToolbarComboBox(durationFilterChanged.bind(this));
+    const durationFilterUI = new UI.ToolbarComboBox(durationFilterChanged.bind(this), ls`Duration filter`);
     for (const durationMs of Timeline.EventsTimelineTreeView.Filters._durationFilterPresetsMs) {
       durationFilterUI.addOption(durationFilterUI.createOption(
           durationMs ? Common.UIString('\u2265 %d\xa0ms', durationMs) : Common.UIString('All'),
           String(durationMs)));
     }
-    UI.ARIAUtils.setAccessibleName(durationFilterUI.selectElement(), ls`Duration filter`);
     toolbar.appendToolbarItem(durationFilterUI);
 
     const categoryFiltersUI = {};
diff --git a/third_party/blink/renderer/devtools/front_end/timeline/PerformanceModel.js b/third_party/blink/renderer/devtools/front_end/timeline/PerformanceModel.js
index d3ad810..be41243 100644
--- a/third_party/blink/renderer/devtools/front_end/timeline/PerformanceModel.js
+++ b/third_party/blink/renderer/devtools/front_end/timeline/PerformanceModel.js
@@ -37,6 +37,13 @@
   }
 
   /**
+   * @return {?SDK.Target}
+   */
+  mainTarget() {
+    return this._mainTarget;
+  }
+
+  /**
    * @param {number} time
    */
   setRecordStartTime(time) {
diff --git a/third_party/blink/renderer/devtools/front_end/timeline/TimelineEventOverview.js b/third_party/blink/renderer/devtools/front_end/timeline/TimelineEventOverview.js
index 63beaf9..e9a5be5 100644
--- a/third_party/blink/renderer/devtools/front_end/timeline/TimelineEventOverview.js
+++ b/third_party/blink/renderer/devtools/front_end/timeline/TimelineEventOverview.js
@@ -704,3 +704,113 @@
     this._remainder = this._quantDuration - interval;
   }
 };
+
+/**
+ * @unrestricted
+ */
+Timeline.TimelineEventOverviewCoverage = class extends Timeline.TimelineEventOverview {
+  constructor() {
+    super('coverage', Common.UIString('COVERAGE'));
+    this._heapSizeLabel = this.element.createChild('div', 'timeline-overview-coverage-label');
+  }
+
+  resetHeapSizeLabels() {
+    this._heapSizeLabel.textContent = '';
+  }
+
+  /**
+   * @override
+   * @param {?Timeline.PerformanceModel} model
+   */
+  setModel(model) {
+    super.setModel(model);
+    if (this._model)
+      this._coverageModel = model.mainTarget().model(Coverage.CoverageModel);
+  }
+
+  /**
+   * @override
+   */
+  update() {
+    super.update();
+    const ratio = window.devicePixelRatio;
+
+    if (!this._coverageModel)
+      return;
+
+    let total = 0;
+    let total_used = 0;
+    const usedByTimestamp = new Map();
+    for (const urlInfo of this._coverageModel.entries()) {
+      for (const info of urlInfo.entries()) {
+        total += info.size();
+        for (const [stamp, used] of info.usedByTimestamp()) {
+          total_used += used;
+          if (!usedByTimestamp.has(stamp))
+            usedByTimestamp.set(stamp, used);
+          else
+            usedByTimestamp.set(stamp, usedByTimestamp.get(stamp) + used);
+        }
+      }
+    }
+    const percentUsed = total ? Math.round(100 * total_used / total) : 0;
+    const lowerOffset = 3 * ratio;
+
+    const minTime = this._model.recordStartTime();
+    const maxTime =
+        minTime + (this._model.timelineModel().maximumRecordTime() - this._model.timelineModel().minimumRecordTime());
+
+    const lineWidth = 1;
+    const width = this.width();
+    const height = this.height() - lowerOffset;
+    const xFactor = width / (maxTime - minTime);
+    const yFactor = (height - lineWidth) / Math.max(total, 1);
+
+
+    let y = 0;
+    const ctx = this.context();
+    const heightBeyondView = height + lowerOffset + lineWidth;
+    ctx.translate(0.5, 0.5);
+    ctx.beginPath();
+    ctx.moveTo(-lineWidth, heightBeyondView);
+
+    ctx.lineTo(-lineWidth, height - y);
+
+    const entries = Array.from(usedByTimestamp.entries()).sort((a, b) => a[0] - b[0]);
+    let cummulative_used = 0;
+    for (const [stamp, used] of entries) {
+      if (stamp > maxTime)
+        break;
+      const x = (stamp - minTime) * xFactor;
+      cummulative_used += used;
+      y = cummulative_used * yFactor;
+      ctx.lineTo(x, height - y);
+    }
+
+
+    ctx.lineTo(width + lineWidth, height - y);
+    ctx.lineTo(width + lineWidth, heightBeyondView);
+    ctx.closePath();
+
+    ctx.fillStyle = 'hsla(220, 90%, 70%, 0.2)';
+    ctx.fill();
+    ctx.lineWidth = lineWidth;
+    ctx.strokeStyle = 'hsl(220, 90%, 70%)';
+    ctx.stroke();
+
+    cummulative_used = 0;
+    for (const [stamp, used] of entries) {
+      if (stamp > maxTime)
+        break;
+      cummulative_used += used;
+      ctx.beginPath();
+      const x = (stamp - minTime) * xFactor;
+      ctx.arc(x, height - cummulative_used * yFactor, 2 * lineWidth, 0, 2 * Math.PI, false);
+      ctx.closePath();
+      ctx.stroke();
+      ctx.fill();
+    }
+
+    this._heapSizeLabel.textContent = `${percentUsed}% used`;
+  }
+};
diff --git a/third_party/blink/renderer/devtools/front_end/timeline/TimelinePanel.js b/third_party/blink/renderer/devtools/front_end/timeline/TimelinePanel.js
index 4311b1f..4d4f7be 100644
--- a/third_party/blink/renderer/devtools/front_end/timeline/TimelinePanel.js
+++ b/third_party/blink/renderer/devtools/front_end/timeline/TimelinePanel.js
@@ -319,7 +319,7 @@
    * @return {!UI.ToolbarComboBox}
    */
   _createNetworkConditionsSelect() {
-    const toolbarItem = new UI.ToolbarComboBox(null);
+    const toolbarItem = new UI.ToolbarComboBox(null, ls`Network conditions`);
     toolbarItem.setMaxWidth(140);
     MobileThrottling.throttlingManager().decorateSelectWithNetworkThrottling(toolbarItem.selectElement());
     return toolbarItem;
@@ -430,6 +430,8 @@
       this._overviewControls.push(new Timeline.TimelineFilmStripOverview());
     if (this._showMemorySetting.get())
       this._overviewControls.push(new Timeline.TimelineEventOverviewMemory());
+    if (this._startCoverage.get())
+      this._overviewControls.push(new Timeline.TimelineEventOverviewCoverage());
     for (const control of this._overviewControls)
       control.setModel(this._performanceModel);
     this._overviewPane.setOverviewControls(this._overviewControls);
@@ -771,7 +773,8 @@
     if (this._startCoverage.get()) {
       UI.viewManager.showView('coverage')
           .then(() => UI.viewManager.view('coverage').widget())
-          .then(widget => widget.stopRecording());
+          .then(widget => widget.stopRecording())
+          .then(() => this._updateOverviewControls());
     }
   }
 
diff --git a/third_party/blink/renderer/devtools/front_end/timeline/module.json b/third_party/blink/renderer/devtools/front_end/timeline/module.json
index 7a17009..e437532 100644
--- a/third_party/blink/renderer/devtools/front_end/timeline/module.json
+++ b/third_party/blink/renderer/devtools/front_end/timeline/module.json
@@ -220,6 +220,7 @@
     ],
     "dependencies": [
         "components",
+        "coverage",
         "layer_viewer",
         "timeline_model",
         "perf_ui",
diff --git a/third_party/blink/renderer/devtools/front_end/timeline/timelinePanel.css b/third_party/blink/renderer/devtools/front_end/timeline/timelinePanel.css
index 225c6a9..e4c089ff 100644
--- a/third_party/blink/renderer/devtools/front_end/timeline/timelinePanel.css
+++ b/third_party/blink/renderer/devtools/front_end/timeline/timelinePanel.css
@@ -240,6 +240,21 @@
     line-height: 18px;
 }
 
+#timeline-overview-coverage {
+    flex-basis: 20px;
+}
+
+.timeline-overview-coverage-label {
+    position: absolute;
+    right: 0;
+    bottom: 0;
+    font-size: 9px;
+    color: #888;
+    white-space: nowrap;
+    padding: 0 4px;
+    background-color: hsla(0, 0%, 100%, 0.8);
+}
+
 .timeline-details {
     vertical-align: top;
 }
diff --git a/third_party/blink/renderer/devtools/front_end/timeline/timeline_strings.grdp b/third_party/blink/renderer/devtools/front_end/timeline/timeline_strings.grdp
index 9442d983..0d615980 100644
--- a/third_party/blink/renderer/devtools/front_end/timeline/timeline_strings.grdp
+++ b/third_party/blink/renderer/devtools/front_end/timeline/timeline_strings.grdp
@@ -639,6 +639,9 @@
   <message name="IDS_DEVTOOLS_a580a76abe8b0912889d80f5c4cb9559" desc="Text in Timeline Tree View of the Performance panel">
     Group by Product
   </message>
+  <message name="IDS_DEVTOOLS_a5d91e1697b7c75863fb9c6163a3446e" desc="Text in Timeline Event Overview of the Performance panel">
+    COVERAGE
+  </message>
   <message name="IDS_DEVTOOLS_a6f22a2373839a1d417d7a4078f0383a" desc="Text in Timeline Panel of the Performance panel">
     - CPU throttling is enabled
   </message>
diff --git a/third_party/blink/renderer/devtools/front_end/ui/ARIAUtils.js b/third_party/blink/renderer/devtools/front_end/ui/ARIAUtils.js
index 088e6ee..ac714f32 100644
--- a/third_party/blink/renderer/devtools/front_end/ui/ARIAUtils.js
+++ b/third_party/blink/renderer/devtools/front_end/ui/ARIAUtils.js
@@ -46,12 +46,10 @@
 
 /**
  * @param {!Element} element
- * @param {boolean=} modal
  */
-export function markAsDialog(element, modal) {
+export function markAsModalDialog(element) {
   element.setAttribute('role', 'dialog');
-  if (modal)
-    element.setAttribute('aria-modal', 'true');
+  element.setAttribute('aria-modal', 'true');
 }
 
 /**
@@ -452,7 +450,7 @@
   markAsAlert,
   markAsButton,
   markAsCheckbox,
-  markAsDialog,
+  markAsModalDialog,
   markAsGroup,
   markAsLink,
   markAsMenuButton,
diff --git a/third_party/blink/renderer/devtools/front_end/ui/Dialog.js b/third_party/blink/renderer/devtools/front_end/ui/Dialog.js
index 7b146fc..3a45ac64 100644
--- a/third_party/blink/renderer/devtools/front_end/ui/Dialog.js
+++ b/third_party/blink/renderer/devtools/front_end/ui/Dialog.js
@@ -42,7 +42,7 @@
       this.hide();
       event.consume(true);
     });
-    UI.ARIAUtils.markAsDialog(this.contentElement, true);
+    UI.ARIAUtils.markAsModalDialog(this.contentElement);
     /** @type {!Map<!HTMLElement, number>} */
     this._tabIndexMap = new Map();
     /** @type {?UI.WidgetFocusRestorer} */
diff --git a/third_party/blink/renderer/devtools/front_end/ui/Toolbar.js b/third_party/blink/renderer/devtools/front_end/ui/Toolbar.js
index ff51637..7a0a3163 100644
--- a/third_party/blink/renderer/devtools/front_end/ui/Toolbar.js
+++ b/third_party/blink/renderer/devtools/front_end/ui/Toolbar.js
@@ -833,9 +833,10 @@
 UI.ToolbarComboBox = class extends UI.ToolbarItem {
   /**
    * @param {?function(!Event)} changeHandler
+   * @param {string} title
    * @param {string=} className
    */
-  constructor(changeHandler, className) {
+  constructor(changeHandler, title, className) {
     super(createElementWithClass('span', 'toolbar-select-container'));
 
     this._selectElement = this.element.createChild('select', 'toolbar-item');
@@ -843,17 +844,10 @@
     this.element.appendChild(dropdownArrowIcon);
     if (changeHandler)
       this._selectElement.addEventListener('change', changeHandler, false);
-    if (className)
-      this._selectElement.classList.add(className);
-  }
-
-  /**
-   * @override
-   * @param {string} title
-   */
-  setTitle(title) {
     UI.ARIAUtils.setAccessibleName(this._selectElement, title);
     super.setTitle(title);
+    if (className)
+      this._selectElement.classList.add(className);
   }
 
   /**
@@ -969,15 +963,13 @@
   /**
    * @param {!Array<!{value: string, label: string}>} options
    * @param {!Common.Setting} setting
-   * @param {string=} accessibleName
+   * @param {string} accessibleName
    */
   constructor(options, setting, accessibleName) {
-    super(null);
+    super(null, accessibleName);
     this._options = options;
     this._setting = setting;
     this._selectElement.addEventListener('change', this._valueChanged.bind(this), false);
-    if (accessibleName)
-      UI.ARIAUtils.setAccessibleName(this._selectElement, accessibleName);
     this.setOptions(options);
     setting.addChangeListener(this._settingChanged, this);
   }
diff --git a/third_party/blink/renderer/devtools/karma.conf.js b/third_party/blink/renderer/devtools/karma.conf.js
index acc4d2be..860d9bf 100644
--- a/third_party/blink/renderer/devtools/karma.conf.js
+++ b/third_party/blink/renderer/devtools/karma.conf.js
@@ -32,16 +32,19 @@
       compilerOptions: {
         target: "esnext",
         module: "esnext",
-        typeRoots: ["./third_party/devtools-node-modules/third_party/node_modules/@types"]
+        typeRoots: ["../../../../third_party/devtools-node-modules/third_party/node_modules/@types"]
       },
       coverageOptions: {
         instrumentation: false
       },
       bundlerOptions: {
         resolve: {
-          directories: ["./third_party/devtools-node-modules/third_party/node_modules"]
+          directories: ["../../../../third_party/devtools-node-modules/third_party/node_modules"]
         }
-      }
+      },
+      exclude: [
+        "scripts"
+      ]
     },
 
     proxies: {
diff --git a/third_party/blink/renderer/devtools/scripts/compile_frontend.py b/third_party/blink/renderer/devtools/scripts/compile_frontend.py
index 0f251eb..9a3eb88 100755
--- a/third_party/blink/renderer/devtools/scripts/compile_frontend.py
+++ b/third_party/blink/renderer/devtools/scripts/compile_frontend.py
@@ -279,9 +279,9 @@
         '--externs',
         namespace_externs_path,
         '--js',
-        ROOT_MODULE_FILE,
-        '--js',
         RUNTIME_FILE,
+        '--js',
+        ROOT_MODULE_FILE,
     ]
 
     all_files = descriptors.all_compiled_files()
@@ -318,6 +318,7 @@
     namespace_externs_file = tempfile.NamedTemporaryFile(mode='wt', delete=False)
     try:
         for namespace in namespaces:
+            namespace_externs_file.write('/** @const */\n')
             namespace_externs_file.write('var %s = {};\n' % namespace)
     finally:
         namespace_externs_file.close()
diff --git a/third_party/blink/renderer/devtools/tests/front_end/platform/dom-extension.js b/third_party/blink/renderer/devtools/tests/front_end/platform/dom-extension.ts
similarity index 96%
rename from third_party/blink/renderer/devtools/tests/front_end/platform/dom-extension.js
rename to third_party/blink/renderer/devtools/tests/front_end/platform/dom-extension.ts
index 30510a7..cf2a59a 100644
--- a/third_party/blink/renderer/devtools/tests/front_end/platform/dom-extension.js
+++ b/third_party/blink/renderer/devtools/tests/front_end/platform/dom-extension.ts
@@ -5,6 +5,14 @@
 const { assert } = chai;
 import '../../../front_end/dom_extension/DOMExtension.js';
 
+declare global {
+    function createElementWithClass(tagName: string, className?: string, content?: string): HTMLElement;
+
+    interface HTMLElement {
+        traverseNextNode(node: HTMLElement): HTMLElement;
+        createChild(tagName: string, className?: string, content?: string): HTMLElement;
+    }
+}
 
 function createSlot(parent, name) {
     const slot = parent.createChild('slot');
@@ -224,4 +232,4 @@
         assert.equal(node.nodeValue, 'component2 light dom text');
         assert.equal(node.nodeName, '#text');
     });
-});
\ No newline at end of file
+});
diff --git a/third_party/blink/renderer/devtools/tests/front_end/platform/utilities.ts b/third_party/blink/renderer/devtools/tests/front_end/platform/utilities.ts
index e7f68e4..5f4e307 100644
--- a/third_party/blink/renderer/devtools/tests/front_end/platform/utilities.ts
+++ b/third_party/blink/renderer/devtools/tests/front_end/platform/utilities.ts
@@ -15,7 +15,6 @@
     upperBound(value: T, comparator?: (a: T, b: T) => number): number;
     lowerBound(value: T, comparator?: (a: T, b: T) => number): number;
     binaryIndexOf(value: T, comparator: (a: T, b: T) => number): number;
-    qselect(idx: number): number;
     sortRange(comparator: (a: T, b: T) => number, leftBound: number, rightBound: number, sortWindowLeft: number, sortWindowRight: number): T[];
   }
 
@@ -162,28 +161,6 @@
     }
   });
 
-  it('q selects', () => {
-    let testArrays =
-        [[], [0], [0, 0, 0, 0, 0, 0, 0, 0], [4, 3, 2, 1], [1, 2, 3, 4, 5], [-1, 3, 2, 7, 7, 7, 10, 12, 3, 4, -1, 2]];
-
-    function testArray(array: number[]) {
-      function compare(a: number, b: number) {
-        return a - b;
-      }
-      const sorted = array.slice(0).sort(compare);
-      const reference = {min: sorted[0], median: sorted[Math.floor(sorted.length / 2)], max: sorted[sorted.length - 1]};
-      const actual = {
-        min: array.slice(0).qselect(0),
-        median: array.slice(0).qselect(Math.floor(array.length / 2)),
-        max: array.slice(0).qselect(array.length - 1)
-      };
-
-      assert.deepStrictEqual(reference, actual);
-    }
-    for (let i = 0, l = testArrays.length; i < l; ++i)
-      testArray(testArrays[i]);
-  });
-
   it('sorts ranges', () => {
     const testArrays = [[], [1], [2, 1], [6, 4, 2, 7, 10, 15, 1], [10, 44, 3, 6, 56, 66, 10, 55, 32, 56, 2, 5]];
 
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_database.cc b/third_party/blink/renderer/modules/indexeddb/idb_database.cc
index 6551d98..ba4706eb 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_database.cc
+++ b/third_party/blink/renderer/modules/indexeddb/idb_database.cc
@@ -37,6 +37,7 @@
 #include "third_party/blink/renderer/bindings/modules/v8/v8_idb_observer_callback.h"
 #include "third_party/blink/renderer/core/dom/events/event_queue.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/modules/indexed_db_names.h"
 #include "third_party/blink/renderer/modules/indexeddb/idb_any.h"
 #include "third_party/blink/renderer/modules/indexeddb/idb_event_dispatcher.h"
 #include "third_party/blink/renderer/modules/indexeddb/idb_index.h"
@@ -433,9 +434,9 @@
       mojom::IDBTransactionDurability::Default;
   if (options) {
     DCHECK(RuntimeEnabledFeatures::IDBRelaxedDurabilityEnabled());
-    if (options->durability() == "relaxed") {
+    if (options->durability() == indexed_db_names::kRelaxed) {
       durability = mojom::IDBTransactionDurability::Relaxed;
-    } else if (options->durability() == "strict") {
+    } else if (options->durability() == indexed_db_names::kStrict) {
       durability = mojom::IDBTransactionDurability::Strict;
     }
   }
@@ -446,7 +447,7 @@
 
   return IDBTransaction::CreateNonVersionChange(
       script_state, std::move(transaction_backend), transaction_id, scope, mode,
-      this);
+      durability, this);
 }
 
 void IDBDatabase::ForceClose() {
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_request_test.cc b/third_party/blink/renderer/modules/indexeddb/idb_request_test.cc
index 4ec6a3ad..9c8d28d 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_request_test.cc
+++ b/third_party/blink/renderer/modules/indexeddb/idb_request_test.cc
@@ -197,7 +197,8 @@
     HashSet<String> transaction_scope = {"store"};
     transaction_ = IDBTransaction::CreateNonVersionChange(
         scope.GetScriptState(), std::move(transaction_backend), kTransactionId,
-        transaction_scope, mojom::IDBTransactionMode::ReadOnly, db_.Get());
+        transaction_scope, mojom::IDBTransactionMode::ReadOnly,
+        mojom::IDBTransactionDurability::Relaxed, db_.Get());
 
     IDBKeyPath store_key_path("primaryKey");
     scoped_refptr<IDBObjectStoreMetadata> store_metadata = base::AdoptRef(
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_transaction.cc b/third_party/blink/renderer/modules/indexeddb/idb_transaction.cc
index 7106e79..b1b2ec1 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_transaction.cc
+++ b/third_party/blink/renderer/modules/indexeddb/idb_transaction.cc
@@ -52,12 +52,14 @@
     int64_t id,
     const HashSet<String>& scope,
     mojom::IDBTransactionMode mode,
+    mojom::IDBTransactionDurability durability,
     IDBDatabase* db) {
   DCHECK_NE(mode, mojom::IDBTransactionMode::VersionChange);
   DCHECK(!scope.IsEmpty()) << "Non-version transactions should operate on a "
                               "well-defined set of stores";
-  return MakeGarbageCollected<IDBTransaction>(
-      script_state, std::move(transaction_backend), id, scope, mode, db);
+  return MakeGarbageCollected<IDBTransaction>(script_state,
+                                              std::move(transaction_backend),
+                                              id, scope, mode, durability, db);
 }
 
 IDBTransaction* IDBTransaction::CreateVersionChange(
@@ -78,12 +80,14 @@
     int64_t id,
     const HashSet<String>& scope,
     mojom::IDBTransactionMode mode,
+    mojom::IDBTransactionDurability durability,
     IDBDatabase* db)
     : ContextLifecycleObserver(ExecutionContext::From(script_state)),
       transaction_backend_(std::move(transaction_backend)),
       id_(id),
       database_(db),
       mode_(mode),
+      durability_(durability),
       scope_(scope),
       event_queue_(
           MakeGarbageCollected<EventQueue>(ExecutionContext::From(script_state),
@@ -122,6 +126,7 @@
       database_(db),
       open_db_request_(open_db_request),
       mode_(mojom::IDBTransactionMode::VersionChange),
+      durability_(mojom::IDBTransactionDurability::Default),
       state_(kInactive),
       old_database_metadata_(old_metadata),
       event_queue_(
@@ -495,6 +500,21 @@
   return indexed_db_names::kReadonly;
 }
 
+const String& IDBTransaction::durability() const {
+  switch (durability_) {
+    case mojom::IDBTransactionDurability::Default:
+      return indexed_db_names::kDefault;
+
+    case mojom::IDBTransactionDurability::Strict:
+      return indexed_db_names::kStrict;
+
+    case mojom::IDBTransactionDurability::Relaxed:
+      return indexed_db_names::kRelaxed;
+  }
+
+  NOTREACHED();
+}
+
 DOMStringList* IDBTransaction::objectStoreNames() const {
   if (IsVersionChange())
     return database_->objectStoreNames();
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_transaction.h b/third_party/blink/renderer/modules/indexeddb/idb_transaction.h
index 913cb29..11fd9efb 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_transaction.h
+++ b/third_party/blink/renderer/modules/indexeddb/idb_transaction.h
@@ -75,6 +75,7 @@
       int64_t transaction_id,
       const HashSet<String>& scope,
       mojom::IDBTransactionMode,
+      mojom::IDBTransactionDurability,
       IDBDatabase* database);
   static IDBTransaction* CreateVersionChange(
       ExecutionContext*,
@@ -90,6 +91,7 @@
                  int64_t,
                  const HashSet<String>& scope,
                  mojom::IDBTransactionMode,
+                 mojom::IDBTransactionDurability,
                  IDBDatabase*);
   // For upgrade transactions.
   IDBTransaction(ExecutionContext*,
@@ -122,6 +124,7 @@
 
   // Implement the IDBTransaction IDL
   const String& mode() const;
+  const String& durability() const;
   DOMStringList* objectStoreNames() const;
   IDBDatabase* db() const { return database_.Get(); }
   DOMException* error() const { return error_; }
@@ -213,6 +216,7 @@
   Member<IDBDatabase> database_;
   Member<IDBOpenDBRequest> open_db_request_;
   const mojom::IDBTransactionMode mode_;
+  const mojom::IDBTransactionDurability durability_;
 
   // The names of the object stores that make up this transaction's scope.
   //
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_transaction.idl b/third_party/blink/renderer/modules/indexeddb/idb_transaction.idl
index 5e68ee6..2956e88 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_transaction.idl
+++ b/third_party/blink/renderer/modules/indexeddb/idb_transaction.idl
@@ -42,6 +42,7 @@
     // Properties
     readonly attribute DOMStringList objectStoreNames;
     readonly attribute IDBTransactionMode mode;
+    [RuntimeEnabled=IDBRelaxedDurability] readonly attribute IDBTransactionDurability durability;
     [SameObject] readonly attribute IDBDatabase db;
     readonly attribute DOMException error;
 
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_transaction_test.cc b/third_party/blink/renderer/modules/indexeddb/idb_transaction_test.cc
index a599928..f71d72e 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_transaction_test.cc
+++ b/third_party/blink/renderer/modules/indexeddb/idb_transaction_test.cc
@@ -98,7 +98,8 @@
     HashSet<String> transaction_scope = {"store"};
     transaction_ = IDBTransaction::CreateNonVersionChange(
         scope.GetScriptState(), std::move(transaction_backend), kTransactionId,
-        transaction_scope, mojom::IDBTransactionMode::ReadOnly, db_.Get());
+        transaction_scope, mojom::IDBTransactionMode::ReadOnly,
+        mojom::IDBTransactionDurability::Relaxed, db_.Get());
 
     IDBKeyPath store_key_path("primaryKey");
     scoped_refptr<IDBObjectStoreMetadata> store_metadata = base::AdoptRef(
diff --git a/third_party/blink/renderer/modules/indexeddb/indexed_db_names.json5 b/third_party/blink/renderer/modules/indexeddb/indexed_db_names.json5
index edab532..3aa16b760 100644
--- a/third_party/blink/renderer/modules/indexeddb/indexed_db_names.json5
+++ b/third_party/blink/renderer/modules/indexeddb/indexed_db_names.json5
@@ -32,5 +32,11 @@
     "put",
     "delete",
     "clear",
+
+    // The IDBTransactionDurability enum is still being standardized.
+    // https://chromestatus.com/feature/5730701489995776
+    "default",
+    "relaxed",
+    "strict",
   ],
 }
diff --git a/third_party/blink/renderer/modules/push_messaging/push_messaging_client.cc b/third_party/blink/renderer/modules/push_messaging/push_messaging_client.cc
index a5a32209..ecd69c6 100644
--- a/third_party/blink/renderer/modules/push_messaging/push_messaging_client.cc
+++ b/third_party/blink/renderer/modules/push_messaging/push_messaging_client.cc
@@ -7,7 +7,7 @@
 #include <string>
 #include <utility>
 
-#include "third_party/blink/public/mojom/frame/document_interface_broker.mojom-blink.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
 #include "third_party/blink/public/mojom/push_messaging/push_messaging_status.mojom-blink.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/web/web_local_frame.h"
@@ -43,7 +43,7 @@
 
 mojom::blink::PushMessaging* PushMessagingClient::GetPushMessagingRemote() {
   if (!push_messaging_manager_) {
-    GetSupplementable()->GetDocumentInterfaceBroker().GetPushMessaging(
+    GetSupplementable()->GetBrowserInterfaceBroker().GetInterface(
         push_messaging_manager_.BindNewPipeAndPassReceiver(
             GetSupplementable()->GetTaskRunner(TaskType::kMiscPlatformAPI)));
   }
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-blink-features=LayoutNG b/third_party/blink/web_tests/FlagExpectations/disable-blink-features=LayoutNG
index 04c5a4a5..5b5fbbb7 100644
--- a/third_party/blink/web_tests/FlagExpectations/disable-blink-features=LayoutNG
+++ b/third_party/blink/web_tests/FlagExpectations/disable-blink-features=LayoutNG
@@ -363,3 +363,7 @@
 Bug(none) virtual/prefer_compositing_to_lcd_text/compositing/overflow/rotate-then-clip-effect-interleave.html [ Failure ]
 Bug(none) virtual/prefer_compositing_to_lcd_text/compositing/overflow/rotate-then-clip-z-order-interleave.html [ Failure ]
 Bug(none) virtual/prefer_compositing_to_lcd_text/compositing/overflow/rotate-then-clip.html [ Failure ]
+
+# display-locking
+crbug.com/1007506 wpt_internal/display-lock/rendersubtree/sizing/large-content-size-in-overflow-auto.html [ Failure ]
+crbug.com/1007506 wpt_internal/display-lock/rendersubtree/sizing/overflow-auto-with-overflow.html [ Failure ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 9c539f21..ed95ce6 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -3226,6 +3226,16 @@
 crbug.com/618969 external/wpt/css/css-grid/subgrid/ [ Skip ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 [ Linux ] external/wpt/css/css-text/white-space/textarea-pre-wrap-013.html [ Failure ]
+crbug.com/626703 [ Mac ] external/wpt/css/css-text/white-space/textarea-pre-wrap-013.html [ Failure ]
+crbug.com/626703 [ Win ] external/wpt/css/css-text/white-space/textarea-pre-wrap-013.html [ Failure ]
+crbug.com/626703 [ Mac ] external/wpt/css/css-text/white-space/pre-wrap-018.html [ Failure ]
+crbug.com/626703 [ Linux ] external/wpt/css/css-text/white-space/pre-wrap-019.html [ Failure ]
+crbug.com/626703 [ Mac ] external/wpt/css/css-text/white-space/pre-wrap-019.html [ Failure ]
+crbug.com/626703 [ Win ] external/wpt/css/css-text/white-space/pre-wrap-019.html [ Failure ]
+crbug.com/626703 [ Linux ] external/wpt/css/css-text/white-space/textarea-pre-wrap-012.html [ Failure ]
+crbug.com/626703 [ Mac ] external/wpt/css/css-text/white-space/textarea-pre-wrap-012.html [ Failure ]
+crbug.com/626703 [ Win ] external/wpt/css/css-text/white-space/textarea-pre-wrap-012.html [ Failure ]
 crbug.com/626703 [ Win7 ] external/wpt/pointerevents/pointerevent_touch-action-pan-y-css_touch.html [ Timeout ]
 crbug.com/626703 [ Win10 ] external/wpt/payment-request/payment-request-hasenrolledinstrument-method.tentative.https.html [ Failure Timeout ]
 crbug.com/626703 [ Linux ] external/wpt/css/motion/offset-path-ray-contain-003.html [ Failure ]
diff --git a/third_party/blink/web_tests/animations/interpolation/resources/interpolation-test.js b/third_party/blink/web_tests/animations/interpolation/resources/interpolation-test.js
index 6fd90a5..43227df5 100644
--- a/third_party/blink/web_tests/animations/interpolation/resources/interpolation-test.js
+++ b/third_party/blink/web_tests/animations/interpolation/resources/interpolation-test.js
@@ -158,6 +158,8 @@
         }
         if (property === 'offset')
           property = 'cssOffset';
+        else if (property === 'float')
+          property = 'cssFloat';
       }
       var keyframes = [];
       if (!isNeutralKeyframe(from)) {
diff --git a/third_party/blink/web_tests/animations/interpolation/scale-interpolation.html b/third_party/blink/web_tests/animations/interpolation/scale-interpolation.html
deleted file mode 100644
index e64d573..0000000
--- a/third_party/blink/web_tests/animations/interpolation/scale-interpolation.html
+++ /dev/null
@@ -1,205 +0,0 @@
-<!DOCTYPE html>
-<meta charset="UTF-8">
-<style>
-.parent {
-  scale: 0.5 1 2
-}
-.target {
-  width: 10px;
-  height: 10px;
-  background-color: black;
-  scale: 1.1 1;
-}
-.expected {
-  background-color: green;
-}
-</style>
-<template id="target-template">
-<div class="parent">
-    <div class="target"></div>
-</div>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-assertInterpolation({
-  property: 'scale',
-  from: 'none',
-  to: '1.5 1',
-}, [
-  {at: -1, is: '0.5 1'},
-  {at: 0, is: 'none'},
-  {at: 0.25, is: '1.125 1'},
-  {at: 0.75, is: '1.375 1'},
-  {at: 1, is: '1.5 1'},
-  {at: 2, is: '2 1'},
-]);
-
-assertInterpolation({
-  property: 'scale',
-  from: neutralKeyframe,
-  to: '1.5 1',
-}, [
-  {at: -1, is: '0.7 1'},
-  {at: 0, is: '1.1 1'},
-  {at: 0.25, is: '1.2 1'},
-  {at: 0.75, is: '1.4 1'},
-  {at: 1, is: '1.5 1'},
-  {at: 2, is: '1.9 1'},
-]);
-
-assertInterpolation({
-  property: 'scale',
-  from: 'unset',
-  to: '1.5 1',
-}, [
-  {at: -1, is: '0.5 1'},
-  {at: 0, is: 'none'},
-  {at: 0.25, is: '1.125 1'},
-  {at: 0.75, is: '1.375 1'},
-  {at: 1, is: '1.5 1'},
-  {at: 2, is: '2 1'},
-]);
-
-assertInterpolation({
-  property: 'scale',
-  from: '-10 1',
-  to: '10 1',
-}, [
-  {at: -1, is: '-30 1'},
-  {at: 0, is: '-10 1'},
-  {at: 0.25, is: '-5 1'},
-  {at: 0.75, is: '5 1'},
-  {at: 1, is: '10 1'},
-  {at: 2, is: '30 1'},
-]);
-
-assertInterpolation({
-  property: 'scale',
-  from: '-10 5',
-  to: '10 -5',
-}, [
-  {at: -1, is: '-30 15'},
-  {at: 0, is: '-10 5'},
-  {at: 0.25, is: '-5 2.5'},
-  {at: 0.75, is: '5 -2.5'},
-  {at: 1, is: '10 -5'},
-  {at: 2, is: '30 -15'},
-]);
-
-assertInterpolation({
-  property: 'scale',
-  from: '-10 5 1',
-  to: '10 -5 0',
-}, [
-  {at: -1, is: '-30 15 2'},
-  {at: 0, is: '-10 5 1'},
-  {at: 0.25, is: '-5 2.5 0.75'},
-  {at: 0.75, is: '5 -2.5 0.25'},
-  {at: 1, is: '10 -5 0'},
-  {at: 2, is: '30 -15 -1'},
-]);
-
-assertInterpolation({
-  property: 'scale',
-  from: '1',
-  to: '10 -5 0',
-}, [
-  {at: -1, is: '-8 7 2'},
-  {at: 0, is: '1'},
-  {at: 0.25, is: '3.25 -0.5 0.75'},
-  {at: 0.75, is: '7.75 -3.5 0.25'},
-  {at: 1, is: '10 -5 0'},
-  {at: 2, is: '19 -11 -1'},
-]);
-
-assertInterpolation({
-  property: 'scale',
-  from: '-10 5 1',
-  to: '1',
-}, [
-  {at: -1, is: '-21 9'},
-  {at: 0, is: '-10 5'},
-  {at: 0.25, is: '-7.25 4'},
-  {at: 0.75, is: '-1.75 2'},
-  {at: 1, is: '1'},
-  {at: 2, is: '12 -3'},
-]);
-
-assertInterpolation({
-  property: 'scale',
-  from: 'inherit',
-  to: '2 0.5 1',
-}, [
-  {at: -1, is: '-1 1.5 3'},
-  {at: 0, is: '0.5 1 2'},
-  {at: 0.25, is: '0.875 0.875 1.75'},
-  {at: 0.75, is: '1.625 0.625 1.25'},
-  {at: 1, is: '2 0.5 1'},
-  {at: 2, is: '3.5 0 0'},
-]);
-
-assertInterpolation({
-  property: 'scale',
-  from: '2 0.5 1',
-  to: 'inherit',
-}, [
-  {at: -1, is: '3.5 0 0'},
-  {at: 0, is: '2 0.5 1'},
-  {at: 0.25, is: '1.625 0.625 1.25'},
-  {at: 0.75, is: '0.875 0.875 1.75'},
-  {at: 1, is: '0.5 1 2'},
-  {at: 2, is: '-1 1.5 3'},
-]);
-
-assertInterpolation({
-  property: 'scale',
-  from: 'initial',
-  to: '2 0.5 1',
-}, [
-  {at: -1, is: '0 1.5'},
-  {at: 0, is: 'none'},
-  {at: 0.25, is: '1.25 0.875'},
-  {at: 0.75, is: '1.75 0.625'},
-  {at: 1, is: '2 0.5'},
-  {at: 2, is: '3 0'},
-]);
-
-assertInterpolation({
-  property: 'scale',
-  from: '2 0.5 1',
-  to: 'initial',
-}, [
-  {at: -1, is: '3 0'},
-  {at: 0, is: '2 0.5 1'},
-  {at: 0.25, is: '1.75 0.6251'},
-  {at: 0.75, is: '1.25 0.875'},
-  {at: 1, is: 'none'},
-  {at: 2, is: '0 1.5'},
-]);
-
-assertInterpolation({
-  property: 'scale',
-  from: 'initial',
-  to: 'inherit',
-}, [
-  {at: -1, is: '1.5 1 0'},
-  {at: 0, is: 'none'},
-  {at: 0.25, is: '0.875 1 1.25'},
-  {at: 0.75, is: '0.625 1 1.75'},
-  {at: 1, is: '0.5 1 2'},
-  {at: 2, is: '0 1 3'},
-]);
-
-assertInterpolation({
-  property: 'scale',
-  from: 'inherit',
-  to: 'initial',
-}, [
-  {at: -1, is: '0 1 3'},
-  {at: 0, is: '0.5 1 2'},
-  {at: 0.25, is: '0.625 1 1.75'},
-  {at: 0.75, is: '0.875 1 1.25'},
-  {at: 1, is: 'none'},
-  {at: 2, is: '1.5 1 0'},
-]);
-</script>
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
index 72e56301..7fdbeae 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
@@ -74055,6 +74055,54 @@
      {}
     ]
    ],
+   "css/css-text/white-space/pre-wrap-017.html": [
+    [
+     "css/css-text/white-space/pre-wrap-017.html",
+     [
+      [
+       "/css/css-text/white-space/reference/pre-wrap-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-text/white-space/pre-wrap-018.html": [
+    [
+     "css/css-text/white-space/pre-wrap-018.html",
+     [
+      [
+       "/css/css-text/white-space/reference/pre-wrap-018-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-text/white-space/pre-wrap-019.html": [
+    [
+     "css/css-text/white-space/pre-wrap-019.html",
+     [
+      [
+       "/css/css-text/white-space/reference/pre-wrap-019-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-text/white-space/pre-wrap-020.html": [
+    [
+     "css/css-text/white-space/pre-wrap-020.html",
+     [
+      [
+       "/css/css-text/white-space/reference/pre-wrap-020-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-text/white-space/pre-wrap-float-001.html": [
     [
      "css/css-text/white-space/pre-wrap-float-001.html",
@@ -74540,7 +74588,7 @@
      "css/css-text/white-space/textarea-pre-wrap-012.html",
      [
       [
-       "/css/css-text/white-space/reference/textarea-pre-wrap-001-ref.html",
+       "/css/css-text/white-space/reference/pre-wrap-012-ref.html",
        "=="
       ]
      ],
@@ -74552,7 +74600,7 @@
      "css/css-text/white-space/textarea-pre-wrap-013.html",
      [
       [
-       "/css/css-text/white-space/reference/textarea-pre-wrap-001-ref.html",
+       "/css/css-text/white-space/reference/pre-wrap-013-ref.html",
        "=="
       ]
      ],
@@ -74564,7 +74612,7 @@
      "css/css-text/white-space/textarea-pre-wrap-014.html",
      [
       [
-       "/css/css-text/white-space/reference/textarea-pre-wrap-001-ref.html",
+       "/css/css-text/white-space/reference/textarea-pre-wrap-014-ref.html",
        "=="
       ]
      ],
@@ -124090,6 +124138,24 @@
    "battery-status/OWNERS": [
     []
    ],
+   "battery-status/battery-allowed-by-feature-policy-attribute-redirect-on-load.https.sub-expected.txt": [
+    []
+   ],
+   "battery-status/battery-allowed-by-feature-policy.https.sub.html.headers": [
+    []
+   ],
+   "battery-status/battery-default-feature-policy.https.sub-expected.txt": [
+    []
+   ],
+   "battery-status/battery-disabled-by-feature-policy.https.sub-expected.txt": [
+    []
+   ],
+   "battery-status/battery-disabled-by-feature-policy.https.sub.html.headers": [
+    []
+   ],
+   "battery-status/battery-disallowed-in-cross-origin-iframe.https.sub-expected.txt": [
+    []
+   ],
    "battery-status/battery-discharging-manual.https-expected.txt": [
     []
    ],
@@ -142711,6 +142777,15 @@
    "css/css-text/white-space/reference/pre-wrap-014-ref.html": [
     []
    ],
+   "css/css-text/white-space/reference/pre-wrap-018-ref.html": [
+    []
+   ],
+   "css/css-text/white-space/reference/pre-wrap-019-ref.html": [
+    []
+   ],
+   "css/css-text/white-space/reference/pre-wrap-020-ref.html": [
+    []
+   ],
    "css/css-text/white-space/reference/pre-wrap-float-001-ref.html": [
     []
    ],
@@ -142732,6 +142807,9 @@
    "css/css-text/white-space/reference/textarea-pre-wrap-001-ref.html": [
     []
    ],
+   "css/css-text/white-space/reference/textarea-pre-wrap-014-ref.html": [
+    []
+   ],
    "css/css-text/white-space/reference/trailing-ideographic-space-001-ref.html": [
     []
    ],
@@ -152263,6 +152341,9 @@
    "feature-policy/resources/feature-policy-autoplay.html": [
     []
    ],
+   "feature-policy/resources/feature-policy-battery.html": [
+    []
+   ],
    "feature-policy/resources/feature-policy-generic-sensor.html": [
     []
    ],
@@ -161548,9 +161629,6 @@
    "interfaces/ambient-light.idl": [
     []
    ],
-   "interfaces/animation-worklet.idl": [
-    []
-   ],
    "interfaces/appmanifest.idl": [
     []
    ],
@@ -161587,6 +161665,9 @@
    "interfaces/csp-embedded-enforcement.idl": [
     []
    ],
+   "interfaces/css-animation-worklet.idl": [
+    []
+   ],
    "interfaces/css-animations.idl": [
     []
    ],
@@ -194093,9 +194174,45 @@
      }
     ]
    ],
-   "battery-status/battery-iframe.https.html": [
+   "battery-status/battery-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html": [
     [
-     "battery-status/battery-iframe.https.html",
+     "battery-status/battery-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html",
+     {}
+    ]
+   ],
+   "battery-status/battery-allowed-by-feature-policy-attribute.https.sub.html": [
+    [
+     "battery-status/battery-allowed-by-feature-policy-attribute.https.sub.html",
+     {}
+    ]
+   ],
+   "battery-status/battery-allowed-by-feature-policy.https.sub.html": [
+    [
+     "battery-status/battery-allowed-by-feature-policy.https.sub.html",
+     {}
+    ]
+   ],
+   "battery-status/battery-allowed-in-same-origin-iframe.https.html": [
+    [
+     "battery-status/battery-allowed-in-same-origin-iframe.https.html",
+     {}
+    ]
+   ],
+   "battery-status/battery-default-feature-policy.https.sub.html": [
+    [
+     "battery-status/battery-default-feature-policy.https.sub.html",
+     {}
+    ]
+   ],
+   "battery-status/battery-disabled-by-feature-policy.https.sub.html": [
+    [
+     "battery-status/battery-disabled-by-feature-policy.https.sub.html",
+     {}
+    ]
+   ],
+   "battery-status/battery-disallowed-in-cross-origin-iframe.https.sub.html": [
+    [
+     "battery-status/battery-disallowed-in-cross-origin-iframe.https.sub.html",
      {}
     ]
    ],
@@ -310093,7 +310210,9 @@
    "worklets/animation-worklet-referrer.https.html": [
     [
      "worklets/animation-worklet-referrer.https.html",
-     {}
+     {
+      "timeout": "long"
+     }
     ]
    ],
    "worklets/animation-worklet-service-worker-interception.https.html": [
@@ -310125,7 +310244,9 @@
    "worklets/audio-worklet-referrer.https.html": [
     [
      "worklets/audio-worklet-referrer.https.html",
-     {}
+     {
+      "timeout": "long"
+     }
     ]
    ],
    "worklets/audio-worklet-service-worker-interception.https.html": [
@@ -310163,7 +310284,9 @@
    "worklets/layout-worklet-referrer.https.html": [
     [
      "worklets/layout-worklet-referrer.https.html",
-     {}
+     {
+      "timeout": "long"
+     }
     ]
    ],
    "worklets/layout-worklet-service-worker-interception.https.html": [
@@ -310193,7 +310316,9 @@
    "worklets/paint-worklet-referrer.https.html": [
     [
      "worklets/paint-worklet-referrer.https.html",
-     {}
+     {
+      "timeout": "long"
+     }
     ]
    ],
    "worklets/paint-worklet-service-worker-interception.https.html": [
@@ -327587,7 +327712,7 @@
    "testharness"
   ],
   "animation-worklet/META.yml": [
-   "c6918965843779e02522af1abf48acda8d0a128b",
+   "7a53b4d76d2c41ece6d9acc86482f92a28173e03",
    "support"
   ],
   "animation-worklet/animate-multiple-effects-on-different-targets-via-main-thread.https.html": [
@@ -327623,7 +327748,7 @@
    "support"
   ],
   "animation-worklet/idlharness.any.js": [
-   "e821a2fee8a3ace54e8e7092ab17c490a0ded914",
+   "efd2fdeb98dc5093babd24c785145ace9fdc8757",
    "testharness"
   ],
   "animation-worklet/idlharness.any.worker-expected.txt": [
@@ -327939,17 +328064,69 @@
    "testharness"
   ],
   "battery-status/META.yml": [
-   "12a2f12c32e9c58912a209e369af59d6ceee3aa4",
+   "a069984ddb226b6f07cd5f1408e159634dfec7f4",
    "support"
   ],
   "battery-status/OWNERS": [
    "f34b5e22642d3034ed19768c2405a24227fe9cb0",
    "support"
   ],
+  "battery-status/battery-allowed-by-feature-policy-attribute-redirect-on-load.https.sub-expected.txt": [
+   "82fcc27853d595ec5563cbced99357838de45a86",
+   "support"
+  ],
+  "battery-status/battery-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html": [
+   "47a9cbac0fc4da3ec56e63896d62fa51feb512c6",
+   "testharness"
+  ],
+  "battery-status/battery-allowed-by-feature-policy-attribute.https.sub.html": [
+   "96bca54ec8e087ba98961c303e7f96c955963450",
+   "testharness"
+  ],
+  "battery-status/battery-allowed-by-feature-policy.https.sub.html": [
+   "5849af5750148f9af220e9781827fd3b10b32de1",
+   "testharness"
+  ],
+  "battery-status/battery-allowed-by-feature-policy.https.sub.html.headers": [
+   "03b98040cc4d2e5cd352584b69ffd09ca1cb308c",
+   "support"
+  ],
+  "battery-status/battery-allowed-in-same-origin-iframe.https.html": [
+   "c0d684f26d7d272cdff5e9545ffbd4f2c354c4a3",
+   "testharness"
+  ],
   "battery-status/battery-charging-manual.https.html": [
    "9ff7421638a85e077532eecbeab417d0fe5b0314",
    "manual"
   ],
+  "battery-status/battery-default-feature-policy.https.sub-expected.txt": [
+   "54b00b9d60da6c9073324b84545d30018d2c6da1",
+   "support"
+  ],
+  "battery-status/battery-default-feature-policy.https.sub.html": [
+   "5486a453e4e99c26e50b6de99a27a48c78f896de",
+   "testharness"
+  ],
+  "battery-status/battery-disabled-by-feature-policy.https.sub-expected.txt": [
+   "8cf8e32cc55110598c75ddc1f8a355907c6782e5",
+   "support"
+  ],
+  "battery-status/battery-disabled-by-feature-policy.https.sub.html": [
+   "515c64fe490fbf11fd516f932af429215e655ea5",
+   "testharness"
+  ],
+  "battery-status/battery-disabled-by-feature-policy.https.sub.html.headers": [
+   "09a5ae84a123aac7591b20f78ffeea1cbd279a7c",
+   "support"
+  ],
+  "battery-status/battery-disallowed-in-cross-origin-iframe.https.sub-expected.txt": [
+   "0d7a2cc743f2b4843586adee3a3e97829398ca07",
+   "support"
+  ],
+  "battery-status/battery-disallowed-in-cross-origin-iframe.https.sub.html": [
+   "8b48626b5511414e2e8d8ffa93f63779cd37b3cb",
+   "testharness"
+  ],
   "battery-status/battery-discharging-manual.https-expected.txt": [
    "6057a79e9994ac6fa910a29bc66f035fc5f5e676",
    "support"
@@ -327966,10 +328143,6 @@
    "13eb1058adbc72b761513c71783a11b7ff83d5d7",
    "support"
   ],
-  "battery-status/battery-iframe.https.html": [
-   "1f95b4ecb32037ef818cc2a01d5f4fecd35cb444",
-   "testharness"
-  ],
   "battery-status/battery-insecure-context-expected.txt": [
    "6594edf423b5a0753f30718ab4d9801cbb0723a4",
    "support"
@@ -355371,11 +355544,11 @@
    "reftest"
   ],
   "css/css-color/opacity-overlapping-letters-ref.html": [
-   "913aa7bc3c9f08ca0d346d473fefaa1b1a8dd9f1",
+   "bab1f80f685f9e52ea74b8b98f5153dcd9516624",
    "support"
   ],
   "css/css-color/opacity-overlapping-letters.html": [
-   "34b444e26c97a5db7488716d9eed3e3675e3271f",
+   "65ab3742de39205341e04b18001deea3f7be192d",
    "reftest"
   ],
   "css/css-color/parsing/color-computed.html": [
@@ -390895,15 +391068,15 @@
    "reftest"
   ],
   "css/css-text/white-space/pre-wrap-012.html": [
-   "f0eb17c4f975d49047faa0547ecee6ecbb675d4a",
+   "e844d97860450c1e324745e17d4fb2fd099a8a82",
    "reftest"
   ],
   "css/css-text/white-space/pre-wrap-013.html": [
-   "29333f5946e196ed2f0d551b4aceead81f9c2ba1",
+   "23c4b536cde73a22c32a19637312337c47952c0a",
    "reftest"
   ],
   "css/css-text/white-space/pre-wrap-014.html": [
-   "ac867771d58b9b3346a7338cc17e1d764794c424",
+   "26423c192842516fd491f2ec89e3bf0bad9c7828",
    "reftest"
   ],
   "css/css-text/white-space/pre-wrap-015.html": [
@@ -390914,6 +391087,22 @@
    "0590f669e918a8782142784080179b1f37cbaf45",
    "reftest"
   ],
+  "css/css-text/white-space/pre-wrap-017.html": [
+   "541e1abe575b8af2c359cdf36fcfa2fb672bfb09",
+   "reftest"
+  ],
+  "css/css-text/white-space/pre-wrap-018.html": [
+   "f911b2dcdeac18fb6c5e1f531985a3d144077899",
+   "reftest"
+  ],
+  "css/css-text/white-space/pre-wrap-019.html": [
+   "58dae9f50070e7820c09e901f197700e4226e2e5",
+   "reftest"
+  ],
+  "css/css-text/white-space/pre-wrap-020.html": [
+   "ec3e8621159a28103527809c582e1ac0ea365bcc",
+   "reftest"
+  ],
   "css/css-text/white-space/pre-wrap-float-001.html": [
    "af29b0505e0eefbab09b011798c0dd6136598cca",
    "reftest"
@@ -391038,6 +391227,18 @@
    "87d51f6067d5718b03f74df1532058f765ab2b76",
    "support"
   ],
+  "css/css-text/white-space/reference/pre-wrap-018-ref.html": [
+   "a87649432fea65476e82dd09d212cbc35417f766",
+   "support"
+  ],
+  "css/css-text/white-space/reference/pre-wrap-019-ref.html": [
+   "e3be478a351dc3ea98cb40010c4627d05ebce5fd",
+   "support"
+  ],
+  "css/css-text/white-space/reference/pre-wrap-020-ref.html": [
+   "2ef5e7f408e3451f22530d24cfc9e2f188a14213",
+   "support"
+  ],
   "css/css-text/white-space/reference/pre-wrap-float-001-ref.html": [
    "e72b3c94ea454eceee9e934ff7929d18da2fc441",
    "support"
@@ -391066,6 +391267,10 @@
    "31070ea92815e4d3a3ece48ed69da03de02f671e",
    "support"
   ],
+  "css/css-text/white-space/reference/textarea-pre-wrap-014-ref.html": [
+   "99a38bf88b21722910494852fa5b2254c5f1d13f",
+   "support"
+  ],
   "css/css-text/white-space/reference/trailing-ideographic-space-001-ref.html": [
    "aa97e2bc8347a12b03eae593860f6403da311cd8",
    "support"
@@ -391175,7 +391380,7 @@
    "support"
   ],
   "css/css-text/white-space/reference/white-space-intrinsic-size-004-ref.html": [
-   "0c31cb4299673421f45572c3bec54ce474e048bb",
+   "93b8b913cc9f4325a676af9c04640979a0eda604",
    "support"
   ],
   "css/css-text/white-space/reference/white-space-pre-wrap-trailing-spaces-001-ref.html": [
@@ -391183,7 +391388,7 @@
    "support"
   ],
   "css/css-text/white-space/reference/white-space-pre-wrap-trailing-spaces-002-ref.html": [
-   "5f94d076e840080f8cc855e013039ef16f1d993c",
+   "0971868116fcd7c5fed8801de1caf71aa8ad3ec3",
    "support"
   ],
   "css/css-text/white-space/reference/white-space-pre-wrap-trailing-spaces-003-ref.html": [
@@ -391363,15 +391568,15 @@
    "reftest"
   ],
   "css/css-text/white-space/textarea-pre-wrap-012.html": [
-   "04e07d6bcc815fb640e843a36420bab6b3bef9bc",
+   "5ca12811280592d9253668787de454408113e7df",
    "reftest"
   ],
   "css/css-text/white-space/textarea-pre-wrap-013.html": [
-   "853d2c33d140d3e8b973ba01b40d004049a71b16",
+   "e3d5c3253d6268864e1e09bbedef70e782a85811",
    "reftest"
   ],
   "css/css-text/white-space/textarea-pre-wrap-014.html": [
-   "b6d62ce2bff35103f46a81918e622a938d0c9491",
+   "f2812af2fbf4cee10b7fd8f292d5d5219fe859f4",
    "reftest"
   ],
   "css/css-text/white-space/trailing-ideographic-space-001.html": [
@@ -391503,27 +391708,27 @@
    "reftest"
   ],
   "css/css-text/white-space/white-space-intrinsic-size-004.html": [
-   "cc2d73992d54b9340b4eb7aad4ec7d9b29793f08",
+   "a5be242e23a7d00785f520aa52adf794a19aaed3",
    "reftest"
   ],
   "css/css-text/white-space/white-space-pre-wrap-trailing-spaces-001.html": [
-   "ca6f65e613d035cb3f79abaa0e527643126cadce",
+   "82fbfbc976cd02629d1180e4470170a533aa27e9",
    "reftest"
   ],
   "css/css-text/white-space/white-space-pre-wrap-trailing-spaces-002.html": [
-   "76ca5ef77dbb5ab32c9da92c7a2c4f181a1f98ff",
+   "f7e0f21f45761400e5f7b317de521added098b73",
    "reftest"
   ],
   "css/css-text/white-space/white-space-pre-wrap-trailing-spaces-003.html": [
-   "15e47a7adba3d4fc5534eab8811e3c91518aa771",
+   "def9bcaee32b6c9327e8785df3901549f17c8759",
    "reftest"
   ],
   "css/css-text/white-space/white-space-pre-wrap-trailing-spaces-004.html": [
-   "aa048b512e940511030631f2c379aaa995e6b868",
+   "d271057c43cc7b232c00fa0f3426e2ef5a7666f3",
    "reftest"
   ],
   "css/css-text/white-space/white-space-pre-wrap-trailing-spaces-005.html": [
-   "62ecb84757e61b6866213b71503c4dd6ae204410",
+   "e10b4e19033ea81edd8aefb8131db8a8b49828d3",
    "reftest"
   ],
   "css/css-text/white-space/white-space-wrap-after-nowrap-001.html": [
@@ -420455,7 +420660,7 @@
    "testharness"
   ],
   "dom/idlharness.window_exclude=Node-expected.txt": [
-   "42cd0e0da09ef90ea71e2901ee238f18aca9e6d3",
+   "6609f69a7adf6c676a4802fbd0397123cafe8b6d",
    "support"
   ],
   "dom/interface-objects.html": [
@@ -426442,6 +426647,10 @@
    "79f8eefb9d619c3f54524fd53649cf03d66713b3",
    "support"
   ],
+  "feature-policy/resources/feature-policy-battery.html": [
+   "dff4b3290d66c4c804267ecfe2fb9717a6449cff",
+   "support"
+  ],
   "feature-policy/resources/feature-policy-generic-sensor.html": [
    "59652e2e7ae0056a6cc4be7f004b6d0151fb9d44",
    "support"
@@ -443275,11 +443484,11 @@
    "reftest"
   ],
   "html/semantics/embedded-content/the-img-element/img.complete-expected.txt": [
-   "18aa059551492cd8f861db7c89c559b5702c9dbc",
+   "d245e4d8a5f2891115ac86188a2c3dd0718db63a",
    "support"
   ],
   "html/semantics/embedded-content/the-img-element/img.complete.html": [
-   "dcacf43db2ddf8c2a179d67326a18f78b03ff0a9",
+   "d8d5a84eb7998044fb24847cc0ac5a1185b82bb6",
    "testharness"
   ],
   "html/semantics/embedded-content/the-img-element/invalid-src.html": [
@@ -451426,10 +451635,6 @@
    "ce335161a2570fa9f2ab8051c75c0ab71aa2df76",
    "support"
   ],
-  "interfaces/animation-worklet.idl": [
-   "02deca73a3a3378c9906776d547a37b7c31e0fb5",
-   "support"
-  ],
   "interfaces/appmanifest.idl": [
    "4a6425829f23da3cd1f78f74ff52a18635f7af7c",
    "support"
@@ -451478,6 +451683,10 @@
    "167bc96eb53c5d1e67f34b1cc39622a30d30a7f8",
    "support"
   ],
+  "interfaces/css-animation-worklet.idl": [
+   "4aca84e5a024efdc2d3e674540bf2091758551c9",
+   "support"
+  ],
   "interfaces/css-animations.idl": [
    "f87015f6a87fccc0accab30920cd8371eee99e63",
    "support"
@@ -451547,7 +451756,7 @@
    "support"
   ],
   "interfaces/dom.idl": [
-   "03a0201b16fed569429c6cfc709063ed31681422",
+   "d1557a676ef0f7c458c8654c59ec713a42833d0a",
    "support"
   ],
   "interfaces/element-timing.idl": [
@@ -451807,7 +452016,7 @@
    "support"
   ],
   "interfaces/scroll-animations.idl": [
-   "f2560d9ffc88eaadf961b055480ed605610f72bf",
+   "8fd67a7af7bbdaa8129fb03cf395eb6e411dbcd4",
    "support"
   ],
   "interfaces/secure-contexts.idl": [
@@ -494799,7 +495008,7 @@
    "testharness"
   ],
   "web-animations/interfaces/Animatable/getAnimations-expected.txt": [
-   "8450824bb96bd57f7d04601203b1f19488584fc4",
+   "35c5a8255743e118091c928ad2210c82c333231b",
    "support"
   ],
   "web-animations/interfaces/Animatable/getAnimations.html": [
@@ -505963,7 +506172,7 @@
    "support"
   ],
   "worklets/animation-worklet-referrer.https.html": [
-   "494e06a8472795016e2ee346397d7c227477809c",
+   "49933dea47d554b0d9dbdeb8305c522c076c9c81",
    "testharness"
   ],
   "worklets/animation-worklet-service-worker-interception.https.html": [
@@ -505991,7 +506200,7 @@
    "support"
   ],
   "worklets/audio-worklet-referrer.https.html": [
-   "f258cd5a452d57002d041211cb44ee6f27f0b3aa",
+   "61cb63d75ca647a7385200573c3a6b5aca27ae34",
    "testharness"
   ],
   "worklets/audio-worklet-service-worker-interception.https.html": [
@@ -506023,7 +506232,7 @@
    "support"
   ],
   "worklets/layout-worklet-referrer.https.html": [
-   "cb383a935a2a6d154d804595e78275e289076a4c",
+   "dc7b84b350c5114624caf7afd87924d5c673763a",
    "testharness"
   ],
   "worklets/layout-worklet-service-worker-interception.https.html": [
@@ -506051,7 +506260,7 @@
    "support"
   ],
   "worklets/paint-worklet-referrer.https.html": [
-   "a4b5a6f498c2755d498fd22afc1ab7398fab56ec",
+   "8f3d82a1ddc62a482caf70dd6591cb7244bd7fe5",
    "testharness"
   ],
   "worklets/paint-worklet-service-worker-interception.https.html": [
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/transaction-relaxed-durability.tentative.any.js b/third_party/blink/web_tests/external/wpt/IndexedDB/transaction-relaxed-durability.tentative.any.js
index 2ba96ec..865c28c 100644
--- a/third_party/blink/web_tests/external/wpt/IndexedDB/transaction-relaxed-durability.tentative.any.js
+++ b/third_party/blink/web_tests/external/wpt/IndexedDB/transaction-relaxed-durability.tentative.any.js
@@ -3,18 +3,18 @@
 
 /**
  * This file contains the webplatform smoke tests for the optional
- * relaxedDurability parameter of the IndexedDB transaction API.
+ * durability parameter of the IndexedDB transaction API.
  *
  * @author enne@chromium.org
  */
 
 // Smoke test optional parameter on IndexedDB.transaction.
 let cases = [
-  undefined,
-  {},
-  {durability: "default"},
-  {durability: "relaxed"},
-  {durability: "strict"},
+  { options: undefined, expected: 'default' },
+  { options: {}, expected: 'default' },
+  { options: { durability: 'default'}, expected: 'default' },
+  { options: { durability: 'relaxed'}, expected: 'relaxed' },
+  { options: { durability: 'strict'}, expected: 'strict' },
 ];
 
 for (let i = 0; i < cases.length; ++i) {
@@ -22,11 +22,13 @@
     const db = await createDatabase(testCase, db => {
       createBooksStore(testCase, db);
     });
-    const txn = db.transaction(['books'], 'readwrite', cases[i]);
+    const txn = db.transaction(['books'], 'readwrite', cases[i].options);
     const objectStore = txn.objectStore('books');
     objectStore.put({isbn: 'one', title: 'title1'});
     await promiseForTransaction(testCase, txn);
 
+    assert_equals(txn.durability, cases[i].expected);
+
     const txn2 = db.transaction(['books'], 'readonly');
     const objectStore2 = txn2.objectStore('books');
     const getTitle1 = objectStore2.get('one');
@@ -38,3 +40,14 @@
     db.close();
   }, 'Committed data can be read back out: case ' + i);
 }
+
+promise_test(async testCase => {
+  const db = await createDatabase(testCase, db => {
+    createBooksStore(testCase, db);
+  });
+
+  assert_throws(new TypeError(), function() {
+      db.transaction(['books'], 'readwrite', { durability: 'invalid' });
+  });
+  db.close();
+}, 'Invalid durability option throws a TypeError');
diff --git a/third_party/blink/web_tests/external/wpt/animation-worklet/META.yml b/third_party/blink/web_tests/external/wpt/animation-worklet/META.yml
index c691896..7a53b4d7 100644
--- a/third_party/blink/web_tests/external/wpt/animation-worklet/META.yml
+++ b/third_party/blink/web_tests/external/wpt/animation-worklet/META.yml
@@ -1,4 +1,4 @@
-spec: https://wicg.github.io/animation-worklet/
+spec: https://drafts.css-houdini.org/css-animationworklet/
 suggested_reviewers:
   - flackr
   - majido
diff --git a/third_party/blink/web_tests/external/wpt/animation-worklet/idlharness.any.js b/third_party/blink/web_tests/external/wpt/animation-worklet/idlharness.any.js
index e821a2fee..efd2fdeb 100644
--- a/third_party/blink/web_tests/external/wpt/animation-worklet/idlharness.any.js
+++ b/third_party/blink/web_tests/external/wpt/animation-worklet/idlharness.any.js
@@ -6,7 +6,7 @@
 // https://wicg.github.io/animation-worklet/
 
 idl_test(
-  ['animation-worklet'],
+  ['css-animation-worklet'],
   ['worklets', 'web-animations', 'html', 'cssom', 'dom'],
   idl_array => {
     idl_array.add_objects({
diff --git a/third_party/blink/web_tests/external/wpt/battery-status/META.yml b/third_party/blink/web_tests/external/wpt/battery-status/META.yml
index 12a2f12c..a069984d 100644
--- a/third_party/blink/web_tests/external/wpt/battery-status/META.yml
+++ b/third_party/blink/web_tests/external/wpt/battery-status/META.yml
@@ -2,3 +2,4 @@
 suggested_reviewers:
   - anssiko
   - zqzhang
+  - Honry
diff --git a/third_party/blink/web_tests/external/wpt/battery-status/battery-allowed-by-feature-policy-attribute-redirect-on-load.https.sub-expected.txt b/third_party/blink/web_tests/external/wpt/battery-status/battery-allowed-by-feature-policy-attribute-redirect-on-load.https.sub-expected.txt
new file mode 100644
index 0000000..82fcc27
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/battery-status/battery-allowed-by-feature-policy-attribute-redirect-on-load.https.sub-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+PASS Feature-Policy allow="battery" allows same-origin relocation.
+FAIL Feature-Policy allow="battery" disallows cross-origin relocation. assert_false: navigator.getBattery() expected false got true
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/battery-status/battery-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html b/third_party/blink/web_tests/external/wpt/battery-status/battery-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html
new file mode 100644
index 0000000..47a9cbac
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/battery-status/battery-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<body>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/feature-policy/resources/featurepolicy.js></script>
+<script>
+'use strict';
+
+const relative_path = '/feature-policy/resources/feature-policy-battery.html';
+const base_src = '/feature-policy/resources/redirect-on-load.html#';
+const same_origin_src = base_src + relative_path;
+const cross_origin_src = base_src + 'https://{{domains[www]}}:{{ports[https][0]}}' +
+  relative_path;
+const header = 'Feature-Policy allow="battery"';
+
+async_test(t => {
+  test_feature_availability(
+      'navigator.getBattery()', t, same_origin_src,
+      expect_feature_available_default, 'battery');
+}, `${header} allows same-origin relocation.`);
+
+async_test(t => {
+  test_feature_availability(
+      'navigator.getBattery()', t, cross_origin_src,
+      expect_feature_unavailable_default, 'battery');
+}, `${header} disallows cross-origin relocation.`);
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/battery-status/battery-allowed-by-feature-policy-attribute.https.sub.html b/third_party/blink/web_tests/external/wpt/battery-status/battery-allowed-by-feature-policy-attribute.https.sub.html
new file mode 100644
index 0000000..96bca54
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/battery-status/battery-allowed-by-feature-policy-attribute.https.sub.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<body>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/feature-policy/resources/featurepolicy.js></script>
+<script>
+'use strict';
+
+const same_origin_src = '/feature-policy/resources/feature-policy-battery.html';
+const cross_origin_src = 'https://{{domains[www]}}:{{ports[https][0]}}' +
+  same_origin_src;
+const feature_name = 'Feature policy "battery"';
+const header = 'allow="battery" attribute';
+
+async_test(t => {
+  test_feature_availability(
+      'navigator.getBattery()', t, same_origin_src,
+      expect_feature_available_default, 'battery');
+}, `${feature_name} can be enabled in same-origin iframe using ${header}`);
+
+async_test(t => {
+  test_feature_availability(
+      'navigator.getBattery()', t, cross_origin_src,
+      expect_feature_available_default, 'battery');
+}, `${feature_name} can be enabled in cross-origin iframe using ${header}`);
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/battery-status/battery-allowed-by-feature-policy.https.sub.html b/third_party/blink/web_tests/external/wpt/battery-status/battery-allowed-by-feature-policy.https.sub.html
new file mode 100644
index 0000000..5849af5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/battery-status/battery-allowed-by-feature-policy.https.sub.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<body>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/feature-policy/resources/featurepolicy.js></script>
+<script>
+'use strict';
+
+const same_origin_src = '/feature-policy/resources/feature-policy-battery.html';
+const cross_origin_src = 'https://{{domains[www]}}:{{ports[https][0]}}' +
+  same_origin_src;
+const header = 'Feature-Policy header {"battery" : ["*"]}';
+
+promise_test(
+    async () => await navigator.getBattery(),
+   `${header} allows the top-level document.`);
+
+async_test(t => {
+  test_feature_availability('navigator.getBattery()', t, same_origin_src,
+      expect_feature_available_default);
+}, `${header} allows same-origin iframes.`);
+
+async_test(t => {
+  test_feature_availability('navigator.getBattery()', t, cross_origin_src,
+      expect_feature_available_default);
+}, `${header} allows cross-origin iframes.`);
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/battery-status/battery-allowed-by-feature-policy.https.sub.html.headers b/third_party/blink/web_tests/external/wpt/battery-status/battery-allowed-by-feature-policy.https.sub.html.headers
new file mode 100644
index 0000000..03b98040
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/battery-status/battery-allowed-by-feature-policy.https.sub.html.headers
@@ -0,0 +1 @@
+Feature-Policy: battery *
diff --git a/third_party/blink/web_tests/external/wpt/battery-status/battery-allowed-in-same-origin-iframe.https.html b/third_party/blink/web_tests/external/wpt/battery-status/battery-allowed-in-same-origin-iframe.https.html
new file mode 100644
index 0000000..c0d684f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/battery-status/battery-allowed-in-same-origin-iframe.https.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Battery Test: navigator.getBattery() is allowed in same origin iframe</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="help" href="https://www.w3.org/TR/battery-status/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<iframe id="blank" src="about:blank" style="display: none"></iframe>
+<script>
+
+function load_iframe(iframe, src) {
+  return new Promise((resolve, reject) => {
+    iframe.onload = () => resolve(iframe);
+    iframe.src = src;
+  });
+}
+
+promise_test(async t => {
+  let iframe = document.getElementById('blank');
+  const src = 'support-iframe.html';
+  iframe = await load_iframe(iframe, src);
+  await iframe.contentWindow.navigator.getBattery();
+}, "navigator.getBattery() is allowed in same origin iframe");
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/battery-status/battery-default-feature-policy.https.sub-expected.txt b/third_party/blink/web_tests/external/wpt/battery-status/battery-default-feature-policy.https.sub-expected.txt
new file mode 100644
index 0000000..54b00b9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/battery-status/battery-default-feature-policy.https.sub-expected.txt
@@ -0,0 +1,6 @@
+This is a testharness.js-based test.
+PASS Default "battery" feature policy ["self"] allows the top-level document.
+PASS Default "battery" feature policy ["self"] allows same-origin iframes.
+FAIL Default "battery" feature policy ["self"] disallows cross-origin iframes. assert_false: navigator.getBattery() expected false got true
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/battery-status/battery-default-feature-policy.https.sub.html b/third_party/blink/web_tests/external/wpt/battery-status/battery-default-feature-policy.https.sub.html
new file mode 100644
index 0000000..5486a45
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/battery-status/battery-default-feature-policy.https.sub.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<body>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/feature-policy/resources/featurepolicy.js></script>
+<script>
+'use strict';
+
+const same_origin_src = '/feature-policy/resources/feature-policy-battery.html';
+const cross_origin_src = 'https://{{domains[www]}}:{{ports[https][0]}}' +
+  same_origin_src;
+const header = 'Default "battery" feature policy ["self"]';
+
+promise_test(
+    async () => await navigator.getBattery(),
+    `${header} allows the top-level document.`);
+
+async_test(t => {
+  test_feature_availability('navigator.getBattery()', t, same_origin_src,
+      expect_feature_available_default);
+}, `${header} allows same-origin iframes.`);
+
+async_test(t => {
+  test_feature_availability('navigator.getBattery()', t, cross_origin_src,
+      expect_feature_unavailable_default);
+}, `${header} disallows cross-origin iframes.`);
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/battery-status/battery-disabled-by-feature-policy.https.sub-expected.txt b/third_party/blink/web_tests/external/wpt/battery-status/battery-disabled-by-feature-policy.https.sub-expected.txt
new file mode 100644
index 0000000..8cf8e32
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/battery-status/battery-disabled-by-feature-policy.https.sub-expected.txt
@@ -0,0 +1,6 @@
+This is a testharness.js-based test.
+FAIL Feature-Policy header {"battery" : []} disallows the top-level document. assert_unreached: Should have rejected: undefined Reached unreachable code
+FAIL Feature-Policy header {"battery" : []} disallows same-origin iframes. assert_false: navigator.getBattery() expected false got true
+FAIL Feature-Policy header {"battery" : []} disallows cross-origin iframes. assert_false: navigator.getBattery() expected false got true
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/battery-status/battery-disabled-by-feature-policy.https.sub.html b/third_party/blink/web_tests/external/wpt/battery-status/battery-disabled-by-feature-policy.https.sub.html
new file mode 100644
index 0000000..515c64fe4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/battery-status/battery-disabled-by-feature-policy.https.sub.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<body>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/feature-policy/resources/featurepolicy.js></script>
+<script>
+'use strict';
+
+const same_origin_src = '/feature-policy/resources/feature-policy-battery.html';
+const cross_origin_src = 'https://{{domains[www]}}:{{ports[https][0]}}' +
+  same_origin_src;
+const header = 'Feature-Policy header {"battery" : []}';
+
+promise_test(async t => {
+  await promise_rejects(t, 'NotAllowedError', navigator.getBattery());
+}, `${header} disallows the top-level document.`);
+
+async_test(t => {
+  test_feature_availability('navigator.getBattery()', t, same_origin_src,
+      expect_feature_unavailable_default);
+}, `${header} disallows same-origin iframes.`);
+
+async_test(t => {
+  test_feature_availability('navigator.getBattery()', t, cross_origin_src,
+      expect_feature_unavailable_default);
+}, `${header} disallows cross-origin iframes.`);
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/battery-status/battery-disabled-by-feature-policy.https.sub.html.headers b/third_party/blink/web_tests/external/wpt/battery-status/battery-disabled-by-feature-policy.https.sub.html.headers
new file mode 100644
index 0000000..09a5ae8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/battery-status/battery-disabled-by-feature-policy.https.sub.html.headers
@@ -0,0 +1 @@
+Feature-Policy: battery 'none'
diff --git a/third_party/blink/web_tests/external/wpt/battery-status/battery-disallowed-in-cross-origin-iframe.https.sub-expected.txt b/third_party/blink/web_tests/external/wpt/battery-status/battery-disallowed-in-cross-origin-iframe.https.sub-expected.txt
new file mode 100644
index 0000000..0d7a2cc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/battery-status/battery-disallowed-in-cross-origin-iframe.https.sub-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL throw a 'NotAllowedError' when invoking navigator.getBattery() within cross-origin iframe promise_test: Unhandled rejection with value: object "SecurityError: Blocked a frame with origin "https://web-platform.test:8444" from accessing a cross-origin frame."
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/battery-status/battery-disallowed-in-cross-origin-iframe.https.sub.html b/third_party/blink/web_tests/external/wpt/battery-status/battery-disallowed-in-cross-origin-iframe.https.sub.html
new file mode 100644
index 0000000..8b48626
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/battery-status/battery-disallowed-in-cross-origin-iframe.https.sub.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Battery Test: navigator.getBattery() is not allowed in cross origin iframe</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="help" href="https://www.w3.org/TR/battery-status/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<iframe id="blank" src="about:blank" style="display: none"></iframe>
+<script>
+
+function load_iframe(iframe, src) {
+  return new Promise((resolve, reject) => {
+    iframe.onload = () => resolve(iframe);
+    iframe.src = src;
+  });
+}
+
+promise_test(async t => {
+  let iframe = document.getElementById('blank');
+  const path = location.pathname.substring(0, location.pathname.lastIndexOf('/') + 1);
+  const src = 'https://{{domains[www1]}}:{{ports[https][0]}}' + path + 'support-iframe.html';
+  iframe = await load_iframe(iframe, src);
+  await promise_rejects(t, 'NotAllowedError', iframe.contentWindow.navigator.getBattery());
+}, "throw a 'NotAllowedError' when invoking navigator.getBattery() within cross-origin iframe");
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/battery-status/battery-iframe.https.html b/third_party/blink/web_tests/external/wpt/battery-status/battery-iframe.https.html
deleted file mode 100644
index 1f95b4e..0000000
--- a/third_party/blink/web_tests/external/wpt/battery-status/battery-iframe.https.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>Battery Test: navigator.getBattery() is not allowed in non top-level browsing context</title>
-<link rel="author" title="Intel" href="http://www.intel.com">
-<link rel="help" href="https://www.w3.org/TR/battery-status/">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<div id="log"></div>
-<iframe id="blank" src="about:blank" style="display: none"></iframe>
-<script>
-
-function load_iframe(iframe, src) {
-  return new Promise((resolve, reject) => {
-    iframe.onload = () => resolve(iframe);
-    iframe.src = src;
-  });
-}
-
-promise_test(t => {
-  var iframe = document.getElementById('blank');
-  var src = 'support-iframe.html';
-  return load_iframe(iframe, src)
-    .then(iframe => promise_rejects(t, 'SecurityError',
-                                    iframe.contentWindow.navigator.getBattery()));
-}, "throw a 'SecurityError' when invoking navigator.getBattery() within iframe");
-
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/opacity-overlapping-letters-ref.html b/third_party/blink/web_tests/external/wpt/css/css-color/opacity-overlapping-letters-ref.html
index 913aa7bc..bab1f80f 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-color/opacity-overlapping-letters-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/opacity-overlapping-letters-ref.html
@@ -1,2 +1,3 @@
+<link rel="stylesheet" href="/fonts/ahem.css">
 <meta name="flags" content="ahem">
 <div style="opacity: 0.5; letter-spacing: -0.6em; font: 100px/1 Ahem; white-space: pre">X X X</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/opacity-overlapping-letters.html b/third_party/blink/web_tests/external/wpt/css/css-color/opacity-overlapping-letters.html
index 34b444e..65ab3742 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-color/opacity-overlapping-letters.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/opacity-overlapping-letters.html
@@ -1,5 +1,6 @@
 <link rel="help" href="http://www.w3.org/TR/css3-color/#transparency">
 <link rel="match" href="opacity-overlapping-letters-ref.html">
+<link rel="stylesheet" href="/fonts/ahem.css">
 <meta name="flags" content="ahem">
 <meta name="assert" content="Opacity should be apply on the whole text content atomically.">
 <div style="opacity: 0.5; letter-spacing: -0.6em; font: 100px/1 Ahem">XXXXX</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/animation/grid-template-columns-interpolation-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-grid/animation/grid-template-columns-interpolation-expected.txt
index 15f1181..52ecd70 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/animation/grid-template-columns-interpolation-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/animation/grid-template-columns-interpolation-expected.txt
@@ -364,89 +364,89 @@
 FAIL Web Animations: property <grid-template-columns> from [1fr repeat(2, 2fr auto 30px) 1fr] to [2fr repeat(2, 3fr 30px 40px) 2fr] at (0.6) should be [1.6fr 2.6fr 30px 36px 2.6fr 30px 36px 1.6fr] assert_equals: expected "1.6fr 2.6fr 30px 36px 2.6fr 30px 36px 1.6fr " but got "2fr 3fr 30px 40px 3fr 30px 40px 2fr "
 PASS Web Animations: property <grid-template-columns> from [1fr repeat(2, 2fr auto 30px) 1fr] to [2fr repeat(2, 3fr 30px 40px) 2fr] at (1) should be [2fr 3fr 30px 40px 3fr 30px 40px 2fr]
 FAIL Web Animations: property <grid-template-columns> from [1fr repeat(2, 2fr auto 30px) 1fr] to [2fr repeat(2, 3fr 30px 40px) 2fr] at (2) should be [3fr 4fr 30px 50px 4fr 30px 50px 3fr] assert_equals: expected "3fr 4fr 30px 50px 4fr 30px 50px 3fr " but got "2fr 3fr 30px 40px 3fr 30px 40px 2fr "
-PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (-0.3) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.3) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.5) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.6) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1.5) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (-0.3) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.3) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.5) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.6) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1.5) should be [20px 20px]
-PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (-0.3) should be [10px 10px]
-PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0) should be [10px 10px]
-PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.3) should be [10px 10px]
-PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.5) should be [20px 20px]
-PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.6) should be [20px 20px]
-PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1) should be [20px 20px]
-PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1.5) should be [20px 20px]
-PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (-0.3) should be [10px 10px]
-PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0) should be [10px 10px]
-PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.3) should be [10px 10px]
-PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.5) should be [20px 20px]
-PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.6) should be [20px 20px]
-PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1) should be [20px 20px]
-PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1.5) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (-0.3) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.3) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.5) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.6) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1.5) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (-0.3) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.3) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.5) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.6) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1.5) should be [20px 20px]
-PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (-0.3) should be [10px 10px]
-PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0) should be [10px 10px]
-PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.3) should be [10px 10px]
-PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.5) should be [20px 20px]
-PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.6) should be [20px 20px]
-PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1) should be [20px 20px]
-PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1.5) should be [20px 20px]
-PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (-0.3) should be [10px 10px]
-PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0) should be [10px 10px]
-PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.3) should be [10px 10px]
-PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.5) should be [20px 20px]
-PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.6) should be [20px 20px]
-PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1) should be [20px 20px]
-PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1.5) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (-0.3) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.3) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.5) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.6) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1.5) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (-0.3) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.3) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.5) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.6) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1.5) should be [20px 20px]
-PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (-0.3) should be [10px 10px]
-PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0) should be [10px 10px]
-PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.3) should be [10px 10px]
-PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.5) should be [20px 20px]
-PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.6) should be [20px 20px]
-PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1) should be [20px 20px]
-PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1.5) should be [20px 20px]
-PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (-0.3) should be [10px 10px]
-PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0) should be [10px 10px]
-PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.3) should be [10px 10px]
-PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.5) should be [20px 20px]
-PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.6) should be [20px 20px]
-PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1) should be [20px 20px]
-PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1.5) should be [20px 20px]
+PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (-0.3) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.3) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.5) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.6) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1.5) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (-0.3) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.3) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.5) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.6) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1.5) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (-0.3) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.3) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.5) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.6) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1.5) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (-0.3) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.3) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.5) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.6) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1.5) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (-0.3) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.3) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.5) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.6) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1.5) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (-0.3) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.3) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.5) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.6) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1.5) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (-0.3) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.3) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.5) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.6) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1.5) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (-0.3) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.3) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.5) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.6) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1.5) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (-0.3) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.3) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.5) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.6) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Transitions: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1.5) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (-0.3) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.3) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.5) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.6) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Transitions with transition: all: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1.5) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (-0.3) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.3) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.5) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.6) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1.5) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (-0.3) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.3) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.5) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.6) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS Web Animations: property <grid-template-columns> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1.5) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/animation/grid-template-rows-interpolation-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-grid/animation/grid-template-rows-interpolation-expected.txt
index 497a536..b11bbee 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/animation/grid-template-rows-interpolation-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/animation/grid-template-rows-interpolation-expected.txt
@@ -364,89 +364,89 @@
 FAIL Web Animations: property <grid-template-rows> from [1fr repeat(2, 2fr auto 30px) 1fr] to [2fr repeat(2, 3fr 30px 40px) 2fr] at (0.6) should be [1.6fr 2.6fr 30px 36px 2.6fr 30px 36px 1.6fr] assert_equals: expected "1.6fr 2.6fr 30px 36px 2.6fr 30px 36px 1.6fr " but got "2fr 3fr 30px 40px 3fr 30px 40px 2fr "
 PASS Web Animations: property <grid-template-rows> from [1fr repeat(2, 2fr auto 30px) 1fr] to [2fr repeat(2, 3fr 30px 40px) 2fr] at (1) should be [2fr 3fr 30px 40px 3fr 30px 40px 2fr]
 FAIL Web Animations: property <grid-template-rows> from [1fr repeat(2, 2fr auto 30px) 1fr] to [2fr repeat(2, 3fr 30px 40px) 2fr] at (2) should be [3fr 4fr 30px 50px 4fr 30px 50px 3fr] assert_equals: expected "3fr 4fr 30px 50px 4fr 30px 50px 3fr " but got "2fr 3fr 30px 40px 3fr 30px 40px 2fr "
-PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (-0.3) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.3) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.5) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.6) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1.5) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (-0.3) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.3) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.5) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.6) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1.5) should be [20px 20px]
-PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (-0.3) should be [10px 10px]
-PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0) should be [10px 10px]
-PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.3) should be [10px 10px]
-PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.5) should be [20px 20px]
-PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.6) should be [20px 20px]
-PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1) should be [20px 20px]
-PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1.5) should be [20px 20px]
-PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (-0.3) should be [10px 10px]
-PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0) should be [10px 10px]
-PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.3) should be [10px 10px]
-PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.5) should be [20px 20px]
-PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.6) should be [20px 20px]
-PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1) should be [20px 20px]
-PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1.5) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (-0.3) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.3) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.5) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.6) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1.5) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (-0.3) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.3) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.5) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.6) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1.5) should be [20px 20px]
-PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (-0.3) should be [10px 10px]
-PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0) should be [10px 10px]
-PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.3) should be [10px 10px]
-PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.5) should be [20px 20px]
-PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.6) should be [20px 20px]
-PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1) should be [20px 20px]
-PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1.5) should be [20px 20px]
-PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (-0.3) should be [10px 10px]
-PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0) should be [10px 10px]
-PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.3) should be [10px 10px]
-PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.5) should be [20px 20px]
-PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.6) should be [20px 20px]
-PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1) should be [20px 20px]
-PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1.5) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (-0.3) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.3) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.5) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.6) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1) should be [20px 20px]
-PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1.5) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (-0.3) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.3) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.5) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.6) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1) should be [20px 20px]
-PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1.5) should be [20px 20px]
-PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (-0.3) should be [10px 10px]
-PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0) should be [10px 10px]
-PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.3) should be [10px 10px]
-PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.5) should be [20px 20px]
-PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.6) should be [20px 20px]
-PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1) should be [20px 20px]
-PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1.5) should be [20px 20px]
-PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (-0.3) should be [10px 10px]
-PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0) should be [10px 10px]
-PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.3) should be [10px 10px]
-PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.5) should be [20px 20px]
-PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.6) should be [20px 20px]
-PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1) should be [20px 20px]
-PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1.5) should be [20px 20px]
+PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (-0.3) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.3) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.5) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.6) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1.5) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (-0.3) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.3) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.5) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.6) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1.5) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (-0.3) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.3) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.5) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.6) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1.5) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (-0.3) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.3) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.5) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (0.6) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px 20px repeat(auto-fill, minmax(30px, 1fr))] at (1.5) should be [20px 20px repeat(auto-fill, minmax(30px, 1fr))]
+PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (-0.3) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.3) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.5) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.6) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1.5) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (-0.3) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.3) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.5) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.6) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1.5) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (-0.3) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.3) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.5) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.6) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1.5) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (-0.3) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.3) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.5) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (0.6) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fit, minmax(30px, 1fr)) 20px] at (1.5) should be [20px repeat(auto-fit, minmax(30px, 1fr)) 20px]
+PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (-0.3) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.3) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.5) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.6) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Transitions: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1.5) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (-0.3) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.3) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.5) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.6) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Transitions with transition: all: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1.5) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (-0.3) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.3) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.5) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.6) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS CSS Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1.5) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (-0.3) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.3) should be [10px repeat(auto-fill, minmax(25px, 1fr)) 10px]
+PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.5) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (0.6) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
+PASS Web Animations: property <grid-template-rows> from [10px repeat(auto-fill, minmax(25px, 1fr)) 10px] to [20px repeat(auto-fill, minmax(35px, auto)) 20px] at (1.5) should be [20px repeat(auto-fill, minmax(35px, auto)) 20px]
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-template-columns-computed-nogrid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-template-columns-computed-nogrid-expected.txt
new file mode 100644
index 0000000..26a5800
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-template-columns-computed-nogrid-expected.txt
@@ -0,0 +1,24 @@
+This is a testharness.js-based test.
+PASS Property grid-template-columns value 'none' computes to 'none'
+PASS Property grid-template-columns value '1px' computes to '1px'
+PASS Property grid-template-columns value '1px [a]' computes to '1px [a]'
+PASS Property grid-template-columns value '1px [a] 2px' computes to '1px [a] 2px'
+PASS Property grid-template-columns value '[a] 1px' computes to '[a] 1px'
+PASS Property grid-template-columns value '[a] 1px [b]' computes to '[a] 1px [b]'
+FAIL Property grid-template-columns value '1px repeat(1, 2px) 3px' computes to '1px repeat(1, 2px) 3px' assert_equals: expected "1px repeat(1, 2px) 3px" but got "1px 2px 3px"
+PASS Property grid-template-columns value '1px repeat(auto-fill, 2px) 3px' computes to '1px repeat(auto-fill, 2px) 3px'
+PASS Property grid-template-columns value '1px repeat(auto-fit, 2px) 3px' computes to '1px repeat(auto-fit, 2px) 3px'
+FAIL Property grid-template-columns value '1px [a] repeat(1, [b] 2px [c]) [d] 3px' computes to '1px [a] repeat(1, [b] 2px [c]) [d] 3px' assert_equals: expected "1px [a] repeat(1, [b] 2px [c]) [d] 3px" but got "1px [a b] 2px [c d] 3px"
+PASS Property grid-template-columns value '1px [a] repeat(auto-fill, [b] 2px [c]) [d] 3px' computes to '1px [a] repeat(auto-fill, [b] 2px [c]) [d] 3px'
+PASS Property grid-template-columns value '1px [a] repeat(auto-fit, [b] 2px [c]) [d] 3px' computes to '1px [a] repeat(auto-fit, [b] 2px [c]) [d] 3px'
+FAIL Property grid-template-columns value '[a] 1px repeat(1, 2px [b] 3px) 4px [d]' computes to '[a] 1px repeat(1, 2px [b] 3px) 4px [d]' assert_equals: expected "[a] 1px repeat(1, 2px [b] 3px) 4px [d]" but got "[a] 1px 2px [b] 3px 4px [d]"
+PASS Property grid-template-columns value '[a] 1px repeat(auto-fill, 2px [b] 3px) 4px [d]' computes to '[a] 1px repeat(auto-fill, 2px [b] 3px) 4px [d]'
+PASS Property grid-template-columns value '[a] 1px repeat(auto-fit, 2px [b] 3px) 4px [d]' computes to '[a] 1px repeat(auto-fit, 2px [b] 3px) 4px [d]'
+FAIL Property grid-template-rows value '100% [a] repeat(1, [b] 200% [c]) [d] 300%' computes to '100% [a] repeat(1, [b] 200% [c]) [d] 300%' assert_equals: expected "100% [a] repeat(1, [b] 200% [c]) [d] 300%" but got "100% [a b] 200% [c d] 300%"
+PASS Property grid-template-rows value '100% [a] repeat(auto-fill, [b] 200% [c]) [d] 300%' computes to '100% [a] repeat(auto-fill, [b] 200% [c]) [d] 300%'
+PASS Property grid-template-rows value '100% [a] repeat(auto-fit, [b] 200% [c]) [d] 300%' computes to '100% [a] repeat(auto-fit, [b] 200% [c]) [d] 300%'
+FAIL Property grid-template-columns value '[a] 1em repeat(1, 2em [b] 3em) 4em [d]' computes to '[a] 1px repeat(1, 2px [b] 3px) 4px [d]' assert_equals: expected "[a] 1px repeat(1, 2px [b] 3px) 4px [d]" but got "[a] 1px 2px [b] 3px 4px [d]"
+PASS Property grid-template-columns value '[a] 1em repeat(auto-fill, 2em [b] 3em) 4em [d]' computes to '[a] 1px repeat(auto-fill, 2px [b] 3px) 4px [d]'
+PASS Property grid-template-columns value '[a] 1em repeat(auto-fit, 2em [b] 3em) 4em [d]' computes to '[a] 1px repeat(auto-fit, 2px [b] 3px) 4px [d]'
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-template-columns-computed-nogrid.html b/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-template-columns-computed-nogrid.html
new file mode 100644
index 0000000..b95914f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-template-columns-computed-nogrid.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: getComputedStyle().gridTemplateColumns</title>
+<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid/#resolved-track-list" title="7.2.6. Resolved Value of a Track Listing">
+<meta name="assert" content="Checks the resolved value of grid-template-columns on an element which is not a grid container.">
+<style>
+#target {
+  display: block;
+  height: 1px;
+  font-size: 1px;
+}
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<div id="target"></div>
+<script>
+test_computed_value("grid-template-columns", "none");
+test_computed_value("grid-template-columns", "1px");
+test_computed_value("grid-template-columns", "1px [a]");
+test_computed_value("grid-template-columns", "1px [a] 2px");
+test_computed_value("grid-template-columns", "[a] 1px");
+test_computed_value("grid-template-columns", "[a] 1px [b]");
+test_computed_value("grid-template-columns", "1px repeat(1, 2px) 3px");
+test_computed_value("grid-template-columns", "1px repeat(auto-fill, 2px) 3px");
+test_computed_value("grid-template-columns", "1px repeat(auto-fit, 2px) 3px");
+test_computed_value("grid-template-columns", "1px [a] repeat(1, [b] 2px [c]) [d] 3px");
+test_computed_value("grid-template-columns", "1px [a] repeat(auto-fill, [b] 2px [c]) [d] 3px");
+test_computed_value("grid-template-columns", "1px [a] repeat(auto-fit, [b] 2px [c]) [d] 3px");
+test_computed_value("grid-template-columns", "[a] 1px repeat(1, 2px [b] 3px) 4px [d]");
+test_computed_value("grid-template-columns", "[a] 1px repeat(auto-fill, 2px [b] 3px) 4px [d]");
+test_computed_value("grid-template-columns", "[a] 1px repeat(auto-fit, 2px [b] 3px) 4px [d]");
+test_computed_value("grid-template-rows", "100% [a] repeat(1, [b] 200% [c]) [d] 300%");
+test_computed_value("grid-template-rows", "100% [a] repeat(auto-fill, [b] 200% [c]) [d] 300%");
+test_computed_value("grid-template-rows", "100% [a] repeat(auto-fit, [b] 200% [c]) [d] 300%");
+test_computed_value("grid-template-columns", "[a] 1em repeat(1, 2em [b] 3em) 4em [d]", "[a] 1px repeat(1, 2px [b] 3px) 4px [d]");
+test_computed_value("grid-template-columns", "[a] 1em repeat(auto-fill, 2em [b] 3em) 4em [d]", "[a] 1px repeat(auto-fill, 2px [b] 3px) 4px [d]");
+test_computed_value("grid-template-columns", "[a] 1em repeat(auto-fit, 2em [b] 3em) 4em [d]", "[a] 1px repeat(auto-fit, 2px [b] 3px) 4px [d]");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-template-columns-computed.html b/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-template-columns-computed.html
new file mode 100644
index 0000000..f6d0d97
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-template-columns-computed.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: getComputedStyle().gridTemplateColumns</title>
+<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid/#resolved-track-list" title="7.2.6. Resolved Value of a Track Listing">
+<meta name="assert" content="Checks the resolved value of grid-template-columns on a grid container.">
+<style>
+#target {
+  display: grid;
+  width: 1px;
+  font-size: 1px;
+}
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<div id="target"></div>
+<script>
+test_computed_value("grid-template-columns", "none");
+test_computed_value("grid-template-columns", "1px");
+test_computed_value("grid-template-columns", "1px [a]");
+test_computed_value("grid-template-columns", "1px [a] 2px");
+test_computed_value("grid-template-columns", "[a] 1px");
+test_computed_value("grid-template-columns", "[a] 1px [b]");
+test_computed_value("grid-template-columns", "1px repeat(1, 2px) 3px", "1px 2px 3px");
+test_computed_value("grid-template-columns", "1px repeat(auto-fill, 2px) 3px", "1px 2px 3px");
+test_computed_value("grid-template-columns", "1px repeat(auto-fit, 2px) 3px", "1px 0px 3px");
+test_computed_value("grid-template-columns", "1px [a] repeat(1, [b] 2px [c]) [d] 3px", "1px [a b] 2px [c d] 3px");
+test_computed_value("grid-template-columns", "1px [a] repeat(auto-fill, [b] 2px [c]) [d] 3px", "1px [a b] 2px [c d] 3px");
+test_computed_value("grid-template-columns", "1px [a] repeat(auto-fit, [b] 2px [c]) [d] 3px", "1px [a b] 0px [c d] 3px");
+test_computed_value("grid-template-columns", "[a] 1px repeat(1, 2px [b] 3px) 4px [d]", "[a] 1px 2px [b] 3px 4px [d]");
+test_computed_value("grid-template-columns", "[a] 1px repeat(auto-fill, 2px [b] 3px) 4px [d]", "[a] 1px 2px [b] 3px 4px [d]");
+test_computed_value("grid-template-columns", "[a] 1px repeat(auto-fit, 2px [b] 3px) 4px [d]", "[a] 1px 0px [b] 0px 4px [d]");
+test_computed_value("grid-template-columns", "100% [a] repeat(1, [b] 200% [c]) [d] 300%", "1px [a b] 2px [c d] 3px");
+test_computed_value("grid-template-columns", "100% [a] repeat(auto-fill, [b] 200% [c]) [d] 300%", "1px [a b] 2px [c d] 3px");
+test_computed_value("grid-template-columns", "100% [a] repeat(auto-fit, [b] 200% [c]) [d] 300%", "1px [a b] 0px [c d] 3px");
+test_computed_value("grid-template-columns", "[a] 1em repeat(1, 2em [b] 3em) 4em [d]", "[a] 1px 2px [b] 3px 4px [d]");
+test_computed_value("grid-template-columns", "[a] 1em repeat(auto-fill, 2em [b] 3em) 4em [d]", "[a] 1px 2px [b] 3px 4px [d]");
+test_computed_value("grid-template-columns", "[a] 1em repeat(auto-fit, 2em [b] 3em) 4em [d]", "[a] 1px 0px [b] 0px 4px [d]");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-template-rows-computed-nogrid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-template-rows-computed-nogrid-expected.txt
new file mode 100644
index 0000000..b2946e95
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-template-rows-computed-nogrid-expected.txt
@@ -0,0 +1,24 @@
+This is a testharness.js-based test.
+PASS Property grid-template-rows value 'none' computes to 'none'
+PASS Property grid-template-rows value '1px' computes to '1px'
+PASS Property grid-template-rows value '1px [a]' computes to '1px [a]'
+PASS Property grid-template-rows value '1px [a] 2px' computes to '1px [a] 2px'
+PASS Property grid-template-rows value '[a] 1px' computes to '[a] 1px'
+PASS Property grid-template-rows value '[a] 1px [b]' computes to '[a] 1px [b]'
+FAIL Property grid-template-rows value '1px repeat(1, 2px) 3px' computes to '1px repeat(1, 2px) 3px' assert_equals: expected "1px repeat(1, 2px) 3px" but got "1px 2px 3px"
+PASS Property grid-template-rows value '1px repeat(auto-fill, 2px) 3px' computes to '1px repeat(auto-fill, 2px) 3px'
+PASS Property grid-template-rows value '1px repeat(auto-fit, 2px) 3px' computes to '1px repeat(auto-fit, 2px) 3px'
+FAIL Property grid-template-rows value '1px [a] repeat(1, [b] 2px [c]) [d] 3px' computes to '1px [a] repeat(1, [b] 2px [c]) [d] 3px' assert_equals: expected "1px [a] repeat(1, [b] 2px [c]) [d] 3px" but got "1px [a b] 2px [c d] 3px"
+PASS Property grid-template-rows value '1px [a] repeat(auto-fill, [b] 2px [c]) [d] 3px' computes to '1px [a] repeat(auto-fill, [b] 2px [c]) [d] 3px'
+PASS Property grid-template-rows value '1px [a] repeat(auto-fit, [b] 2px [c]) [d] 3px' computes to '1px [a] repeat(auto-fit, [b] 2px [c]) [d] 3px'
+FAIL Property grid-template-rows value '[a] 1px repeat(1, 2px [b] 3px) 4px [d]' computes to '[a] 1px repeat(1, 2px [b] 3px) 4px [d]' assert_equals: expected "[a] 1px repeat(1, 2px [b] 3px) 4px [d]" but got "[a] 1px 2px [b] 3px 4px [d]"
+PASS Property grid-template-rows value '[a] 1px repeat(auto-fill, 2px [b] 3px) 4px [d]' computes to '[a] 1px repeat(auto-fill, 2px [b] 3px) 4px [d]'
+PASS Property grid-template-rows value '[a] 1px repeat(auto-fit, 2px [b] 3px) 4px [d]' computes to '[a] 1px repeat(auto-fit, 2px [b] 3px) 4px [d]'
+FAIL Property grid-template-rows value '100% [a] repeat(1, [b] 200% [c]) [d] 300%' computes to '100% [a] repeat(1, [b] 200% [c]) [d] 300%' assert_equals: expected "100% [a] repeat(1, [b] 200% [c]) [d] 300%" but got "100% [a b] 200% [c d] 300%"
+PASS Property grid-template-rows value '100% [a] repeat(auto-fill, [b] 200% [c]) [d] 300%' computes to '100% [a] repeat(auto-fill, [b] 200% [c]) [d] 300%'
+PASS Property grid-template-rows value '100% [a] repeat(auto-fit, [b] 200% [c]) [d] 300%' computes to '100% [a] repeat(auto-fit, [b] 200% [c]) [d] 300%'
+FAIL Property grid-template-rows value '[a] 1em repeat(1, 2em [b] 3em) 4em [d]' computes to '[a] 1px repeat(1, 2px [b] 3px) 4px [d]' assert_equals: expected "[a] 1px repeat(1, 2px [b] 3px) 4px [d]" but got "[a] 1px 2px [b] 3px 4px [d]"
+PASS Property grid-template-rows value '[a] 1em repeat(auto-fill, 2em [b] 3em) 4em [d]' computes to '[a] 1px repeat(auto-fill, 2px [b] 3px) 4px [d]'
+PASS Property grid-template-rows value '[a] 1em repeat(auto-fit, 2em [b] 3em) 4em [d]' computes to '[a] 1px repeat(auto-fit, 2px [b] 3px) 4px [d]'
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-template-rows-computed-nogrid.html b/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-template-rows-computed-nogrid.html
new file mode 100644
index 0000000..03e601ac
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-template-rows-computed-nogrid.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: getComputedStyle().gridTemplateRows</title>
+<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid/#resolved-track-list" title="7.2.6. Resolved Value of a Track Listing">
+<meta name="assert" content="Checks the resolved value of grid-template-rows on an element which is not a grid container.">
+<style>
+#target {
+  display: block;
+  height: 1px;
+  font-size: 1px;
+}
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<div id="target"></div>
+<script>
+test_computed_value("grid-template-rows", "none");
+test_computed_value("grid-template-rows", "1px");
+test_computed_value("grid-template-rows", "1px [a]");
+test_computed_value("grid-template-rows", "1px [a] 2px");
+test_computed_value("grid-template-rows", "[a] 1px");
+test_computed_value("grid-template-rows", "[a] 1px [b]");
+test_computed_value("grid-template-rows", "1px repeat(1, 2px) 3px");
+test_computed_value("grid-template-rows", "1px repeat(auto-fill, 2px) 3px");
+test_computed_value("grid-template-rows", "1px repeat(auto-fit, 2px) 3px");
+test_computed_value("grid-template-rows", "1px [a] repeat(1, [b] 2px [c]) [d] 3px");
+test_computed_value("grid-template-rows", "1px [a] repeat(auto-fill, [b] 2px [c]) [d] 3px");
+test_computed_value("grid-template-rows", "1px [a] repeat(auto-fit, [b] 2px [c]) [d] 3px");
+test_computed_value("grid-template-rows", "[a] 1px repeat(1, 2px [b] 3px) 4px [d]");
+test_computed_value("grid-template-rows", "[a] 1px repeat(auto-fill, 2px [b] 3px) 4px [d]");
+test_computed_value("grid-template-rows", "[a] 1px repeat(auto-fit, 2px [b] 3px) 4px [d]");
+test_computed_value("grid-template-rows", "100% [a] repeat(1, [b] 200% [c]) [d] 300%");
+test_computed_value("grid-template-rows", "100% [a] repeat(auto-fill, [b] 200% [c]) [d] 300%");
+test_computed_value("grid-template-rows", "100% [a] repeat(auto-fit, [b] 200% [c]) [d] 300%");
+test_computed_value("grid-template-rows", "[a] 1em repeat(1, 2em [b] 3em) 4em [d]", "[a] 1px repeat(1, 2px [b] 3px) 4px [d]");
+test_computed_value("grid-template-rows", "[a] 1em repeat(auto-fill, 2em [b] 3em) 4em [d]", "[a] 1px repeat(auto-fill, 2px [b] 3px) 4px [d]");
+test_computed_value("grid-template-rows", "[a] 1em repeat(auto-fit, 2em [b] 3em) 4em [d]", "[a] 1px repeat(auto-fit, 2px [b] 3px) 4px [d]");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-template-rows-computed.html b/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-template-rows-computed.html
new file mode 100644
index 0000000..4072262
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-template-rows-computed.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: getComputedStyle().gridTemplateRows</title>
+<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid/#resolved-track-list" title="7.2.6. Resolved Value of a Track Listing">
+<meta name="assert" content="Checks the resolved value of grid-template-rows on a grid container.">
+<style>
+#target {
+  display: grid;
+  height: 1px;
+  font-size: 1px;
+}
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<div id="target"></div>
+<script>
+test_computed_value("grid-template-rows", "none");
+test_computed_value("grid-template-rows", "1px");
+test_computed_value("grid-template-rows", "1px [a]");
+test_computed_value("grid-template-rows", "1px [a] 2px");
+test_computed_value("grid-template-rows", "[a] 1px");
+test_computed_value("grid-template-rows", "[a] 1px [b]");
+test_computed_value("grid-template-rows", "1px repeat(1, 2px) 3px", "1px 2px 3px");
+test_computed_value("grid-template-rows", "1px repeat(auto-fill, 2px) 3px", "1px 2px 3px");
+test_computed_value("grid-template-rows", "1px repeat(auto-fit, 2px) 3px", "1px 0px 3px");
+test_computed_value("grid-template-rows", "1px [a] repeat(1, [b] 2px [c]) [d] 3px", "1px [a b] 2px [c d] 3px");
+test_computed_value("grid-template-rows", "1px [a] repeat(auto-fill, [b] 2px [c]) [d] 3px", "1px [a b] 2px [c d] 3px");
+test_computed_value("grid-template-rows", "1px [a] repeat(auto-fit, [b] 2px [c]) [d] 3px", "1px [a b] 0px [c d] 3px");
+test_computed_value("grid-template-rows", "[a] 1px repeat(1, 2px [b] 3px) 4px [d]", "[a] 1px 2px [b] 3px 4px [d]");
+test_computed_value("grid-template-rows", "[a] 1px repeat(auto-fill, 2px [b] 3px) 4px [d]", "[a] 1px 2px [b] 3px 4px [d]");
+test_computed_value("grid-template-rows", "[a] 1px repeat(auto-fit, 2px [b] 3px) 4px [d]", "[a] 1px 0px [b] 0px 4px [d]");
+test_computed_value("grid-template-rows", "100% [a] repeat(1, [b] 200% [c]) [d] 300%", "1px [a b] 2px [c d] 3px");
+test_computed_value("grid-template-rows", "100% [a] repeat(auto-fill, [b] 200% [c]) [d] 300%", "1px [a b] 2px [c d] 3px");
+test_computed_value("grid-template-rows", "100% [a] repeat(auto-fit, [b] 200% [c]) [d] 300%", "1px [a b] 0px [c d] 3px");
+test_computed_value("grid-template-rows", "[a] 1em repeat(1, 2em [b] 3em) 4em [d]", "[a] 1px 2px [b] 3px 4px [d]");
+test_computed_value("grid-template-rows", "[a] 1em repeat(auto-fill, 2em [b] 3em) 4em [d]", "[a] 1px 2px [b] 3px 4px [d]");
+test_computed_value("grid-template-rows", "[a] 1em repeat(auto-fit, 2em [b] 3em) 4em [d]", "[a] 1px 0px [b] 0px 4px [d]");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-012.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-012.html
index f0eb17c..e844d9786 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-012.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-012.html
@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>CSS Text level 3 Test: preserved white space at the end of and white-space:pre-wrap with right alignement</title>
+<title>CSS Text level 3 Test: preserved white space at the end of soft-wrapped lines and white-space:pre-wrap with right alignement</title>
 <link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
 <link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2">
 <link rel="match" href="reference/pre-wrap-012-ref.html">
-<meta name="assert" content="When white-space is pre-wrap, spaces at the end of the line hang, so they do not have any effect when right-aligning.">
+<meta name="assert" content="When white-space is pre-wrap, spaces at the end of soft-wrapped lines hang, so they do not have any effect when right-aligning.">
 <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
 <style>
 div {
@@ -22,6 +22,5 @@
 </style>
 <body>
   <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p>
-  <div>XX&#x20;
-XX </div>
+  <div>XX XX</div>
 </body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-013.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-013.html
index 29333f5..23c4b536 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-013.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-013.html
@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>CSS Text level 3 Test: preserved white space at the end of and white-space:pre-wrap with center alignement</title>
+<title>CSS Text level 3 Test: preserved white space at the end of soft-wrapped lines and white-space:pre-wrap with center alignement</title>
 <link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
 <link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2">
 <link rel="match" href="reference/pre-wrap-013-ref.html">
-<meta name="assert" content="When white-space is pre-wrap, spaces at the end of the line hang, so they do not have any effect when centering.">
+<meta name="assert" content="When white-space is pre-wrap, spaces at the end of soft-wrapped lines hang, so they do not have any effect when centering.">
 <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
 <style>
 div {
@@ -22,6 +22,5 @@
 </style>
 <body>
   <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p>
-  <div>XX&#x20;
-XX </div>
+  <div>XX XX</div>
 </body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-014.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-014.html
index ac86777..26423c1 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-014.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-014.html
@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>CSS Text level 3 Test: preserved white space at the end of and white-space:pre-wrap with justification</title>
+<title>CSS Text level 3 Test: preserved white space at the end of soft-wrapped lines and white-space:pre-wrap with justification</title>
 <link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
 <link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2">
 <link rel="match" href="reference/pre-wrap-014-ref.html">
-<meta name="assert" content="When white-space is pre-wrap, spaces at the end of the line hang, so they do not have any effect when justifying.">
+<meta name="assert" content="When white-space is pre-wrap, spaces at the end of soft-wrapped lines hang, so they do not have any effect when justifying.">
 <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
 <style>
 div {
@@ -27,6 +27,6 @@
 </style>
 <body>
   <p>Test passes if there is a <strong>filled green rectangle</strong> and <strong>no red</strong>.</p>
-  <div><span>X X</span>&#x20;
-  X</div><!-- invisible last line, because justification works on non-last lines-->
+  <div><span>X X</span> X</div>
+  <!-- invisible last line, because justification works on non-last lines-->
 </body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-017.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-017.html
new file mode 100644
index 0000000..541e1ab
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-017.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text level 3 Test: pre-wrap trailing spaces and max-content</title>
+<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2">
+<link rel="match" href="reference/pre-wrap-001-ref.html">
+<meta name="assert" content="When white-space is pre-wrap, trailing spaces spaces are taken into account for max-content">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+#red {
+  position: absolute;
+  z-index:-1;
+  width: 40px;
+  height: 40px;
+  background: red;
+}
+#test {
+  margin-left: -1em;
+  font: 40px/1 Ahem;
+  color: white;
+  background: green;
+  width: max-content;
+  white-space: pre-wrap
+}
+</style>
+
+<p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p>
+
+<div id=red></div>
+<div id=test>X&#x0020;</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-018.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-018.html
new file mode 100644
index 0000000..f911b2dc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-018.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text level 3 Test: pre-wrap spaces and centering</title>
+<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2">
+<link rel="match" href="reference/pre-wrap-018-ref.html">
+<meta name="assert" content="conditionally hanging white space at the end of lines with forced breaks provides symmetry with the start of the line">
+<style>
+div {
+  font-size: 2rem;
+  margin: 1rem;
+}
+#test {
+  white-space: pre-wrap;
+  width: 5ch;
+  border: solid 1px;
+  font-family: monospace;
+  text-align: center;
+  text-decoration: underline;
+}
+
+#ref {
+  white-space: pre;
+  width: 5ch;
+  border: solid 1px;
+  font-family: monospace;
+}
+#ref span {
+  text-decoration: underline;
+}
+
+</style>
+
+<p>Test passes if the two boxes below are identical.
+
+<div id=test> 0 </div>
+<div id=ref> <span> 0 </span></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-019.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-019.html
new file mode 100644
index 0000000..58dae9f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-019.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text level 3 Test: trailing pre-wrap spaces and hanging</title>
+<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2">
+<link rel="match" href="reference/pre-wrap-019-ref.html">
+<meta name="assert" content="trailing pre-wrap spaces hang at soft-wrapped lines, and hang conditionally before forced breaks.">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+div {
+  font-size: 2rem;
+  font-family: Ahem;
+  width: 3ch;
+}
+#test1, #test2 {
+  white-space: pre-wrap;
+  color: green;
+}
+#test2 {
+  text-align: right;
+}
+
+.ref {
+  white-space: pre;
+  color: red;
+  position: absolute;
+  z-index: -1;
+}
+
+</style>
+
+<p>Test passes if there are green squares below and no red.
+
+<div class=ref> 0 <br>0 0 <br>0 </div>
+<div id=test1> 0 0 0 0 </div>
+
+<div class=ref>  0<br>0 0 <br> 0</div>
+<div id=test2> 0 0 0 0 </div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-020.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-020.html
new file mode 100644
index 0000000..ec3e862
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-wrap-020.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text level 3 Test: trailing pre-wrap spaces and conditional hanging</title>
+<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2">
+<link rel="match" href="reference/pre-wrap-020-ref.html">
+<meta name="assert" content="trailing pre-wrap spaces hang conditionally before forced breaks, which is different from not hanging at all, as it doesn't cause wrapping at earlier opportunities.">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+div {
+  font-size: 2rem;
+  font-family: Ahem;
+  width: 3ch;
+}
+#test {
+  white-space: pre-wrap;
+  color: green;
+}
+
+.ref {
+  white-space: pre;
+  color: red;
+  position: absolute;
+  z-index: -1;
+}
+
+</style>
+
+<p>Test passes if there are green rectangles below and no red.
+
+<div class=ref>0 0<br>0 0</div>
+<div id=test>0 0 0 0 </div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/pre-wrap-018-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/pre-wrap-018-ref.html
new file mode 100644
index 0000000..a876494
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/pre-wrap-018-ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Test reference</title>
+<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
+<style>
+div {
+  font-size: 2rem;
+  margin: 1rem;
+  white-space: pre;
+  width: 5ch;
+  border: solid 1px;
+  font-family: monospace;
+}
+span {
+  text-decoration: underline;
+}
+
+</style>
+
+<p>Test passes if the two boxes below are identical.
+
+<div> <span> 0 </span></div>
+<div> <span> 0 </span></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/pre-wrap-019-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/pre-wrap-019-ref.html
new file mode 100644
index 0000000..e3be478
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/pre-wrap-019-ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Test reference</title>
+<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+div {
+  font-size: 2rem;
+  font-family: Ahem;
+  width: 3ch;
+  white-space: pre;
+  color: green;
+}
+
+</style>
+
+<p>Test passes if there are green squares below and no red.
+
+<div class=ref> 0 <br>0 0 <br>0 </div>
+
+<div class=ref>  0<br>0 0 <br> 0</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/pre-wrap-020-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/pre-wrap-020-ref.html
new file mode 100644
index 0000000..2ef5e7f4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/pre-wrap-020-ref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>test reference</title>
+<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+div {
+  font-size: 2rem;
+  font-family: Ahem;
+  width: 3ch;
+  white-space: pre;
+  color: green;
+}
+
+</style>
+
+<p>Test passes if there are green rectangles below and no red.
+
+<div>0 0<br>0 0</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/textarea-pre-wrap-014-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/textarea-pre-wrap-014-ref.html
new file mode 100644
index 0000000..99a38bf
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/textarea-pre-wrap-014-ref.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Test reference</title>
+<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
+<p>Test passes if there is <strong>no red</strong> below.</p>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/white-space-intrinsic-size-004-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/white-space-intrinsic-size-004-ref.html
index 0c31cb4..93b8b913 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/white-space-intrinsic-size-004-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/white-space-intrinsic-size-004-ref.html
@@ -2,14 +2,13 @@
 <meta charset="utf-8">
 <title>test reference</title>
 <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
 <style>
 div {
   color: transparent;
-  font-family: Ahem;
+  font-family: monospace;
   font-size: 50px;
   width: 3ch;
-  height: 2ch;
+  height: 2em;
   background: green;
 }
 </style>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/white-space-pre-wrap-trailing-spaces-002-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/white-space-pre-wrap-trailing-spaces-002-ref.html
index 5f94d07..0971868 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/white-space-pre-wrap-trailing-spaces-002-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/white-space-pre-wrap-trailing-spaces-002-ref.html
@@ -2,7 +2,19 @@
 <meta charset=utf-8>
 <title>CSS test Reference</title>
 <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+div {
+  font-size: 20px;
+  font-family: Ahem;
+  line-height: 1em;
+  white-space: pre-wrap;
+}
+#test { color: orange; }
+#ref { color: blue; }
+</style>
 
-<p>This test passes if the letters below are spaced equally.
+<p>This test passes if the orange blocks below are vertically aligned with the blue ones.
 
-<div>X X X X</div>
+<div id=test>X  X  X  X</div>
+<div id=ref>X  X  X  X</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/textarea-pre-wrap-012.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/textarea-pre-wrap-012.html
index 04e07d6b..5ca12811 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/textarea-pre-wrap-012.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/textarea-pre-wrap-012.html
@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>CSS Text level 3 Test: preserved white space at the end of and white-space:pre-wrap with right alignement in a textarea</title>
+<title>CSS Text level 3 Test: preserved white space at the end of soft-wrapped lines and white-space:pre-wrap with right alignement in a textarea</title>
 <link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
 <link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2">
-<link rel="match" href="reference/textarea-pre-wrap-001-ref.html">
-<meta name="assert" content="When white-space is pre-wrap, only spaces that overflow the line get collapsed or hanged, the ones that fit have an effect when right-aligning in a textarea.">
+<link rel="match" href="reference/pre-wrap-012-ref.html">
+<meta name="assert" content="When white-space is pre-wrap, only spaces at the end of soft-wrapped lines get collapsed or hanged, so they do not have any effect when right aligning.">
 <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
 <style>
 textarea {
@@ -25,7 +25,7 @@
   white-space: pre-wrap;
   color: green;
 
-  background: linear-gradient(red, red) 0 0/2ch 2ch no-repeat;
+  background: linear-gradient(red, red) 1ch 0/2ch 2ch no-repeat;
 
   width: 3ch;
   text-align: right;
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/textarea-pre-wrap-013.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/textarea-pre-wrap-013.html
index 853d2c3..e3d5c3253 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/textarea-pre-wrap-013.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/textarea-pre-wrap-013.html
@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>CSS Text level 3 Test: preserved white space at the end of and white-space:pre-wrap with center alignement in a textarea</title>
+<title>CSS Text level 3 Test: preserved white space at the end of soft-wrapped line and white-space:pre-wrap with center alignement in a textarea</title>
 <link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
 <link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2">
-<link rel="match" href="reference/textarea-pre-wrap-001-ref.html">
-<meta name="assert" content="When white-space is pre-wrap, only spaces that overflow the line get collapsed or hanged, the ones that fit have an effect when centering in a textarea.">
+<link rel="match" href="reference/pre-wrap-013-ref.html">
+<meta name="assert" content="When white-space is pre-wrap, spaces at the end of soft-wrapped lines get collapsed or hanged, so they do not have any effect when centering.">
 <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
 <style>
 textarea {
@@ -25,7 +25,7 @@
   white-space: pre-wrap;
   color: green;
 
-  background: linear-gradient(red, red) 0 0/2ch 2ch no-repeat;
+  background: linear-gradient(red, red) 0.5ch 0/2ch 2ch no-repeat;
 
   width: 3ch;
   text-align: center;
@@ -33,6 +33,5 @@
 </style>
 <body>
   <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p>
-  <textarea>XX&#x20;
-XX </textarea>
+  <textarea>XX XX</textarea>
 </body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/textarea-pre-wrap-014.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/textarea-pre-wrap-014.html
index b6d62ce..f2812af 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/textarea-pre-wrap-014.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/textarea-pre-wrap-014.html
@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>CSS Text level 3 Test: preserved white space at the end of and white-space:pre-wrap with justification in a textarea</title>
+<title>CSS Text level 3 Test: preserved white space at the end of soft-wrapped lines and white-space:pre-wrap with justification in a textarea</title>
 <link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
 <link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2">
-<link rel="match" href="reference/textarea-pre-wrap-001-ref.html">
-<meta name="assert" content="When white-space is pre-wrap, only spaces that overflow the line get collapsed or hanged, the ones that fit have an effect when justifying in a textarea.">
+<link rel="match" href="reference/textarea-pre-wrap-014-ref.html">
+<meta name="assert" content="When white-space is pre-wrap, spaces at the end of a soft-wrapped line get collapsed or hanged, and don't influence justification.">
 <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
 <style>
 textarea {
@@ -23,17 +23,15 @@
   font-family: Ahem;
   line-height: 1em;
   white-space: pre-wrap;
-  color: green;
+  color: white;
 
-  background: linear-gradient(red, red) 0 0/2ch 2ch no-repeat;
+  background: linear-gradient(red, red) 3ch 0/2ch 1ch no-repeat;
 
-  width: 3ch;
+  width: 4ch;
   text-align: justify;
-  text-justify: inter-character;
 }
 </style>
 <body>
-  <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p>
-  <textarea>X&#8203;X&#x20;
-X&#8203;X </textarea>
+  <p>Test passes if there is <strong>no red</strong> below.</p>
+  <textarea>X X X</textarea>
 </body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/white-space-intrinsic-size-004.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/white-space-intrinsic-size-004.html
index cc2d7399..a5be242 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/white-space-intrinsic-size-004.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/white-space-intrinsic-size-004.html
@@ -6,8 +6,7 @@
 <link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2">
 <meta name="flags" content="">
 <link rel="match" href="reference/white-space-intrinsic-size-004-ref.html">
-<meta name="assert" content="Preserved spaces at the end of the line do affect the intrinsic max-content size when white-space is pre-wrap, as hanging does not prevent contributing to the max-content size. The value of overflow-wrap makes no difference.">
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<meta name="assert" content="Preserved spaces at the end of the line do affect the intrinsic max-content size when white-space is pre-wrap, as spaces before a forced break, at the end of un unwrapped line, only hanging conditionally, which does not prevent contributing to the max-content size. The value of overflow-wrap makes no difference.">
 <style>
 aside {
   float: left;
@@ -18,10 +17,10 @@
 div {
   background: red;
   color: transparent;
-  font-family: Ahem;
+  font-family: monospace;
   font-size: 50px;
   width: 3ch;
-  height: 2em;
+  line-height: 1;
 }
 </style>
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/white-space-pre-wrap-trailing-spaces-001.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/white-space-pre-wrap-trailing-spaces-001.html
index ca6f65e..82fbfbc9 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/white-space-pre-wrap-trailing-spaces-001.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/white-space-pre-wrap-trailing-spaces-001.html
@@ -1,19 +1,18 @@
 <!doctype html>
 <meta charset=utf-8>
-<title>CSS Text test: hanging trailing spaces with white-space:pre-wrap</title>
+<title>CSS Text test: alignement and trailing spaces with white-space:pre-wrap</title>
 <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
 <link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2">
 <link rel="match" href="reference/white-space-pre-wrap-trailing-spaces-001-ref.html">
-<meta name="assert" content="Preserved white space at the end of the line is hanged when white-space is pre-wrap.">
+<meta name="assert" content="Preserved white space with pre-wrap at the end of a line ending with a forced line break conditionally hangs, so it does affect alignment.">
 
 <style>
 div {
   white-space: pre-wrap;
   font-family: monospace;
 }
-div:nth-of-type(1),
 div:nth-of-type(2) {
-  width: 5ch;
+  width: 7ch;
   text-align: right;
 }
 div:nth-of-type(3),
@@ -25,7 +24,7 @@
 
 <p>This test passes if the 4 letters below are verticaly aligned.
 
-<div>P</div>
-<div>A            </div>
-<div>S</div>
-<div>S           </div>
+<div>    P</div>
+<div>A  </div>
+<div>    S                                </div>
+<div> S </div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/white-space-pre-wrap-trailing-spaces-002.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/white-space-pre-wrap-trailing-spaces-002.html
index 76ca5ef7..f7e0f21 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/white-space-pre-wrap-trailing-spaces-002.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/white-space-pre-wrap-trailing-spaces-002.html
@@ -1,20 +1,28 @@
 <!doctype html>
 <meta charset=utf-8>
-<title>CSS Text test: intrinsic maximum sizing of trailing spaces with white-space:pre-wrap</title>
+<title>CSS Text test: intrinsic maximum sizing and alignment of trailing spaces with white-space:pre-wrap</title>
 <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
 <link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2">
 <link rel="match" href="reference/white-space-pre-wrap-trailing-spaces-002-ref.html">
-<meta name="assert" content="Hanging preserved white space at the end of the line when white-space is pre-wrap has no effect on the max-content size.">
-
+<meta name="assert" content="Preserved white space with white-space is pre-wrap at the end of the line before a forced-break only hangs conditionally, and therefore is included in the max-content size, and taken into account for alignemnt (since it doesn't actually hang in this situation).">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
 <style>
+div {
+  font-size: 20px;
+  font-family: Ahem;
+  line-height: 1em;
+  white-space: pre-wrap;
+}
 span {
   display: inline-block;
-  white-space: pre-wrap;
 }
 #s1 { text-align: right; }
 #s2 { text-align: center; }
+#test { color: orange; }
+#ref { color: blue; }
 </style>
 
-<p>This test passes if the letters below are spaced equally.
+<p>This test passes if the orange blocks below are vertically aligned with the blue ones.
 
-<div><span id=s1>X </span><span id=s2>X </span>X X</div>
+<div id=test><span id=s1>X </span><span id=s2> X </span> X  X</div>
+<div id=ref>X  X  X  X</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/white-space-pre-wrap-trailing-spaces-003.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/white-space-pre-wrap-trailing-spaces-003.html
index 15e47a7a..def9bca 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/white-space-pre-wrap-trailing-spaces-003.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/white-space-pre-wrap-trailing-spaces-003.html
@@ -4,7 +4,7 @@
 <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
 <link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2">
 <link rel="match" href="reference/white-space-pre-wrap-trailing-spaces-003-ref.html">
-<meta name="assert" content="Preserved white space at the end of the line is hanged when white-space is pre-wrap, and therefore does not count when computing the (minimum) intrinsic size.">
+<meta name="assert" content="Preserved white space at the end of soft-wrapped lines is hanged when white-space is pre-wrap, and therefore does not count when computing the (minimum) intrinsic size.">
 
 <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
 <style>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/white-space-pre-wrap-trailing-spaces-004.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/white-space-pre-wrap-trailing-spaces-004.html
index aa048b5..d271057c 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/white-space-pre-wrap-trailing-spaces-004.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/white-space-pre-wrap-trailing-spaces-004.html
@@ -4,7 +4,7 @@
 <link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com">
 <link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2">
 <link rel="match" href="reference/white-space-pre-wrap-trailing-spaces-004-ref.html">
-<meta name="assert" content="Preserved white space at the end of the line is hanged when white-space is pre-wrap.">
+<meta name="assert" content="Preserved white space at the end of a soft-wrapped line is hanged when white-space is pre-wrap.">
 <link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style>
 div {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/white-space-pre-wrap-trailing-spaces-005.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/white-space-pre-wrap-trailing-spaces-005.html
index 62ecb84..e10b4e1 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/white-space-pre-wrap-trailing-spaces-005.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/white-space-pre-wrap-trailing-spaces-005.html
@@ -4,7 +4,7 @@
 <link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
 <link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2">
 <link rel="match" href="reference/white-space-pre-wrap-trailing-spaces-004-ref.html">
-<meta name="assert" content="Preserved white space at the end of the line is hanged when white-space is pre-wrap.">
+<meta name="assert" content="Preserved white space at the end of a soft-wrapped line is hanged when white-space is pre-wrap.">
 <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
 <style>
 div {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/scale-interpolation.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/scale-interpolation.html
index 146575c9..c6fec26 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/scale-interpolation.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/scale-interpolation.html
@@ -9,9 +9,44 @@
     <script src="/resources/testharness.js"></script>
     <script src="/resources/testharnessreport.js"></script>
     <script src="/css/support/interpolation-testcommon.js"></script>
+    <style>
+    .parent {
+      scale: 0.5 1 2
+    }
+    .target {
+      width: 10px;
+      height: 10px;
+      background-color: black;
+      scale: 1.1 1;
+    }
+    .expected {
+      background-color: green;
+    }
+    </style>
   </head>
   <body>
+    <template id="target-template">
+      <div class="parent">
+        <div class="target"></div>
+      </div>
+    </template>
+
     <script>
+      // Matching two <number> version.
+      test_interpolation({
+        property: 'scale',
+        from: '-10 5',
+        to: '10 -5',
+      }, [
+        {at: -1, expect: '-30 15'},
+        {at: 0, expect: '-10 5'},
+        {at: 0.25, expect: '-5 2.5'},
+        {at: 0.75, expect: '5 -2.5'},
+        {at: 1, expect: '10 -5'},
+        {at: 2, expect: '30 -15'},
+      ]);
+
+      // Matching three <number> version.
       test_interpolation({
         property: 'scale',
         from: '2 30 400',
@@ -25,6 +60,7 @@
         {at: 2, expect: '18 190 2000'}
       ]);
 
+      // From three <number> to two <number>; test that it expands correctly.
       test_interpolation({
         property: 'scale',
         from: '26 17 9',
@@ -38,6 +74,48 @@
         {at: 2, expect: '-22 -15 -7'}
       ]);
 
+      // Test one <number> is expanded correctly.
+      test_interpolation({
+        property: 'scale',
+        from: '1',
+        to: '10 -5 0',
+      }, [
+        {at: -1, expect: '-8 7 2'},
+        {at: 0, expect: '1'},
+        {at: 0.25, expect: '3.25 -0.5 0.75'},
+        {at: 0.75, expect: '7.75 -3.5 0.25'},
+        {at: 1, expect: '10 -5 0'},
+        {at: 2, expect: '19 -11 -1'},
+      ]);
+
+      test_interpolation({
+        property: 'scale',
+        from: '-10 5 1',
+        to: '1',
+      }, [
+        {at: -1, expect: '-21 9 1'},
+        {at: 0, expect: '-10 5 1'},
+        {at: 0.25, expect: '-7.25 4 1'},
+        {at: 0.75, expect: '-1.75 2 1'},
+        {at: 1, expect: '1'},
+        {at: 2, expect: '12 -3 1'},
+      ]);
+
+      // Handling of the none value.
+      test_interpolation({
+        property: 'scale',
+        from: 'none',
+        to: 'none',
+      }, [
+        {at: -1, expect: 'none'},
+        {at: 0, expect: 'none'},
+        {at: 0.125, expect: 'none'},
+        {at: 0.875, expect: 'none'},
+        {at: 1, expect: 'none'},
+        {at: 2, expect: 'none'}
+      ]);
+
+      // Going from none to a valid value; test that it converts properly.
       test_interpolation({
         property: 'scale',
         from: 'none',
@@ -51,17 +129,114 @@
         {at: 2, expect: '7 5 3'}
       ]);
 
+      // Test neutral keyframe; make sure it adds the underlying.
       test_interpolation({
         property: 'scale',
-        from: 'none',
-        to: 'none',
+        from: neutralKeyframe,
+        to: '1.5 1',
       }, [
-        {at: -1, expect: 'none'},
+        {at: -1, expect: '0.7 1'},
+        {at: 0, expect: '1.1 1'},
+        {at: 0.25, expect: '1.2 1'},
+        {at: 0.75, expect: '1.4 1'},
+        {at: 1, expect: '1.5 1'},
+        {at: 2, expect: '1.9 1'},
+      ]);
+
+      // Test initial value; for 'scale' this is 'none'.
+      test_interpolation({
+        property: 'scale',
+        from: 'initial',
+        to: '2 0.5 1',
+      }, [
+        {at: -1, expect: '0 1.5 1'},
         {at: 0, expect: 'none'},
-        {at: 0.125, expect: 'none'},
-        {at: 0.875, expect: 'none'},
+        {at: 0.25, expect: '1.25 0.875 1'},
+        {at: 0.75, expect: '1.75 0.625 1'},
+        {at: 1, expect: '2 0.5 1'},
+        {at: 2, expect: '3 0 1'},
+      ]);
+
+      test_interpolation({
+        property: 'scale',
+        from: '2 0.5 1',
+        to: 'initial',
+      }, [
+        {at: -1, expect: '3 0 1'},
+        {at: 0, expect: '2 0.5 1'},
+        {at: 0.25, expect: '1.75 0.6251 1'},
+        {at: 0.75, expect: '1.25 0.875 1'},
         {at: 1, expect: 'none'},
-        {at: 2, expect: 'none'}
+        {at: 2, expect: '0 1.5 1'},
+      ]);
+
+
+      // Test unset value; for 'scale' this is 'none'.
+      test_interpolation({
+        property: 'scale',
+        from: 'unset',
+        to: '1.5 1',
+      }, [
+        {at: -1, expect: '0.5 1'},
+        {at: 0, expect: 'none'},
+        {at: 0.25, expect: '1.125 1'},
+        {at: 0.75, expect: '1.375 1'},
+        {at: 1, expect: '1.5 1'},
+        {at: 2, expect: '2 1'},
+      ]);
+
+      // Test inherited value.
+      test_interpolation({
+        property: 'scale',
+        from: 'inherit',
+        to: '2 0.5 1',
+      }, [
+        {at: -1, expect: '-1 1.5 3'},
+        {at: 0, expect: '0.5 1 2'},
+        {at: 0.25, expect: '0.875 0.875 1.75'},
+        {at: 0.75, expect: '1.625 0.625 1.25'},
+        {at: 1, expect: '2 0.5 1'},
+        {at: 2, expect: '3.5 0 0'},
+      ]);
+
+      test_interpolation({
+        property: 'scale',
+        from: '2 0.5 1',
+        to: 'inherit',
+      }, [
+        {at: -1, expect: '3.5 0 0'},
+        {at: 0, expect: '2 0.5 1'},
+        {at: 0.25, expect: '1.625 0.625 1.25'},
+        {at: 0.75, expect: '0.875 0.875 1.75'},
+        {at: 1, expect: '0.5 1 2'},
+        {at: 2, expect: '-1 1.5 3'},
+      ]);
+
+      // Test combination of initial and inherit.
+      test_interpolation({
+        property: 'scale',
+        from: 'initial',
+        to: 'inherit',
+      }, [
+        {at: -1, expect: '1.5 1 0'},
+        {at: 0, expect: 'none'},
+        {at: 0.25, expect: '0.875 1 1.25'},
+        {at: 0.75, expect: '0.625 1 1.75'},
+        {at: 1, expect: '0.5 1 2'},
+        {at: 2, expect: '0 1 3'},
+      ]);
+
+      test_interpolation({
+        property: 'scale',
+        from: 'inherit',
+        to: 'initial',
+      }, [
+        {at: -1, expect: '0 1 3'},
+        {at: 0, expect: '0.5 1 2'},
+        {at: 0.25, expect: '0.625 1 1.75'},
+        {at: 0.75, expect: '0.875 1 1.25'},
+        {at: 1, expect: 'none'},
+        {at: 2, expect: '1.5 1 0'},
       ]);
     </script>
   </body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-timing-function-computed.html b/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-timing-function-computed.html
index fa03b22..e57856b 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-timing-function-computed.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-timing-function-computed.html
@@ -26,6 +26,7 @@
 
 test_computed_value("transition-timing-function", "step-start", "steps(1, start)");
 test_computed_value("transition-timing-function", "step-end", "steps(1)");
+test_computed_value("transition-timing-function", "steps(4)");
 test_computed_value("transition-timing-function", "steps(4, start)");
 test_computed_value("transition-timing-function", "steps(2, end)", "steps(2)");
 test_computed_value("transition-timing-function", "steps(2, jump-start)");
diff --git a/third_party/blink/web_tests/external/wpt/dom/idlharness.window_exclude=Node-expected.txt b/third_party/blink/web_tests/external/wpt/dom/idlharness.window_exclude=Node-expected.txt
index 42cd0e0d..6609f69 100644
--- a/third_party/blink/web_tests/external/wpt/dom/idlharness.window_exclude=Node-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/dom/idlharness.window_exclude=Node-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 1209 tests; 1184 PASS, 25 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 1210 tests; 1184 PASS, 26 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS idl_test setup
 PASS Partial interface Window: original interface defined
 PASS Event interface: existence and properties of interface object
@@ -519,6 +519,7 @@
 PASS ShadowRoot interface: existence and properties of interface prototype object's @@unscopables property
 PASS ShadowRoot interface: attribute mode
 PASS ShadowRoot interface: attribute host
+FAIL ShadowRoot interface: attribute onslotchange assert_true: The prototype object must have a property "onslotchange" expected true got false
 PASS Element interface: existence and properties of interface object
 PASS Element interface object length
 PASS Element interface object name
diff --git a/third_party/blink/web_tests/external/wpt/feature-policy/resources/feature-policy-battery.html b/third_party/blink/web_tests/external/wpt/feature-policy/resources/feature-policy-battery.html
new file mode 100644
index 0000000..dff4b32
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/feature-policy/resources/feature-policy-battery.html
@@ -0,0 +1,9 @@
+<script>
+'use strict';
+
+Promise.resolve().then(() => navigator.getBattery()).then(battery => {
+  window.parent.postMessage({ enabled: true }, '*');
+}, error => {
+  window.parent.postMessage({ enabled: false }, '*');
+});
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/img.complete-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/img.complete-expected.txt
index 18aa059..d245e4d 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/img.complete-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/img.complete-expected.txt
@@ -10,7 +10,7 @@
 FAIL img src and srcset omitted on image after it started a load assert_true: expected true got false
 PASS async src complete test
 PASS async srcset complete test
-FAIL IDL attribute complete returns true when image resource has been fetched but not run yet & image is not in broken state assert_unreached: .complete didn't change to true Reached unreachable code
+PASS IDL attribute complete cannot "randomly" change during a task
 PASS async src broken test
 FAIL async src removal test assert_true: Should be complete, since we removed the src expected true got false
 FAIL async srcset removal test assert_true: Should be complete, since we removed the srcset expected true got false
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/img.complete.html b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/img.complete.html
index dcacf43..d8d5a84 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/img.complete.html
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/img.complete.html
@@ -1,9 +1,7 @@
 <!DOCTYPE HTML>
 <title>DOM img complete Test</title>
-<meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
+<meta charset=UTF-8>
 <link rel="author" title="Anselm Hannemann" href="http://anselm-hannemann.com/" />
-<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-img-complete" />
-<meta name="assert" content="Tests the complete status of the img-element">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 
@@ -82,42 +80,41 @@
   }, "img src and srcset omitted on image after it started a load");
 
   // test if set to true after img is completely available
-  var t = async_test("async src complete test");
-
-  t.step(function(){
+  async_test(t => {
     var loaded = false;
-    document.getElementById("imgTestTag3").onload = t.step_func_done(function(){
+    const img = document.getElementById("imgTestTag3");
+    img.onload = t.step_func_done(function(){
       assert_false(loaded);
       loaded = true;
-      assert_true(document.getElementById("imgTestTag3").complete);
-      var currentSrc = document.getElementById("imgTestTag3").currentSrc;
+      assert_true(img.complete);
+      var currentSrc = img.currentSrc;
       var expectedUrl = new URL("3.jpg", window.location);
       assert_equals(new URL(currentSrc).pathname, expectedUrl.pathname);
     }, "Only one onload, despite setting the src twice");
 
-    document.getElementById("imgTestTag3").src = 'test' + Math.random();
+    img.src = 'test' + Math.random();
     //test if img.complete is set to false if src is changed
-    assert_false(document.getElementById("imgTestTag3").complete, "src changed, should be set to false")
+    assert_false(img.complete, "src changed, should be set to false")
     //change src again, should make only one request as per 'await stable state'
-    document.getElementById("imgTestTag3").src = '3.jpg?nocache=' + Math.random();
-  });
+    img.src = '3.jpg?nocache=' + Math.random();
+  }, "async src complete test");
 
-  var t1 = async_test("async srcset complete test");
-  t1.step(function(){
+  async_test(t => {
     var loaded = false;
-    document.getElementById("imgTestTag5").onload = t1.step_func_done(function(){
+    const img = document.getElementById("imgTestTag5")
+    img.onload = t.step_func_done(function(){
       assert_false(loaded);
       loaded = true;
-      assert_true(document.getElementById("imgTestTag5").complete);
+      assert_true(img.complete);
     }, "Only one onload, despite setting the srcset twice");
     //Test if src, srcset is omitted
-    assert_true(document.getElementById("imgTestTag5").complete)
-    document.getElementById("imgTestTag5").srcset = "/images/green-256x256.png 1x";
+    assert_true(img.complete)
+    img.srcset = "/images/green-256x256.png 1x";
     //test if img.complete is set to false if srcset is present
-    assert_false(document.getElementById("imgTestTag5").complete, "srcset present, should be set to false");
+    assert_false(img.complete, "srcset present, should be set to false");
     //change src again, should make only one request as per 'await stable state'
-    document.getElementById("imgTestTag5").srcset="/images/green-256x256.png 1.6x"
-  });
+    img.srcset="/images/green-256x256.png 1.6x"
+  }, "async srcset complete test");
 
   // https://html.spec.whatwg.org/multipage/multipage/embedded-content-1.html#update-the-image-data
   // says to "await a stable state" before fetching so we use a separate <script>
@@ -125,86 +122,79 @@
 </script>
 <script>
   // test: The final task that is queued by the networking task source once the resource has been fetched has been queued, but has not yet been run, and the img element is not in the broken state
-  async_test(function(t) {
+  test(function() {
     assert_false(imageInstance.complete, "imageInstance.complete should be false");
     var startTime = Date.now();
     while (true) {
-      if (Date.now() - startTime > 2000)
-        assert_unreached('.complete didn\'t change to true');
-      if (imageInstance.complete === true) break;
+      if (Date.now() - startTime > 2000) {
+        assert_false(imageInstance.complete, "imageInstance.complete should remain false");
+        break;
+      }
+      if (imageInstance.complete === true) {
+        assert_unreached(".complete should not change within a task");
+      }
     }
-    t.done();
   },
-  'IDL attribute complete returns true when image resource has been fetched but not run yet & image is not in broken state');
+  'IDL attribute complete cannot "randomly" change during a task');
 
   // test if broken img does not pass
-  var t2 = async_test("async src broken test");
-  var img4 = document.getElementById("imgTestTag4");
+  async_test(t => {
+    const img = document.getElementById("imgTestTag4");
 
-  t2.step(
-    function(){
-    img4.src = 'brokenimg.jpg';
+    img.src = 'brokenimg.jpg';
 
     //test if img.complete is set to false if src is changed
-    assert_false(img4.complete, "src changed to broken img, should be set to false");
-  });
+    assert_false(img.complete, "src changed to broken img, should be set to false");
 
-  img4.onload = img4.onerror = t2.step_func(function(event){
-    assert_equals(event.type, "error");
-    assert_true(img4.complete);
-    t2.done();
-  });
+    img.onload = img.onerror = t.step_func_done(function(event){
+      assert_equals(event.type, "error");
+      assert_true(img.complete);
+    });
+  }, "async src broken test");
 
-  var t3 = async_test("async src removal test");
-  t3.step(function() {
+  async_test(t => {
     var img = document.createElement("img");
     assert_true(img.complete);
     img.src = `3.jpg?nocache=${Math.random()}`;
     assert_false(img.complete);
-    img.onload = this.step_func_done(() => {
+    img.onload = t.step_func_done(() => {
       assert_true(img.complete);
       img.removeAttribute("src");
       assert_true(img.complete, "Should be complete, since we removed the src");
     });
-  });
+  }, "async src removal test");
 
-  var t4 = async_test("async srcset removal test");
-  t4.step(function() {
+  async_test(t => {
     var img = document.createElement("img");
     assert_true(img.complete);
     img.srcset = `3.jpg?nocache=${Math.random()} 1x`;
     assert_false(img.complete);
-    img.onload = this.step_func_done(() => {
+    img.onload = t.step_func_done(() => {
       assert_true(img.complete);
       img.removeAttribute("srcset");
       assert_true(img.complete, "Should be complete, since we removed the srcset");
     });
-  });
+  }, "async srcset removal test");
 
-  var t5 = async_test("async src available image lookup test");
-  t5.step(function() {
+  async_test(t => {
     var preload = document.createElement("img");
     var url = `3.jpg?nocache=${Math.random()}`;
     preload.src = url;
-    preload.onload = this.step_func_done(function() {
+    preload.onload = t.step_func_done(function() {
       var img = document.createElement("img");
       assert_true(img.complete);
       img.src = url;
       assert_true(img.complete, "Should be complete because we should hit the available image cache");
     });
-  });
+  }, "async src available image lookup test");
 
-  var t6 = async_test("async pending request test");
-  t6.step(function() {
+  async_test(t => {
     var img = document.createElement("img");
     img.src = `3.jpg?nocache=${Math.random()}`;
-    img.onload = this.step_func_done(function() {
+    img.onload = t.step_func_done(function() {
       assert_true(img.complete);
       img.src = `3.jpg?nocache=${Math.random()}`;
-      // This is not strictly per spec, but that's a spec bug.  See
-      // https://github.com/whatwg/html/issues/4884
       assert_false(img.complete, "Should not be complete because we have started a new load");
     });
-  });
-
+  }, "async pending request test");
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/animation-worklet.idl b/third_party/blink/web_tests/external/wpt/interfaces/css-animation-worklet.idl
similarity index 92%
rename from third_party/blink/web_tests/external/wpt/interfaces/animation-worklet.idl
rename to third_party/blink/web_tests/external/wpt/interfaces/css-animation-worklet.idl
index 02deca73..4aca84e 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/animation-worklet.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/css-animation-worklet.idl
@@ -1,7 +1,7 @@
 // GENERATED CONTENT - DO NOT EDIT
 // Content was automatically extracted by Reffy into reffy-reports
 // (https://github.com/tidoust/reffy-reports)
-// Source: CSS Animation Worklet API (https://wicg.github.io/animation-worklet/)
+// Source: CSS Animation Worklet API (https://drafts.css-houdini.org/css-animationworklet-1/)
 
 [Exposed=Window]
 partial namespace CSS {
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/dom.idl b/third_party/blink/web_tests/external/wpt/interfaces/dom.idl
index 03a0201b..d1557a6 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/dom.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/dom.idl
@@ -3,9 +3,10 @@
 // (https://github.com/tidoust/reffy-reports)
 // Source: DOM Standard (https://dom.spec.whatwg.org/)
 
-[Constructor(DOMString type, optional EventInit eventInitDict = {}),
- Exposed=(Window,Worker,AudioWorklet)]
+[Exposed=(Window,Worker,AudioWorklet)]
 interface Event {
+  constructor(DOMString type, optional EventInit eventInitDict = {});
+
   readonly attribute DOMString type;
   readonly attribute EventTarget? target;
   readonly attribute EventTarget? srcElement; // historical
@@ -45,9 +46,10 @@
   [Replaceable] readonly attribute any event; // historical
 };
 
-[Constructor(DOMString type, optional CustomEventInit eventInitDict = {}),
- Exposed=(Window,Worker)]
+[Exposed=(Window,Worker)]
 interface CustomEvent : Event {
+  constructor(DOMString type, optional CustomEventInit eventInitDict = {});
+
   readonly attribute any detail;
 
   void initCustomEvent(DOMString type, optional boolean bubbles = false, optional boolean cancelable = false, optional any detail = null);
@@ -57,9 +59,10 @@
   any detail = null;
 };
 
-[Constructor,
- Exposed=(Window,Worker,AudioWorklet)]
+[Exposed=(Window,Worker,AudioWorklet)]
 interface EventTarget {
+  constructor();
+
   void addEventListener(DOMString type, EventListener? callback, optional (AddEventListenerOptions or boolean) options = {});
   void removeEventListener(DOMString type, EventListener? callback, optional (EventListenerOptions or boolean) options = {});
   boolean dispatchEvent(Event event);
@@ -78,13 +81,15 @@
   boolean once = false;
 };
 
-[Constructor,
- Exposed=(Window,Worker)]
+[Exposed=(Window,Worker)]
 interface AbortController {
+  constructor();
+
   [SameObject] readonly attribute AbortSignal signal;
 
   void abort();
 };
+
 [Exposed=(Window,Worker)]
 interface AbortSignal : EventTarget {
   readonly attribute boolean aborted;
@@ -155,9 +160,10 @@
   getter Element? namedItem(DOMString name);
 };
 
-[Constructor(MutationCallback callback),
- Exposed=Window]
+[Exposed=Window]
 interface MutationObserver {
+  constructor(MutationCallback callback);
+
   void observe(Node target, optional MutationObserverInit options = {});
   void disconnect();
   sequence<MutationRecord> takeRecords();
@@ -250,9 +256,10 @@
   boolean composed = false;
 };
 
-[Constructor,
- Exposed=Window]
+[Exposed=Window]
 interface Document : Node {
+  constructor();
+
   [SameObject] readonly attribute DOMImplementation implementation;
   readonly attribute USVString URL;
   readonly attribute USVString documentURI;
@@ -315,15 +322,16 @@
   readonly attribute DOMString systemId;
 };
 
-[Constructor,
- Exposed=Window]
+[Exposed=Window]
 interface DocumentFragment : Node {
+  constructor();
 };
 
 [Exposed=Window]
 interface ShadowRoot : DocumentFragment {
   readonly attribute ShadowRootMode mode;
   readonly attribute Element host;
+  attribute EventHandler onslotchange;
 };
 
 enum ShadowRootMode { "open", "closed" };
@@ -376,6 +384,7 @@
 
 dictionary ShadowRootInit {
   required ShadowRootMode mode;
+  boolean delegatesFocus = false;
 };
 
 [Exposed=Window,
@@ -414,12 +423,14 @@
   void replaceData(unsigned long offset, unsigned long count, DOMString data);
 };
 
-[Constructor(optional DOMString data = ""),
- Exposed=Window]
+[Exposed=Window]
 interface Text : CharacterData {
+  constructor(optional DOMString data = "");
+
   [NewObject] Text splitText(unsigned long offset);
   readonly attribute DOMString wholeText;
 };
+
 [Exposed=Window]
 interface CDATASection : Text {
 };
@@ -427,9 +438,9 @@
 interface ProcessingInstruction : CharacterData {
   readonly attribute DOMString target;
 };
-[Constructor(optional DOMString data = ""),
- Exposed=Window]
+[Exposed=Window]
 interface Comment : CharacterData {
+  constructor(optional DOMString data = "");
 };
 
 [Exposed=Window]
@@ -448,14 +459,15 @@
   required unsigned long endOffset;
 };
 
-[Constructor(StaticRangeInit init),
- Exposed=Window]
+[Exposed=Window]
 interface StaticRange : AbstractRange {
+  constructor(StaticRangeInit init);
 };
 
-[Constructor,
- Exposed=Window]
+[Exposed=Window]
 interface Range : AbstractRange {
+  constructor();
+
   readonly attribute Node commonAncestorContainer;
 
   void setStart(Node node, unsigned long offset);
@@ -602,7 +614,9 @@
 };
 Document includes XPathEvaluatorBase;
 
-[Exposed=Window, Constructor]
-interface XPathEvaluator {};
+[Exposed=Window]
+interface XPathEvaluator {
+  constructor();
+};
 
 XPathEvaluator includes XPathEvaluatorBase;
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/scroll-animations.idl b/third_party/blink/web_tests/external/wpt/interfaces/scroll-animations.idl
index f2560d9..8fd67a7a 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/scroll-animations.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/scroll-animations.idl
@@ -1,7 +1,7 @@
 // GENERATED CONTENT - DO NOT EDIT
 // Content was automatically extracted by Reffy into reffy-reports
 // (https://github.com/tidoust/reffy-reports)
-// Source: Scroll-linked Animations (https://wicg.github.io/scroll-animations/)
+// Source: Scroll-linked Animations (https://drafts.csswg.org/scroll-animations-1/)
 
 enum ScrollDirection {
   "block",
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-reporting.tentative.https.html b/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-reporting.tentative.https.html
index 16e6d2a7..11ef305 100644
--- a/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-reporting.tentative.https.html
+++ b/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-reporting.tentative.https.html
@@ -54,6 +54,24 @@
     try { fn(); assert_unreached(); } catch (err) { /* ignore */ }
   }
 
+  // Test the "sample" field of the event.
+  // TODO(vogelheim): The current set of tests allows for more variance in the
+  //     sample reports than the current spec draft does. Once the spec has
+  //     been finalized, we should clamp this down to check byte-for-byte
+  //     against the values mandated by the spec.
+
+  function expect_sample(s) { return e => {
+    assert_true(e.sample.includes(s),
+                `expected "${e.sample}" to include "${s}".`);
+    return e;
+  } }
+
+  function expect_blocked_uri(s) { return e => {
+    assert_true(e.blockedURI === s,
+                `expected "${e.blockedUri}" to be "${s}".`);
+    return e;
+  } }
+
   // A sample policy we use to test TrustedTypes.createPolicy behaviour.
   const id = x => x;
   const a_policy = {
@@ -80,6 +98,8 @@
     let p = Promise.resolve()
         .then(promise_violation("trusted-types one"))
         .then(promise_violation("trusted-types two"))
+        .then(expect_sample("three"))
+        .then(expect_blocked_uri("trusted-types-policy"))
         .then(promise_flush());
     expect_throws(_ => TrustedTypes.createPolicy("three", a_policy));
     flush();
@@ -131,18 +151,6 @@
     return p;
   }, "Trusted Type violation report: assign trusted HTML to html; no report");
 
-  // Test the "sample" field of the event.
-  // TODO(vogelheim): The current set of tests allows for more variance in the
-  //     sample reports than the current spec draft does. Once the spec has
-  //     been finalized, we should clamp this down to check byte-for-byte
-  //     against the values mandated by the spec.
-
-  function expect_sample(s) { return e => {
-    assert_true(e.sample.includes(s),
-                `expected "${e.sample}" to include "${s}".`);
-    return e;
-  } }
-
   promise_test(t => {
     let p = Promise.resolve()
         .then(promise_violation("trusted-types two"))
diff --git a/third_party/blink/web_tests/external/wpt/uievents/click/auxclick_event.html b/third_party/blink/web_tests/external/wpt/uievents/click/auxclick_event.html
index 9f4ffed..8bb2e13 100644
--- a/third_party/blink/web_tests/external/wpt/uievents/click/auxclick_event.html
+++ b/third_party/blink/web_tests/external/wpt/uievents/click/auxclick_event.html
@@ -23,6 +23,7 @@
     <div id="target"></div>
     <script>
     var test_auxclick = async_test("auxclick event sequence received.");
+    var actions_promise;
     var target = document.querySelector('#target');
     document.addEventListener('contextmenu', event => { event.preventDefault(); });
     ['click', 'dblclick'].forEach(eventName => {
@@ -60,13 +61,16 @@
                     'There should be two auxclick events for a non-primary button double click each preceded by one mousemove and one mouseup');
                 assert_equals(event.detail, click_count, 'detail attribute of auxclick should be the click count.');
             });
-            test_auxclick.done();
+            // Make sure the test finishes after all the input actions are completed.
+            actions_promise.then( () => {
+                test_auxclick.done();
+            });
         }
     });
 
     // Inject mouse double click events.
     var actions = new test_driver.Actions();
-    actions.pointerMove(0, 0, {origin: target})
+    actions_promise = actions.pointerMove(0, 0, {origin: target})
            .pointerDown({button: actions.ButtonType.MIDDLE})
            .pointerUp({button: actions.ButtonType.MIDDLE})
            .pointerDown({button: actions.ButtonType.MIDDLE})
diff --git a/third_party/blink/web_tests/external/wpt/uievents/click/click_event_target_child_parent.html b/third_party/blink/web_tests/external/wpt/uievents/click/click_event_target_child_parent.html
index 1e07e43..a09e553 100644
--- a/third_party/blink/web_tests/external/wpt/uievents/click/click_event_target_child_parent.html
+++ b/third_party/blink/web_tests/external/wpt/uievents/click/click_event_target_child_parent.html
@@ -38,6 +38,7 @@
     <button id="done">Done</button>
     <script>
     var test_click_target = async_test("Click targets the nearest common ancestor");
+    var actions_promise;
 
     // Prevent drag to avoid interfering with the click.
     document.addEventListener('dragstart', (e) => e.preventDefault());
@@ -59,12 +60,15 @@
         "mousedown@link1,mouseup@link_container1,click@link_container1,mousedown@link_container2,mouseup@link2,click@link_container2",
         "Click should be sent to the nearest common ancestor");
       });
-      test_click_target.done();
+      // Make sure the test finishes after all the input actions are completed.
+      actions_promise.then( () => {
+        test_click_target.done();
+      });
     });
 
     // Inject mouse events.
     var actions = new test_driver.Actions();
-    actions.pointerMove(0, 0, {origin: document.getElementById('link1')})
+    actions_promise = actions.pointerMove(0, 0, {origin: document.getElementById('link1')})
            .pointerDown()
            .pointerMove(0, 0, {origin: document.getElementById('link_container1')})
            .pointerUp()
diff --git a/third_party/blink/web_tests/external/wpt/uievents/click/click_event_target_siblings.html b/third_party/blink/web_tests/external/wpt/uievents/click/click_event_target_siblings.html
index 0306b6f..24d64dc 100644
--- a/third_party/blink/web_tests/external/wpt/uievents/click/click_event_target_siblings.html
+++ b/third_party/blink/web_tests/external/wpt/uievents/click/click_event_target_siblings.html
@@ -51,6 +51,7 @@
     <button id="done">Done</button>
     <script>
     var test_click_target = async_test("Click targets the nearest common ancestor");
+    var actions_promise;
 
     // Prevent drag to avoid interfering with the click.
     document.addEventListener('dragstart', (e) => e.preventDefault());
@@ -72,12 +73,15 @@
         "mousedown@red_div,mouseup@blue_div,click@div_container,mousedown@button1,mouseup@button2,click@button_container,mousedown@link1,mouseup@link2,click@link_container",
         "Click should be sent to the nearest common ancestor");
       });
-      test_click_target.done();
+      // Make sure the test finishes after all the input actions are completed.
+      actions_promise.then( () => {
+        test_click_target.done();
+      });
     });
 
     // Inject mouse events.
     var actions = new test_driver.Actions();
-    actions.pointerMove(0, 0, {origin: document.getElementById('red_div')})
+    actions_promise = actions.pointerMove(0, 0, {origin: document.getElementById('red_div')})
            .pointerDown()
            .pointerMove(0, 0, {origin: document.getElementById('blue_div')})
            .pointerUp()
diff --git a/third_party/blink/web_tests/external/wpt/uievents/click/mouse-dblclick-event.html b/third_party/blink/web_tests/external/wpt/uievents/click/mouse-dblclick-event.html
index 5bf0bbc..31a600b 100644
--- a/third_party/blink/web_tests/external/wpt/uievents/click/mouse-dblclick-event.html
+++ b/third_party/blink/web_tests/external/wpt/uievents/click/mouse-dblclick-event.html
@@ -25,15 +25,19 @@
         function run() {
             var testDoubleClick = async_test('Tests that the double click event is correctly generated by sending pointerDown, pointerUp, pointerDown and pointerUp for the mouse type.');
             var elem = document.getElementById("click_area");
+            var actions_promise;
             elem.addEventListener('dblclick', function(e) {
                 testDoubleClick.step(function () {
                   assert_equals(e.target.id, "click_area");
                   assert_equals(e.detail, 2);
                 });
-                testDoubleClick.done();
+                // Make sure the test finishes after all the input actions are completed.
+                actions_promise.then( () => {
+                  testDoubleClick.done();
+                });
             });
 
-            new test_driver.Actions()
+            actions_promise = new test_driver.Actions()
               .pointerMove(0, 0, {origin: elem})
               .pointerDown()
               .pointerUp()
diff --git a/third_party/blink/web_tests/external/wpt/uievents/mouse/mouse_buttons_back_forward.html b/third_party/blink/web_tests/external/wpt/uievents/mouse/mouse_buttons_back_forward.html
index 787abac..2323bc1 100644
--- a/third_party/blink/web_tests/external/wpt/uievents/mouse/mouse_buttons_back_forward.html
+++ b/third_party/blink/web_tests/external/wpt/uievents/mouse/mouse_buttons_back_forward.html
@@ -15,6 +15,7 @@
             var received_forward = false;
             const backButton = 3;
             const forwardButton = 4;
+            var actions_promise;
             window.addEventListener('mouseup', function(e) {
               if (e.button == backButton) {
                 received_back = true;
@@ -24,14 +25,17 @@
                 e.preventDefault();
               }
               if (received_back && received_forward) {
-                testMouseUp.done();
+                // Make sure the test finishes after all the input actions are completed.
+                actions_promise.then( () => {
+                  testMouseUp.done();
+                });
               }
             });
 
             function inject_input() {
                 // First click on back button and then forward button.
                 var actions = new test_driver.Actions();
-                actions.pointerMove(0, 0, {origin: target})
+                actions_promise = actions.pointerMove(0, 0, {origin: target})
                     .pointerDown({button: actions.ButtonType.BACK})
                     .pointerUp({button: actions.ButtonType.BACK})
                     .pointerDown({button: actions.ButtonType.FORWARD})
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/animation-model/keyframe-effects/effect-value-context-filling-expected.txt b/third_party/blink/web_tests/external/wpt/web-animations/animation-model/keyframe-effects/effect-value-context-filling-expected.txt
index c0b9a11f5..52b57b2 100644
--- a/third_party/blink/web_tests/external/wpt/web-animations/animation-model/keyframe-effects/effect-value-context-filling-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/web-animations/animation-model/keyframe-effects/effect-value-context-filling-expected.txt
@@ -4,7 +4,7 @@
 PASS Filling effect values reflect changes to variables on element
 PASS Filling effect values reflect changes to variables on parent element
 PASS Filling effect values reflect changes to the the animation's keyframes
-FAIL Filling effect values reflect changes to the the animation's composite mode assert_equals: Effect value after updating the composite mode expected "300px" but got "200px"
+PASS Filling effect values reflect changes to the the animation's composite mode
 FAIL Filling effect values reflect changes to the the animation's iteration composite mode assert_equals: Effect value after updating the iteration composite mode expected "200px" but got "100px"
 PASS Filling effect values reflect changes to the base value when using additive animation
 PASS Filling effect values reflect changes to the base value when using additive animation on a single keyframe
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/interfaces/Animatable/getAnimations-expected.txt b/third_party/blink/web_tests/external/wpt/web-animations/interfaces/Animatable/getAnimations-expected.txt
index 35c5a82..eef153d 100644
--- a/third_party/blink/web_tests/external/wpt/web-animations/interfaces/Animatable/getAnimations-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/web-animations/interfaces/Animatable/getAnimations-expected.txt
@@ -12,7 +12,7 @@
 PASS Returns animations yet to reach their active phase
 PASS Does not return reversed finished animations that do not fill backwards
 PASS Returns reversed finished animations that fill backwards
-FAIL Returns reversed animations yet to reach their active phase assert_array_equals: lengths differ, expected 1 got 0
+PASS Returns reversed animations yet to reach their active phase
 PASS Does not return animations with zero playback rate in before phase
 PASS Does not return animations with zero playback rate in after phase
 PASS Returns animations based on dynamic changes to individual animations' duration
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-001-expected.txt b/third_party/blink/web_tests/external/wpt/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-001-expected.txt
deleted file mode 100644
index 5b5ccfe7..0000000
--- a/third_party/blink/web_tests/external/wpt/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-001-expected.txt
+++ /dev/null
@@ -1,74 +0,0 @@
-This is a testharness.js-based test.
-Found 70 tests; 68 PASS, 2 FAIL, 0 TIMEOUT, 0 NOTRUN.
-PASS non-animatable property 'animation' is not accessed when using a property-indexed keyframe object
-PASS non-animatable property 'animationDelay' is not accessed when using a property-indexed keyframe object
-PASS non-animatable property 'animationDirection' is not accessed when using a property-indexed keyframe object
-PASS non-animatable property 'animationDuration' is not accessed when using a property-indexed keyframe object
-PASS non-animatable property 'animationFillMode' is not accessed when using a property-indexed keyframe object
-PASS non-animatable property 'animationIterationCount' is not accessed when using a property-indexed keyframe object
-PASS non-animatable property 'animationName' is not accessed when using a property-indexed keyframe object
-PASS non-animatable property 'animationPlayState' is not accessed when using a property-indexed keyframe object
-PASS non-animatable property 'animationTimingFunction' is not accessed when using a property-indexed keyframe object
-PASS non-animatable property 'transition' is not accessed when using a property-indexed keyframe object
-PASS non-animatable property 'transitionDelay' is not accessed when using a property-indexed keyframe object
-PASS non-animatable property 'transitionDuration' is not accessed when using a property-indexed keyframe object
-PASS non-animatable property 'transitionProperty' is not accessed when using a property-indexed keyframe object
-PASS non-animatable property 'transitionTimingFunction' is not accessed when using a property-indexed keyframe object
-PASS non-animatable property 'contain' is not accessed when using a property-indexed keyframe object
-PASS non-animatable property 'direction' is not accessed when using a property-indexed keyframe object
-PASS non-animatable property 'display' is not accessed when using a property-indexed keyframe object
-PASS non-animatable property 'textOrientation' is not accessed when using a property-indexed keyframe object
-PASS non-animatable property 'unicodeBidi' is not accessed when using a property-indexed keyframe object
-PASS non-animatable property 'willChange' is not accessed when using a property-indexed keyframe object
-PASS non-animatable property 'writingMode' is not accessed when using a property-indexed keyframe object
-PASS non-animatable property 'unsupportedProperty' is not accessed when using a property-indexed keyframe object
-FAIL non-animatable property 'float' is not accessed when using a property-indexed keyframe object assert_equals: Accessor not called expected 0 but got 1
-PASS non-animatable property 'font-size' is not accessed when using a property-indexed keyframe object
-PASS non-animatable property 'animation' is not accessed when using a keyframe sequence
-PASS non-animatable property 'animationDelay' is not accessed when using a keyframe sequence
-PASS non-animatable property 'animationDirection' is not accessed when using a keyframe sequence
-PASS non-animatable property 'animationDuration' is not accessed when using a keyframe sequence
-PASS non-animatable property 'animationFillMode' is not accessed when using a keyframe sequence
-PASS non-animatable property 'animationIterationCount' is not accessed when using a keyframe sequence
-PASS non-animatable property 'animationName' is not accessed when using a keyframe sequence
-PASS non-animatable property 'animationPlayState' is not accessed when using a keyframe sequence
-PASS non-animatable property 'animationTimingFunction' is not accessed when using a keyframe sequence
-PASS non-animatable property 'transition' is not accessed when using a keyframe sequence
-PASS non-animatable property 'transitionDelay' is not accessed when using a keyframe sequence
-PASS non-animatable property 'transitionDuration' is not accessed when using a keyframe sequence
-PASS non-animatable property 'transitionProperty' is not accessed when using a keyframe sequence
-PASS non-animatable property 'transitionTimingFunction' is not accessed when using a keyframe sequence
-PASS non-animatable property 'contain' is not accessed when using a keyframe sequence
-PASS non-animatable property 'direction' is not accessed when using a keyframe sequence
-PASS non-animatable property 'display' is not accessed when using a keyframe sequence
-PASS non-animatable property 'textOrientation' is not accessed when using a keyframe sequence
-PASS non-animatable property 'unicodeBidi' is not accessed when using a keyframe sequence
-PASS non-animatable property 'willChange' is not accessed when using a keyframe sequence
-PASS non-animatable property 'writingMode' is not accessed when using a keyframe sequence
-PASS non-animatable property 'unsupportedProperty' is not accessed when using a keyframe sequence
-FAIL non-animatable property 'float' is not accessed when using a keyframe sequence assert_equals: Accessor not called expected 0 but got 1
-PASS non-animatable property 'font-size' is not accessed when using a keyframe sequence
-PASS Equivalent property-indexed and sequenced keyframes: two properties with one value
-PASS Equivalent property-indexed and sequenced keyframes: two properties with three values
-PASS Equivalent property-indexed and sequenced keyframes: two properties with different numbers of values
-PASS Equivalent property-indexed and sequenced keyframes: same easing applied to all keyframes
-PASS Equivalent property-indexed and sequenced keyframes: same composite applied to all keyframes
-PASS Keyframes are read from a custom iterator
-PASS 'easing' and 'offset' are ignored on iterable objects
-PASS Keyframes are read from a custom iterator with multiple properties specified
-PASS Keyframes are read from a custom iterator with where an offset is specified
-PASS If a keyframe throws for an animatable property, that exception should be propagated
-PASS Reading from a custom iterator that returns a non-object keyframe should throw
-PASS An undefined keyframe returned from a custom iterator should be treated as a default keyframe
-PASS A null keyframe returned from a custom iterator should be treated as a default keyframe
-PASS A list of values returned from a custom iterator should be ignored
-PASS If a custom iterator throws from next(), the exception should be rethrown
-PASS Accessing a Symbol.iterator property that throws should rethrow
-PASS A non-object returned from the Symbol.iterator property should cause a TypeError to be thrown
-PASS Only enumerable properties on keyframes are read
-PASS Only properties defined directly on keyframes are read
-PASS Only enumerable properties on property-indexed keyframes are read
-PASS Only properties defined directly on property-indexed keyframes are read
-PASS Properties are read in ascending order by Unicode codepoint
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/worklets/animation-worklet-referrer.https.html b/third_party/blink/web_tests/external/wpt/worklets/animation-worklet-referrer.https.html
index 494e06a..49933de 100644
--- a/third_party/blink/web_tests/external/wpt/worklets/animation-worklet-referrer.https.html
+++ b/third_party/blink/web_tests/external/wpt/worklets/animation-worklet-referrer.https.html
@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html>
 <head>
+    <meta name="timeout" content="long">
     <script src="/common/get-host-info.sub.js"></script>
     <script src="/resources/testharness.js"></script>
     <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/worklets/audio-worklet-referrer.https.html b/third_party/blink/web_tests/external/wpt/worklets/audio-worklet-referrer.https.html
index f258cd5..61cb63d 100644
--- a/third_party/blink/web_tests/external/wpt/worklets/audio-worklet-referrer.https.html
+++ b/third_party/blink/web_tests/external/wpt/worklets/audio-worklet-referrer.https.html
@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html>
 <head>
+    <meta name="timeout" content="long">
     <script src="/common/get-host-info.sub.js"></script>
     <script src="/resources/testharness.js"></script>
     <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/worklets/layout-worklet-referrer.https.html b/third_party/blink/web_tests/external/wpt/worklets/layout-worklet-referrer.https.html
index cb383a9..dc7b84b 100644
--- a/third_party/blink/web_tests/external/wpt/worklets/layout-worklet-referrer.https.html
+++ b/third_party/blink/web_tests/external/wpt/worklets/layout-worklet-referrer.https.html
@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html>
 <head>
+    <meta name="timeout" content="long">
     <script src="/common/get-host-info.sub.js"></script>
     <script src="/resources/testharness.js"></script>
     <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/worklets/paint-worklet-referrer.https.html b/third_party/blink/web_tests/external/wpt/worklets/paint-worklet-referrer.https.html
index a4b5a6f49..8f3d82a 100644
--- a/third_party/blink/web_tests/external/wpt/worklets/paint-worklet-referrer.https.html
+++ b/third_party/blink/web_tests/external/wpt/worklets/paint-worklet-referrer.https.html
@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html>
 <head>
+    <meta name="timeout" content="long">
     <script src="/common/get-host-info.sub.js"></script>
     <script src="/resources/testharness.js"></script>
     <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/blink/web_tests/fast/scrolling/scrollbars/mouse-scrolling-on-div-scrollbar.html b/third_party/blink/web_tests/fast/scrolling/scrollbars/mouse-scrolling-on-div-scrollbar.html
index 6e5f221..195453e 100644
--- a/third_party/blink/web_tests/fast/scrolling/scrollbars/mouse-scrolling-on-div-scrollbar.html
+++ b/third_party/blink/web_tests/fast/scrolling/scrollbars/mouse-scrolling-on-div-scrollbar.html
@@ -132,6 +132,35 @@
     await waitForCompositorCommit();
     resetScrollOffset(standardDivFast);
 
+    // Testing forward scroll on vertical scrollbar.
+    let x = standardRectFast.right - BUTTON_WIDTH / 2;
+    let y = standardRectFast.top + 50;
+    await mouseClickOn(x, y, /*left_click*/0, /*modifier*/ "Shift");
+    assert_equals(standardDivFast.scrollTop, 617, "Shift + click forward didn't scroll.");
+
+    // Testing backward scroll on vertical scrollbar.
+    x = standardRectFast.right - BUTTON_WIDTH / 2;
+    y = standardRectFast.top + 30;
+    await mouseClickOn(x, y, /*left_click*/0, /*modifier*/ "Shift");
+    assert_equals(standardDivFast.scrollTop, 160, "Shift + click backward didn't scroll.");
+
+    // Testing forward scroll on horizontal scrollbar.
+    x = standardRectFast.left + 50;
+    y = standardRectFast.bottom - BUTTON_WIDTH / 2;
+    await mouseClickOn(x, y, /*left_click*/0, /*modifier*/ "Shift");
+    assert_equals(standardDivFast.scrollLeft, 617, "Shift + click forward didn't scroll.");
+
+    // Testing backward scroll on horizontal scrollbar.
+    x = standardRectFast.left + 30;
+    y = standardRectFast.bottom - BUTTON_WIDTH / 2;
+    await mouseClickOn(x, y, /*left_click*/0, /*modifier*/ "Shift");
+    assert_equals(standardDivFast.scrollLeft, 160, "Shift + click backward didn't scroll.");
+  }, "Test shift + click on non-custom composited scrollbars.");
+
+  promise_test (async () => {
+    await waitForCompositorCommit();
+    resetScrollOffset(standardDivFast);
+
     // Testing the vertical scrollbar thumb.
     let x = standardRectFast.right - TRACK_WIDTH / 2;
     let y = standardRectFast.top + BUTTON_WIDTH + 5;
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/resources/inspector-protocol-test.js b/third_party/blink/web_tests/http/tests/inspector-protocol/resources/inspector-protocol-test.js
index c842f58b..ade00e1 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/resources/inspector-protocol-test.js
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/resources/inspector-protocol-test.js
@@ -140,22 +140,6 @@
     return eval(`${source}\n//# sourceURL=${url}`);
   };
 
-  async loadScriptModule(path) {
-    const source = await this._fetch(this._testBaseURL + path);
-
-    return new Promise((resolve, reject) => {
-      const src = URL.createObjectURL(new Blob([source], { type: 'application/javascript' }));
-      const script = Object.assign(document.createElement('script'), {
-        src,
-        type: 'module',
-        onerror: reject,
-        onload: resolve
-      });
-
-      document.head.appendChild(script);
-    })
-  };
-
   browserP() {
     return this._browserSession.protocol;
   }
diff --git a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index b61487d..a8f015f 100644
--- a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -736,6 +736,7 @@
 interface IDBTransaction : EventTarget
     attribute @@toStringTag
     getter db
+    getter durability
     getter error
     getter mode
     getter objectStoreNames
diff --git a/third_party/blink/web_tests/inspector-protocol/heap-profiler/resources/heap-snapshot-common.js b/third_party/blink/web_tests/inspector-protocol/heap-profiler/resources/heap-snapshot-common.js
index 17053bf..6239b7f 100644
--- a/third_party/blink/web_tests/inspector-protocol/heap-profiler/resources/heap-snapshot-common.js
+++ b/third_party/blink/web_tests/inspector-protocol/heap-profiler/resources/heap-snapshot-common.js
@@ -6,18 +6,12 @@
 
   // This script is supposed to be evaluated in inspector-protocol/heap-profiler tests
   // and the relative paths below are relative to that location.
-  await testRunner.loadScriptModule(
-      '../../../../blink/renderer/devtools/front_end/platform/utilities.js');
-  await testRunner.loadScriptModule(
-      '../../../../blink/renderer/devtools/front_end/common/UIString.js');
-  await testRunner.loadScriptModule(
-      '../../../../blink/renderer/devtools/front_end/heap_snapshot_model/HeapSnapshotModel.js');
-  await testRunner.loadScriptModule(
-      '../../../../blink/renderer/devtools/front_end/heap_snapshot_worker/HeapSnapshot.js');
-  await testRunner.loadScriptModule(
-      '../../../../blink/renderer/devtools/front_end/text_utils/TextUtils.js');
-  await testRunner.loadScriptModule(
-      '../../../../blink/renderer/devtools/front_end/heap_snapshot_worker/HeapSnapshotLoader.js');
+  await testRunner.loadScript('../../../../blink/renderer/devtools/front_end/platform/utilities.js');
+  await testRunner.loadScript('../../../../blink/renderer/devtools/front_end/common/UIString.js');
+  await testRunner.loadScript('../../../../blink/renderer/devtools/front_end/heap_snapshot_model/HeapSnapshotModel.js');
+  await testRunner.loadScript('../../../../blink/renderer/devtools/front_end/heap_snapshot_worker/HeapSnapshot.js');
+  await testRunner.loadScript('../../../../blink/renderer/devtools/front_end/text_utils/TextUtils.js');
+  await testRunner.loadScript('../../../../blink/renderer/devtools/front_end/heap_snapshot_worker/HeapSnapshotLoader.js');
 
   async function takeHeapSnapshotInternal(command) {
     var loader = new HeapSnapshotWorker.HeapSnapshotLoader();
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/select/select-inpage-appearance-basic-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/select/select-inpage-appearance-basic-expected.png
index ae999335..f3f853df 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/select/select-inpage-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/select/select-inpage-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/select/select-inpage-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/select/select-inpage-appearance-basic-expected.png
index 76ed524..8c9249a 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/select/select-inpage-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/select/select-inpage-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/select/select-inpage-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/select/select-inpage-appearance-basic-expected.png
index 76ed524..8c9249a 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/select/select-inpage-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/select/select-inpage-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/select/select-inpage-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/select/select-inpage-appearance-basic-expected.png
index 76ed524..8c9249a 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/select/select-inpage-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/select/select-inpage-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/select/select-inpage-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/select/select-inpage-appearance-basic-expected.png
index 76ed524..8c9249a 100644
--- a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/select/select-inpage-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/select/select-inpage-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/select/select-inpage-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/select/select-inpage-appearance-basic-expected.png
index 76ed524..8c9249a 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/select/select-inpage-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/select/select-inpage-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/resources/gesture-util.js b/third_party/blink/web_tests/resources/gesture-util.js
index 5c5bd4d..13a6ed5 100644
--- a/third_party/blink/web_tests/resources/gesture-util.js
+++ b/third_party/blink/web_tests/resources/gesture-util.js
@@ -239,14 +239,14 @@
 }
 
 // Simulate a mouse click on point.
-function mouseClickOn(x, y, button = 0 /* left */) {
+function mouseClickOn(x, y, button = 0 /* left */, keys = '') {
   return new Promise((resolve, reject) => {
     if (window.chrome && chrome.gpuBenchmarking) {
       let pointerActions = [{
         source: 'mouse',
         actions: [
           { 'name': 'pointerMove', 'x': x, 'y': y },
-          { 'name': 'pointerDown', 'x': x, 'y': y, 'button': button },
+          { 'name': 'pointerDown', 'x': x, 'y': y, 'button': button, 'keys': keys  },
           { 'name': 'pointerUp', 'button': button },
         ]
       }];
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/select/select-inpage-appearance-basic-expected.png b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/select/select-inpage-appearance-basic-expected.png
index 590dae5..0cdfdc4 100644
--- a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/select/select-inpage-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/select/select-inpage-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt b/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt
index 0ce2e10..3de5d2a1 100644
--- a/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt
@@ -322,6 +322,7 @@
     property toString
     property toggleAttribute
     property translate
+    property updateRendering
     property webkitMatchesSelector
     property webkitRequestFullScreen
     property webkitRequestFullscreen
@@ -1502,6 +1503,7 @@
     property tagName
     property textContent
     property toggleAttribute
+    property updateRendering
     property viewportElement
     property webkitMatchesSelector
     property webkitRequestFullScreen
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
index b7b3f26..c6d8be8 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -678,6 +678,7 @@
 [Worker] interface IDBTransaction : EventTarget
 [Worker]     attribute @@toStringTag
 [Worker]     getter db
+[Worker]     getter durability
 [Worker]     getter error
 [Worker]     getter mode
 [Worker]     getter objectStoreNames
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
index 74498fb..3ddd88a8 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -1553,7 +1553,6 @@
     method acquire
     method commit
     method constructor
-    method update
     method updateAndCommit
 interface Document : Node
     attribute @@toStringTag
@@ -2098,6 +2097,7 @@
     method setAttributeNodeNS
     method setPointerCapture
     method toggleAttribute
+    method updateRendering
     method webkitMatchesSelector
     method webkitRequestFullScreen
     method webkitRequestFullscreen
@@ -4407,6 +4407,7 @@
 interface IDBTransaction : EventTarget
     attribute @@toStringTag
     getter db
+    getter durability
     getter error
     getter mode
     getter objectStoreNames
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
index 736f3811..7eaaf64 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -673,6 +673,7 @@
 [Worker] interface IDBTransaction : EventTarget
 [Worker]     attribute @@toStringTag
 [Worker]     getter db
+[Worker]     getter durability
 [Worker]     getter error
 [Worker]     getter mode
 [Worker]     getter objectStoreNames
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/accessibility-activatable.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/accessibility-activatable.html
index 926a285..3076c66 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/accessibility-activatable.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/accessibility-activatable.html
@@ -59,7 +59,7 @@
 
   // update() should trigger style & layout update in the locked tree. The ax objects might get replaced,
   // but the structure should stay the same.
-  await locked.displayLock.update();
+  await locked.updateRendering();
   axLocked = axElementById("locked");
   t.step(() => { assert_equals(axLocked.childrenCount, 7, "Child count after update"); });
 
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/accessibility-non-activatable.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/accessibility-non-activatable.html
index 2cf16f3f1..30118b7 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/accessibility-non-activatable.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/accessibility-non-activatable.html
@@ -28,7 +28,7 @@
   t.step(() => { assert_equals(axLocked.childrenCount, 0); });
 
   // Trigger style & layout recalc in the locked subtree with update().
-  await locked.displayLock.update();
+  await locked.updateRendering();
   t.step(() => { assert_equals(axLocked.childrenCount, 0, "After update, nodes in locked subtree are still ignored"); });
 
   await setVisible(locked);
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-immediate-update-and-commit.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-immediate-update-and-commit.html
index 5973fda..26e8774 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-immediate-update-and-commit.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-immediate-update-and-commit.html
@@ -1,7 +1,7 @@
 <!doctype HTML>
 <html class="reftest-wait">
 <meta charset="utf8">
-<title>Display Locking: acquire, immediate updateAndCommit</title>
+<title>Display Locking: acquire, immediate displayLock.updateAndCommit</title>
 <link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
 <link rel="help" href="https://github.com/WICG/display-locking">
 <link rel="match" href="pass-container-with-child-ref.html">
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-update-and-commit.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-update-and-commit.html
index dd0d2c4..bb53be1 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-update-and-commit.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-update-and-commit.html
@@ -1,7 +1,7 @@
 <!doctype HTML>
 <html class="reftest-wait">
 <meta charset="utf8">
-<title>Display Locking: acquire, updateAndCommit</title>
+<title>Display Locking: acquire, displayLock.updateAndCommit</title>
 <link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
 <link rel="help" href="https://github.com/WICG/display-locking">
 <link rel="match" href="pass-container-with-child-ref.html">
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-update-commit.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-update-commit.html
index 88b893f..bb1c597 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-update-commit.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-update-commit.html
@@ -40,7 +40,7 @@
     container.id = "container";
     document.body.appendChild(container);
 
-    container.displayLock.update().then(() => {
+    container.updateRendering().then(() => {
       setVisible(container).then(
         () => { finishTest("PASS"); },
         (e) => { finishTest("FAIL " + e.message); });
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-update-disconnect-commit.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-update-disconnect-commit.html
index b96a466b..2deff68 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-update-disconnect-commit.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-update-disconnect-commit.html
@@ -35,7 +35,7 @@
   const container = document.getElementById("container");
   setInvisible(container).then(() => {
     // Update, then disconnect the element, and commit.
-    const update_promise = container.displayLock.update();
+    const update_promise = container.updateRendering();
     container.remove();
     const commit_promise = setVisible(container);
 
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-update-measure-remove.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-update-measure-remove.html
index aeccd0b..12619839 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-update-measure-remove.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-update-measure-remove.html
@@ -69,7 +69,7 @@
   setInvisible(container).then(() => {
     construct(container);
     document.getElementById("empty").appendChild(container);
-    container.displayLock.update().then(measureAndRemove).then(takeScreenshot);
+    container.updateRendering().then(measureAndRemove).then(takeScreenshot);
   });
 }
 
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-update-remove-commit.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-update-remove-commit.html
index 7fed331..02357efb 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-update-remove-commit.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-update-remove-commit.html
@@ -31,7 +31,7 @@
 
   setInvisible(container).then(() => {
     document.body.appendChild(container);
-    container.displayLock.update().then(
+    container.updateRendering().then(
       () => { finishTest("FAIL"); },
       (e) => {
         document.body.appendChild(container);
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-update-remove.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-update-remove.html
index a36091e..099e016 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-update-remove.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/acquire-update-remove.html
@@ -31,7 +31,7 @@
 
   setInvisible(container).then(() => {
     document.body.appendChild(container);
-    container.displayLock.update().then(
+    container.updateRendering().then(
       () => { finishTest("FAIL"); },
       (e) => { finishTest("PASS " + e.message); });
     container.remove();
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/activate-update-same-frame.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/activate-update-same-frame.html
index 2bac122..c0f809e 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/activate-update-same-frame.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/activate-update-same-frame.html
@@ -39,7 +39,7 @@
     await acquire_promise;
 
     target.scrollIntoView();
-    let update_promise = container.displayLock.update();
+    let update_promise = container.updateRendering();
     await update_promise;
     t.step(() => assert_false(container.displayLock.locked, "context after update & activation is unlocked"));
     t.done();
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/commit-followed-by-update-and-commit.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/commit-followed-by-update-and-commit.html
index 206043a..ab7f6a9 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/commit-followed-by-update-and-commit.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/commit-followed-by-update-and-commit.html
@@ -1,7 +1,7 @@
 <!doctype HTML>
 <html class="reftest-wait">
 <meta charset="utf8">
-<title>Display Locking: commit, updateAndCommit</title>
+<title>Display Locking: commit, displayLock.updateAndCommit</title>
 <link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
 <link rel="help" href="https://github.com/WICG/display-locking">
 <link rel="match" href="pass-container-with-child-ref.html">
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/display-none-ancestor.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/display-none-ancestor.html
index f119bfb..da43535 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/display-none-ancestor.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/display-none-ancestor.html
@@ -37,7 +37,7 @@
   locked.id = "locked";
   setInvisible(locked).then(() => {
     container.appendChild(locked);
-    locked.displayLock.update().then(() => {
+    locked.updateRendering().then(() => {
       // Make container visible & force style + layout.
       container.style = "display:block";
       container.offsetTop;
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/locked-attribute.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/locked-attribute.html
index 451a491..a97df23 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/locked-attribute.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/locked-attribute.html
@@ -23,7 +23,7 @@
     await acquire_promise;
     t.step(() => assert_true(container.displayLock.locked, "context after acquire finishes is locked"));
 
-    const update_promise = container.displayLock.update();
+    const update_promise = container.updateRendering();
     t.step(() => assert_true(container.displayLock.locked, "context during update is locked"));
 
     await update_promise;
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/measure-updated-layout.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/measure-updated-layout.html
index a015af0..075011d 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/measure-updated-layout.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/measure-updated-layout.html
@@ -83,7 +83,7 @@
     document.getElementById("parent").appendChild(container);
     construct(container);
 
-    container.displayLock.update().then(() => {
+    container.updateRendering().then(() => {
       measureInUpdate();
       setVisible(container).then(() => {
         measureInCommit();
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/multiple-acquires-all-succeed.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/multiple-acquires-all-succeed.html
index fa8e57c..eee6dbb8 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/multiple-acquires-all-succeed.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/multiple-acquires-all-succeed.html
@@ -46,10 +46,10 @@
     document.body.appendChild(container);
 
     Promise.all([
-      container.displayLock.update(),
-      container.displayLock.update(),
-      container.displayLock.update(),
-      container.displayLock.update()
+      container.updateRendering(),
+      container.updateRendering(),
+      container.updateRendering(),
+      container.updateRendering()
     ]).then(() => {
       setVisible(container).then(
         () => { finishTest("PASS"); },
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/multiple-update-and-commit.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/multiple-update-and-commit.html
index c7cbea4..d5ffb99 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/multiple-update-and-commit.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/multiple-update-and-commit.html
@@ -1,7 +1,7 @@
 <!doctype HTML>
 <html class="reftest-wait">
 <meta charset="utf8">
-<title>Display Locking: multiple updateAndCommit</title>
+<title>Display Locking: multiple displayLock.updateAndCommit</title>
 <link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
 <link rel="help" href="https://github.com/WICG/display-locking">
 <link rel="match" href="pass-container-with-child-ref.html">
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/nested-update-and-commit.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/nested-update-and-commit.html
index fcc233f..e87bd3a 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/nested-update-and-commit.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/nested-update-and-commit.html
@@ -1,7 +1,7 @@
 <!doctype HTML>
 <html class="reftest-wait">
 <meta charset="utf8">
-<title>Display Locking: nested updateAndCommit</title>
+<title>Display Locking: nested displayLock.updateAndCommit</title>
 <link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
 <link rel="help" href="https://github.com/WICG/display-locking">
 <link rel="match" href="pass-ref.html">
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/nested-update.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/nested-update.html
index e6488547..8ce9a60 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/nested-update.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/nested-update.html
@@ -46,7 +46,7 @@
     setInvisible(inner)]);
   // Dirty the inner layout
   inner.appendChild(document.createElement("div"));
-  inner.displayLock.update().then(
+  inner.updateRendering().then(
     () => { finishTest("FAIL"); },
     (e) => { finishTest("PASS " + e.message); });
 }
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/large-content-size-in-overflow-auto-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/large-content-size-in-overflow-auto-ref.html
new file mode 100644
index 0000000..fafd8f70
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/large-content-size-in-overflow-auto-ref.html
@@ -0,0 +1,23 @@
+<!doctype HTML>
+<meta charset="utf8">
+<title>Display Locking: content-size is larger than height (ref)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://github.com/WICG/display-locking">
+
+<style>
+#container {
+  contain: style layout size;
+  width: 200px;
+  height: 100px;
+  overflow: auto;
+  background: lightblue;
+}
+#container > div {
+  margin: 0;
+  padding: 0;
+  width: 1px;
+  height: 200px;
+}
+</style>
+
+<div id=container><div></div></div>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/large-content-size-in-overflow-auto.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/large-content-size-in-overflow-auto.html
new file mode 100644
index 0000000..1f82d62
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/large-content-size-in-overflow-auto.html
@@ -0,0 +1,30 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Display Locking: content-size is larger than height</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://github.com/WICG/display-locking">
+<link rel="match" href="large-content-size-in-overflow-auto-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<script src="../resources/utils.js"></script>
+
+<style>
+#container {
+  content-size: 1px 200px;
+  width: 200px;
+  height: 100px;
+  overflow: auto;
+  background: lightblue;
+}
+</style>
+
+<div id=container>Text</div>
+
+<script>
+function runTest() {
+  setInvisible(document.getElementById("container")).then(() => {
+    takeScreenshot();
+  });
+}
+window.onload = runTest;
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/measure-updated-layout.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/measure-updated-layout.html
index 47ab110..7f5c1fe 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/measure-updated-layout.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/measure-updated-layout.html
@@ -78,7 +78,7 @@
 
     construct(document.getElementById("large"));
 
-    container.displayLock.update().then(() => {
+    container.updateRendering().then(() => {
       measureInUpdate();
       setVisible(container).then(() => {
         measureInCommit();
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/slotted-moved-after-lock.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/slotted-moved-after-lock.html
new file mode 100644
index 0000000..42e0809
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/slotted-moved-after-lock.html
@@ -0,0 +1,29 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Display Locking: slot moved after lock acquired</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://github.com/WICG/display-locking">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/utils.js"></script>
+
+<div id=host>
+<input id=slotted>
+<script>
+async_test((t) => {
+  let container = document.createElement("div");
+  container.innerHTML = "<slot></slot>";
+  let shadowRoot = host.attachShadow({ mode: "open" });
+  shadowRoot.appendChild(container);
+
+  t.step(() => {
+    setInvisible(container);
+
+    assert_equals(slotted.offsetTop, 0);
+    container.innerHTML = "<div style='height: 20px;'></div><slot></slot>";
+
+    t.done();
+  });
+});
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-and-commit-followed-by-commit.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-and-commit-followed-by-commit.html
index 22beb33..404f75e0 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-and-commit-followed-by-commit.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-and-commit-followed-by-commit.html
@@ -1,7 +1,7 @@
 <!doctype HTML>
 <html class="reftest-wait">
 <meta charset="utf8">
-<title>Display Locking: updateAndCommit, commit</title>
+<title>Display Locking: displayLock.updateAndCommit, commit</title>
 <link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
 <link rel="help" href="https://github.com/WICG/display-locking">
 <link rel="match" href="pass-container-with-child-ref.html">
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-and-commit-followed-by-update.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-and-commit-followed-by-update.html
index 67a2dfed..b5a8615 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-and-commit-followed-by-update.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-and-commit-followed-by-update.html
@@ -1,7 +1,7 @@
 <!doctype HTML>
 <html class="reftest-wait">
 <meta charset="utf8">
-<title>Display Locking: updateAndCommit, update</title>
+<title>Display Locking: displayLock.updateAndCommit, update</title>
 <link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
 <link rel="help" href="https://github.com/WICG/display-locking">
 <link rel="match" href="pass-container-with-child-ref.html">
@@ -41,7 +41,7 @@
     document.body.appendChild(container);
 
     const first_promise = container.displayLock.updateAndCommit();
-    const second_promise = container.displayLock.update();
+    const second_promise = container.updateRendering();
     Promise.all([first_promise, second_promise]).then(() => finishTest("PASS"));
   });
 }
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-and-commit.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-and-commit.html
index a0a3e47..c0ad7ac 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-and-commit.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-and-commit.html
@@ -1,7 +1,7 @@
 <!doctype HTML>
 <html class="reftest-wait">
 <meta charset="utf8">
-<title>Display Locking: updateAndCommit without acquire</title>
+<title>Display Locking: displayLock.updateAndCommit without acquire</title>
 <link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
 <link rel="help" href="https://github.com/WICG/display-locking">
 <link rel="match" href="pass-ref.html">
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-followed-by-update-and-commit.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-followed-by-update-and-commit.html
index b9cc57b..d9348dd 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-followed-by-update-and-commit.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-followed-by-update-and-commit.html
@@ -1,7 +1,7 @@
 <!doctype HTML>
 <html class="reftest-wait">
 <meta charset="utf8">
-<title>Display Locking: update, updateAndCommit</title>
+<title>Display Locking: update, displayLock.updateAndCommit</title>
 <link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
 <link rel="help" href="https://github.com/WICG/display-locking">
 <link rel="match" href="pass-container-with-child-ref.html">
@@ -40,7 +40,7 @@
     container.id = "container";
     document.body.appendChild(container);
 
-    const first_promise = container.displayLock.update();
+    const first_promise = container.updateRendering();
     const second_promise = container.displayLock.updateAndCommit();
     Promise.all([first_promise, second_promise]).then(() => finishTest("PASS"));
   });
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-together-with-commit-both-succeed.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-together-with-commit-both-succeed.html
index fcc4940..ab504d74 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-together-with-commit-both-succeed.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-together-with-commit-both-succeed.html
@@ -41,7 +41,7 @@
     document.body.appendChild(container);
 
     Promise.all([
-      container.displayLock.update(),
+      container.updateRendering(),
       setVisible(container)
     ]).then(() => { finishTest("PASS"); },
             () => { finishTest("FAIL"); });
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-while-disconnected-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-while-disconnected-ref.html
deleted file mode 100644
index 3743163ee..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-while-disconnected-ref.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: update while disconnected (reference)</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<div id="log">PASS Element is unlocked.</div>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-while-disconnected.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-while-disconnected.html
index e49ddd7b1..17bf5dca 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-while-disconnected.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-while-disconnected.html
@@ -4,7 +4,7 @@
 <title>Display Locking: update while disconnected</title>
 <link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
 <link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="update-while-disconnected-ref.html">
+<link rel="match" href="pass-ref.html">
 <script src="/common/reftest-wait.js"></script>
 <script src="resources/utils.js"></script>
 
@@ -22,9 +22,9 @@
   container.id = "container";
 
   setInvisible(container).then(() => {
-    container.displayLock.update().then(
-      () => { finishTest("FAIL"); },
-      (e) => { finishTest("PASS " + e.message); });
+    container.updateRendering().then(
+      () => { finishTest("PASS"); },
+      (e) => { finishTest("FAIL " + e.message); });
   });
 }
 
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-without-acquire-fails-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-without-acquire-fails-ref.html
deleted file mode 100644
index d54ca27..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-without-acquire-fails-ref.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: update without acquire (reference)</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<style>
-#container {
-  contain: style layout;
-  width: 150px;
-  height: 150px;
-  background: lightblue;
-}
-</style>
-
-<div id="log">PASS Element is unlocked.</div>
-<div id="container"></div>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-without-acquire-fails.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-without-acquire-works.html
similarity index 70%
rename from third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-without-acquire-fails.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-without-acquire-works.html
index 48424af..468052f 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-without-acquire-fails.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/update-without-acquire-works.html
@@ -4,7 +4,7 @@
 <title>Display Locking: update without acquire</title>
 <link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
 <link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="update-without-acquire-fails-ref.html">
+<link rel="match" href="pass-container-with-child-ref.html">
 <script src="/common/reftest-wait.js"></script>
 
 <style>
@@ -21,6 +21,7 @@
 </style>
 
 <div id="log"></div>
+<div id="container"><div id="child"></div></div>
 
 <script>
 function finishTest(status_string) {
@@ -30,12 +31,9 @@
 }
 
 function runTest() {
-  const container = document.createElement("div");
-  container.id = "container";
-  container.displayLock.update().then(
-      () => { finishTest("FAIL"); },
-      (e) => { finishTest("PASS " + e.message); });
-  document.body.appendChild(container);
+  container.updateRendering().then(
+      () => { finishTest("PASS"); },
+      (e) => { finishTest("FAIL " + e.message); });
 }
 
 window.onload = runTest;
diff --git a/third_party/ply/OWNERS b/third_party/ply/OWNERS
index 32e3eca0..73dbb19 100644
--- a/third_party/ply/OWNERS
+++ b/third_party/ply/OWNERS
@@ -1 +1,6 @@
+bbudge@chromium.org
+rockot@google.com
+
+file://tools/idl_parser/OWNERS
+
 # COMPONENT: Tools
diff --git a/third_party/ply/README.chromium b/third_party/ply/README.chromium
index c0c85cff..b7ec1d1 100644
--- a/third_party/ply/README.chromium
+++ b/third_party/ply/README.chromium
@@ -6,6 +6,9 @@
 Security Critical: no
 Version: 3.11
 
+PLY is used by (at least) the Mojo python bindings, the PPAPI
+IDL generator, and the Blink IDL generator.
+
 This directory contains a copy of these ply-3.11 components:
 
 README            ply-3.11/README.md
diff --git a/tools/android/elf_compression/compress_section.py b/tools/android/elf_compression/compress_section.py
index 2efe7ef..7f145266 100755
--- a/tools/android/elf_compression/compress_section.py
+++ b/tools/android/elf_compression/compress_section.py
@@ -43,6 +43,30 @@
     'third_party/llvm-build/Release+Asserts/bin/llvm-objcopy')
 
 
+def SegmentContains(main_l, main_r, l, r):
+  """Returns true if [l, r) is contained inside [main_l, main_r).
+
+  Args:
+    main_l: int. Left border of the first segment.
+    main_r: int. Right border (exclusive) of the second segment.
+    l: int. Left border of the second segment.
+    r: int. Right border (exclusive) of the second segment.
+  """
+  return main_l <= l and main_r >= r
+
+
+def SegmentsIntersect(l1, r1, l2, r2):
+  """Returns true if [l1, r1) intersects with [l2, r2).
+
+  Args:
+    l1: int. Left border of the first segment.
+    r1: int. Right border (exclusive) of the second segment.
+    l2: int. Left border of the second segment.
+    r2: int. Right border (exclusive) of the second segment.
+  """
+  return l2 < r1 and r2 > l1
+
+
 def AlignUp(addr, page_size=ADDRESS_ALIGN):
   """Rounds up given address to be aligned to page_size.
 
@@ -125,11 +149,9 @@
     # Current version of the prototype only supports ranges which are fully
     # contained inside one LOAD segment. It should cover most of the common
     # cases.
-    if phdr.p_offset >= r or phdr.FilePositionEnd() <= l:
-      # Range doesn't overlap.
+    if not SegmentsIntersect(phdr.p_offset, phdr.FilePositionEnd(), l, r):
       continue
-    if phdr.p_offset > l or phdr.FilePositionEnd() < r:
-      # Range overlap with LOAD segment but isn't fully covered by it.
+    if not SegmentContains(phdr.p_offset, phdr.FilePositionEnd(), l, r):
       raise RuntimeError('Range is not contained within one LOAD segment')
     l_virt = phdr.p_vaddr + (l - phdr.p_offset)
     r_virt = phdr.p_vaddr + (r - phdr.p_offset)
@@ -277,7 +299,7 @@
   range_phdr = None
   for phdr in elf_hdr.GetProgramHeadersByType(
       elf_headers.ProgramHeader.Type.PT_LOAD):
-    if phdr.p_offset <= l and phdr.FilePositionEnd() >= r:
+    if SegmentContains(phdr.p_offset, phdr.FilePositionEnd(), l, r):
       range_phdr = phdr
       break
   if range_phdr is None:
@@ -329,6 +351,52 @@
   elf_hdr.PatchData(data)
 
 
+def _CutRangeAndCorrectFile(data, l, r):
+  """Removes [l, r) from the data and fixes offsets to stabilize the ELF."""
+  elf = elf_headers.ElfHeader(data)
+  # Removing the range from the file:
+  del data[l:r]
+
+  range_length = r - l
+  for phdr in elf.GetProgramHeaders():
+    # Any other program header intersecting the [l, r) range poses serious
+    # problem as this header needs to be split if possible. However since we are
+    # compressing part of program's code this is highly unlikely, albeit
+    # possible in worst case scenario.
+    # With that in mind we assert that such thing doesn't happen in our case.
+    if SegmentsIntersect(phdr.p_offset, phdr.FilePositionEnd(), l, r):
+      raise RuntimeError('Segment intersects with provided range')
+    if phdr.p_offset >= r:
+      phdr.p_offset -= range_length
+    # Per ELF standard: p_offset % p_align == p_vaddr % p_align.
+    # Since we moved the p_offset we could have broken this rule.
+    # To mitigate this issue we notice the following two facts:
+    # 1) range_length % ADDRESS_ALIGN == 0.
+    # 2) We can reduce the p_align without breaking the alignment.
+    # We reduce all p_align to be less or equal than ADDRESS_ALIGN and now
+    # range_length % p_align == 0, so the alignment remains valid.
+    # Our changes of p_align are perfectly legal per standard
+    # as long as p_align % PAGE_SIZE == 0.
+    if phdr.p_align > ADDRESS_ALIGN:
+      phdr.p_align = ADDRESS_ALIGN
+
+  for shdr in elf.GetSectionHeaders():
+    # Note that if the section overlaps with the cut range we are unable
+    # to adjust its size to match both file and virtual size of it. In such
+    # case we treat sh_size as memory size and don't adjust it, which may
+    # cause some tools treating sh_size as file size to stop working.
+    if shdr.sh_offset >= l:
+      if shdr.sh_offset < r:
+        raise RuntimeError('Section starts within the provided range')
+      else:
+        shdr.sh_offset -= range_length
+  if elf.e_phoff > l:
+    elf.e_phoff -= range_length
+  if elf.e_shoff > l:
+    elf.e_shoff -= range_length
+  elf.PatchData(data)
+
+
 def _ShrinkRangeToAlignVirtualAddress(data, l, r):
   virtual_l, virtual_r = _FileRangeToVirtualAddressRange(data, l, r)
   # LOAD segments borders are being rounded to the page size so we have to
@@ -356,6 +424,7 @@
 
   _CreateLoadForCompressedSection(data)
   _SplitLoadSegmentAndNullifyRange(data, left_range, right_range)
+  _CutRangeAndCorrectFile(data, left_range, right_range)
 
   with open(args.output, 'wb') as f:
     f.write(data)
diff --git a/tools/android/elf_compression/test/compression_script_test.py b/tools/android/elf_compression/test/compression_script_test.py
index 38438ce2..4ec8213 100755
--- a/tools/android/elf_compression/test/compression_script_test.py
+++ b/tools/android/elf_compression/test/compression_script_test.py
@@ -141,6 +141,33 @@
     self.assertEqual(
         compress_section.MatchVaddrAlignment(1024, 2049, 1024), 1025)
 
+  def testSegmentContains(self):
+    """Tests for SegmentContains method of the script."""
+    self.assertTrue(compress_section.SegmentContains(0, 3, 0, 1))
+    self.assertTrue(compress_section.SegmentContains(0, 3, 0, 2))
+    self.assertTrue(compress_section.SegmentContains(0, 3, 0, 3))
+    self.assertTrue(compress_section.SegmentContains(0, 3, 1, 2))
+    self.assertTrue(compress_section.SegmentContains(0, 3, 1, 3))
+
+    self.assertFalse(compress_section.SegmentContains(0, 1, 0, 3))
+    self.assertFalse(compress_section.SegmentContains(0, 3, 0, 4))
+    self.assertFalse(compress_section.SegmentContains(0, 3, -1, 4))
+    self.assertFalse(compress_section.SegmentContains(0, 3, -1, 2))
+    self.assertFalse(compress_section.SegmentContains(0, 3, 2, 4))
+    self.assertFalse(compress_section.SegmentContains(0, 3, 3, 4))
+    self.assertFalse(compress_section.SegmentContains(0, 3, -1, 0))
+
+  def testSegmentsIntersect(self):
+    """Tests for SegmentIntersect method of the script."""
+    self.assertTrue(compress_section.SegmentsIntersect(0, 3, 0, 3))
+    self.assertTrue(compress_section.SegmentsIntersect(0, 3, -1, 1))
+    self.assertTrue(compress_section.SegmentsIntersect(0, 3, 2, 4))
+    self.assertTrue(compress_section.SegmentsIntersect(0, 3, 1, 2))
+
+    self.assertFalse(compress_section.SegmentsIntersect(0, 3, 4, 6))
+    self.assertFalse(compress_section.SegmentsIntersect(0, 3, -1, 0))
+    self.assertFalse(compress_section.SegmentsIntersect(0, 3, 3, 5))
+
 
 if __name__ == '__main__':
   unittest.main()
diff --git a/tools/binary_size/libsupersize/html_report.py b/tools/binary_size/libsupersize/html_report.py
index 9523c55..0ec6b114 100644
--- a/tools/binary_size/libsupersize/html_report.py
+++ b/tools/binary_size/libsupersize/html_report.py
@@ -4,12 +4,15 @@
 
 """Creates an html report that allows you to view binary size by component."""
 
+from __future__ import print_function
+
 import codecs
 import collections
 import itertools
 import json
 import logging
 import os
+import uuid
 
 import archive
 import diff
@@ -281,13 +284,21 @@
   BuildReportFromSizeInfo(
       args.output_report_file, size_info, all_symbols=args.all_symbols)
 
+  logging.warning('Done!')
   msg = [
-      'Done!',
       'View using a local server via: ',
-      '    %s start_server %s',
-      'or upload to the hosted version here:',
+      '    {0} start_server {1}',
+      'or run:',
+      '    gsutil.py cp -a public-read {1} gs://chrome-supersize/oneoffs/'
+      '{2}.ndjson',
+      '  to view at:',
       '    https://storage.googleapis.com/chrome-supersize/viewer.html'
-      ]
+      '?load_url=oneoffs/{2}.ndjson',
+  ]
   supersize_path = os.path.relpath(os.path.join(
       path_util.SRC_ROOT, 'tools', 'binary_size', 'supersize'))
-  logging.warning('\n'.join(msg),  supersize_path, args.output_report_file)
+  # Use a random UUID as the filename so user can copy-and-paste command
+  # directly without a name collision.
+  upload_id = uuid.uuid4()
+  print('\n'.join(msg).format(supersize_path, args.output_report_file,
+                              upload_id))
diff --git a/tools/binary_size/trybot_commit_size_checker.py b/tools/binary_size/trybot_commit_size_checker.py
index 0310b5f..a39f95133 100755
--- a/tools/binary_size/trybot_commit_size_checker.py
+++ b/tools/binary_size/trybot_commit_size_checker.py
@@ -118,7 +118,7 @@
   lines, net_added = _SymbolDiffHelper(symbols)
   details = 'Refer to Dex Method Diff for list of added/removed methods.'
 
-  return lines, _SizeDelta('Dex Methods', 'methods',
+  return lines, _SizeDelta('Dex Methods Count', 'methods',
                            _MAX_DEX_METHOD_COUNT_INCREASE, net_added, details)
 
 
@@ -158,6 +158,12 @@
   ]
 
 
+def _FormatSign(number):
+  if number > 0:
+    return '+{}'.format(number)
+  return '{}'.format(number)
+
+
 def main():
   parser = argparse.ArgumentParser()
   parser.add_argument('--author', required=True, help='CL author')
@@ -288,7 +294,8 @@
       continue
     listing = {
         'name': delta.name,
-        'delta': '{} {}'.format(delta.actual, delta.units),
+        'delta': '{} {}'.format(_FormatSign(delta.actual), delta.units),
+        'limit': '{} {}'.format(_FormatSign(delta.expected), delta.units),
         'allowed': delta.IsAllowable(),
     }
     binary_size_listings.append(listing)
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index f8e80796..dbf4f18b 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -1323,6 +1323,8 @@
   <int value="6" label="User exited the tab switcher"/>
   <int value="7" label="User exited fullscreen mode"/>
   <int value="8" label="User navigated backward in the tab's history"/>
+  <int value="9"
+      label="User used back press to exit tab group dialog from tab strip"/>
 </enum>
 
 <enum name="AndroidApiLevel">
@@ -18124,6 +18126,7 @@
   <int value="607" label="DeviceLoginScreenVirtualKeyboardEnabled"/>
   <int value="608" label="CloudExtensionRequestEnabled"/>
   <int value="609" label="DeviceLoginScreenSystemInfoEnforced"/>
+  <int value="610" label="SharedClipboardEnabled"/>
 </enum>
 
 <enum name="EnterprisePolicyInvalidations">
@@ -19224,6 +19227,7 @@
   <int value="440"
       label="ACCESSIBILITY_PRIVATE_FIND_SCROLLABLE_BOUNDS_FOR_POINT"/>
   <int value="441" label="LOGIN_STATE_ON_SESSION_STATE_CHANGED"/>
+  <int value="442" label="PRINTING_METRICS_ON_PRINT_JOB_FINISHED"/>
 </enum>
 
 <enum name="ExtensionFileWriteResult">
@@ -20674,6 +20678,7 @@
   <int value="1383" label="AUTOTESTPRIVATE_TAKESCREENSHOTFORDISPLAY"/>
   <int value="1384" label="AUTOFILLPRIVATE_SETCREDITCARDFIDOAUTHENABLEDSTATE"/>
   <int value="1385" label="USERSPRIVATE_ISWHITELISTEDUSER"/>
+  <int value="1386" label="PRINTINGMETRICS_GETPRINTJOBS"/>
 </enum>
 
 <enum name="ExtensionIconState">
@@ -21217,6 +21222,7 @@
   <int value="220" label="kLogin"/>
   <int value="221" label="kLoginScreenStorage"/>
   <int value="222" label="kLoginState"/>
+  <int value="223" label="kPrintingMetrics"/>
 </enum>
 
 <enum name="ExtensionServiceVerifyAllSuccess">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 4b99b7ec..18905b5 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -17828,6 +17828,35 @@
   </summary>
 </histogram>
 
+<histogram name="Bookmarks.AddedPerProfileType" enum="BrowserProfileType"
+    expires_after="M85">
+  <owner>rhalavati@chromium.org</owner>
+  <owner>chrome-privacy-core@google.com</owner>
+  <summary>
+    This histogram records when a bookmark is added sliced on profile type.
+  </summary>
+</histogram>
+
+<histogram name="Bookmarks.BookmarkAllTabsWithTabsCount.Incognito" units="tabs"
+    expires_after="M85">
+  <owner>rhalavati@chromium.org</owner>
+  <owner>chrome-privacy-core@google.com</owner>
+  <summary>
+    This histogram records the count of tabs when a user bookmarks all open
+    tabs, in incognito mode.
+  </summary>
+</histogram>
+
+<histogram name="Bookmarks.BookmarkAllTabsWithTabsCount.Regular" units="tabs"
+    expires_after="M85">
+  <owner>rhalavati@chromium.org</owner>
+  <owner>chrome-privacy-core@google.com</owner>
+  <summary>
+    This histogram records the count of tabs when a user bookmarks all open
+    tabs, in regular mode.
+  </summary>
+</histogram>
+
 <histogram name="Bookmarks.BookmarksInFolder" units="bookmarks">
   <owner>calamity@chromium.org</owner>
   <summary>
diff --git a/tools/perf/benchmarks/blink_perf.py b/tools/perf/benchmarks/blink_perf.py
index 09b9082..aa3dce7 100644
--- a/tools/perf/benchmarks/blink_perf.py
+++ b/tools/perf/benchmarks/blink_perf.py
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from __future__ import print_function
+
 import os
 import collections
 
@@ -298,18 +300,18 @@
 
   def PrintAndCollectTraceEventMetrics(self, trace_cpu_time_metrics, results):
     unit = 'ms'
-    print
+    print()
     for trace_event_name, cpu_times in trace_cpu_time_metrics.iteritems():
-      print 'CPU times of trace event "%s":' % trace_event_name
+      print('CPU times of trace event "%s":' % trace_event_name)
       cpu_times_string = ', '.join(['{0:.10f}'.format(t) for t in cpu_times])
-      print 'values %s %s' % (cpu_times_string, unit)
+      print('values %s %s' % (cpu_times_string, unit))
       avg = 0.0
       if cpu_times:
         avg = sum(cpu_times)/len(cpu_times)
-      print 'avg', '{0:.10f}'.format(avg), unit
+      print('avg', '{0:.10f}'.format(avg), unit)
       results.AddMeasurement(trace_event_name, unit, cpu_times)
-      print
-    print '\n'
+      print()
+    print('\n')
 
   def ValidateAndMeasurePage(self, page, tab, results):
     trace_cpu_time_metrics = {}
@@ -329,7 +331,7 @@
 
     for line in log.splitlines():
       if line.startswith("FATAL: "):
-        print line
+        print(line)
         continue
       if not line.startswith('values '):
         continue
@@ -344,7 +346,7 @@
 
       break
 
-    print log
+    print(log)
 
     self.PrintAndCollectTraceEventMetrics(trace_cpu_time_metrics, results)
 
diff --git a/tools/perf/cli_tools/flakiness_cli/main.py b/tools/perf/cli_tools/flakiness_cli/main.py
index 6b5db33..f067628a 100644
--- a/tools/perf/cli_tools/flakiness_cli/main.py
+++ b/tools/perf/cli_tools/flakiness_cli/main.py
@@ -4,6 +4,8 @@
 
 """This tool provides a command line interface for the flakiness dashboard."""
 
+from __future__ import print_function
+
 import argparse
 
 from cli_tools.flakiness_cli import analysis
@@ -54,4 +56,4 @@
 
   df = analysis.pandas.concat(dfs)
   df = df.sort_values('flakiness', ascending=False)
-  print df
+  print(df)
diff --git a/tools/perf/cli_tools/pinpoint_cli/commands.py b/tools/perf/cli_tools/pinpoint_cli/commands.py
index 530be16..9bdcbb8 100644
--- a/tools/perf/cli_tools/pinpoint_cli/commands.py
+++ b/tools/perf/cli_tools/pinpoint_cli/commands.py
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from __future__ import print_function
+
 import csv
 import json
 import logging
@@ -25,13 +27,13 @@
     raise ValueError('Invalid job config')
 
   response = pinpoint_service.NewJob(**config)
-  print 'Started:', response['jobUrl']
+  print('Started:', response['jobUrl'])
 
 
 def CheckJobStatus(job_ids):
   for job_id in job_ids:
     job = pinpoint_service.Job(job_id)
-    print '%s: %s' % (job_id, job['status'].lower())
+    print('%s: %s' % (job_id, job['status'].lower()))
 
 
 def DownloadJobResultsAsCsv(job_ids, only_differences, output_file):
@@ -45,10 +47,10 @@
       os_path = _OsPathFromJob(job)
       results_file = os_path.join(
           job['arguments']['benchmark'], 'perf_results.json')
-      print 'Fetching results for %s job %s:' % (job['status'].lower(), job_id)
+      print('Fetching results for %s job %s:' % (job['status'].lower(), job_id))
       for change_id, isolate_hash in job_results.IterTestOutputIsolates(
           job, only_differences):
-        print '- isolate: %s ...' % isolate_hash
+        print('- isolate: %s ...' % isolate_hash)
         try:
           histograms = isolate_service.RetrieveFile(isolate_hash, results_file)
         except KeyError:
@@ -57,7 +59,7 @@
         for row in histograms_df.IterRows(json.loads(histograms)):
           writer.writerow((job_id, change_id, isolate_hash) + row)
           num_rows += 1
-  print 'Wrote data from %d histograms in %s.' % (num_rows, output_file)
+  print('Wrote data from %d histograms in %s.' % (num_rows, output_file))
 
 
 def _OsPathFromJob(job):
diff --git a/tools/perf/cli_tools/soundwave/commands.py b/tools/perf/cli_tools/soundwave/commands.py
index b6f8522a..079011e 100644
--- a/tools/perf/cli_tools/soundwave/commands.py
+++ b/tools/perf/cli_tools/soundwave/commands.py
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from __future__ import print_function
+
 import json
 import logging
 try:
@@ -47,25 +49,25 @@
       pandas_sqlite.InsertOrReplaceRecords(con, 'alerts', alerts)
       num_alerts += len(alerts)
       bug_ids.update(alerts['bug_id'].unique())
-    print '%d alerts found!' % num_alerts
+    print('%d alerts found!' % num_alerts)
 
     # Get set of bugs associated with those alerts.
     bug_ids.discard(0)  # A bug_id of 0 means untriaged.
-    print '%d bugs found!' % len(bug_ids)
+    print('%d bugs found!' % len(bug_ids))
 
     # Filter out bugs already in cache.
     if args.use_cache:
       known_bugs = set(
           b for b in bug_ids if tables.bugs.Get(con, b) is not None)
       if known_bugs:
-        print '(skipping %d bugs already in the database)' % len(known_bugs)
+        print('(skipping %d bugs already in the database)' % len(known_bugs))
         bug_ids.difference_update(known_bugs)
 
   # Use worker pool to fetch bug data.
   total_seconds = worker_pool.Run(
       'Fetching data of %d bugs: ' % len(bug_ids),
       _FetchBugsWorker, args, bug_ids)
-  print '[%.1f bugs per second]' % (len(bug_ids) / total_seconds)
+  print('[%.1f bugs per second]' % (len(bug_ids) / total_seconds))
 
 
 def _IterStaleTestPaths(con, test_paths):
@@ -131,24 +133,24 @@
     if args.filters:
       test_paths = filter(_MatchesAllFilters, test_paths)
     num_found = len(test_paths)
-    print '%d test paths found!' % num_found
+    print('%d test paths found!' % num_found)
 
     # Filter out test_paths already in cache.
     if args.use_cache:
       test_paths = list(_IterStaleTestPaths(con, test_paths))
       num_skipped = num_found - len(test_paths)
       if num_skipped:
-        print '(skipping %d test paths already in the database)' % num_skipped
+        print('(skipping %d test paths already in the database)' % num_skipped)
 
   # Use worker pool to fetch test path data.
   total_seconds = worker_pool.Run(
       'Fetching data of %d timeseries: ' % len(test_paths),
       _FetchTimeseriesWorker, args, test_paths)
-  print '[%.1f test paths per second]' % (len(test_paths) / total_seconds)
+  print('[%.1f test paths per second]' % (len(test_paths) / total_seconds))
 
   if args.output_csv is not None:
-    print
-    print 'Post-processing data for study ...'
+    print()
+    print('Post-processing data for study ...')
     dfs = []
     with tables.DbSession(args.database_file) as con:
       for test_path in test_paths:
@@ -157,4 +159,4 @@
     df = studies.PostProcess(pandas.concat(dfs, ignore_index=True))
     with cli_utils.OpenWrite(args.output_csv) as f:
       df.to_csv(f, index=False)
-    print 'Wrote timeseries data to:', args.output_csv
+    print('Wrote timeseries data to:', args.output_csv)
diff --git a/tools/perf/contrib/blink_perf_cmdline/blink_perf_cmdline.py b/tools/perf/contrib/blink_perf_cmdline/blink_perf_cmdline.py
index 929321b..786254ca 100644
--- a/tools/perf/contrib/blink_perf_cmdline/blink_perf_cmdline.py
+++ b/tools/perf/contrib/blink_perf_cmdline/blink_perf_cmdline.py
@@ -1,6 +1,9 @@
 # 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.
+
+from __future__ import print_function
+
 import os
 
 from benchmarks import blink_perf
@@ -27,6 +30,6 @@
       path = os.path.abspath(options.test_path)
     else:
       path = os.path.join(blink_perf.BLINK_PERF_BASE_DIR, options.test_path)
-    print
-    print 'Running all tests in %s' % path
+    print()
+    print('Running all tests in %s' % path)
     return blink_perf.CreateStorySetFromPath(path, blink_perf.SKIPPED_FILE)
diff --git a/tools/perf/contrib/cluster_telemetry/analyze_metrics_ct.py b/tools/perf/contrib/cluster_telemetry/analyze_metrics_ct.py
index d74a862..c3a48e82 100755
--- a/tools/perf/contrib/cluster_telemetry/analyze_metrics_ct.py
+++ b/tools/perf/contrib/cluster_telemetry/analyze_metrics_ct.py
@@ -3,8 +3,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-
 from __future__ import division
+from __future__ import print_function
 
 import argparse
 import json
@@ -46,7 +46,7 @@
   trace_size_in_mib = os.path.getsize(args.local_trace_path) / (2 ** 20)
   # Bails out on trace that are too big. See crbug.com/812631 for more details.
   if trace_size_in_mib > 400:
-    print 'Trace size is too big: %s MiB' % trace_size_in_mib
+    print('Trace size is too big: %s MiB' % trace_size_in_mib)
     return 1
 
   logging.warning('Starting to compute metrics on trace')
@@ -59,8 +59,8 @@
       time.time() - start))
 
   for f in mre_result.failures:
-    print 'Running metric failed:'
-    print f.stack
+    print('Running metric failed:')
+    print(f.stack)
     return 1
 
   with tempfile.NamedTemporaryFile() as temp:
@@ -70,12 +70,12 @@
 
     result = histograms_to_csv.HistogramsToCsv(temp.name)
     if result.returncode != 0:
-      print 'histograms_to_csv.HistogramsToCsv returned %d' % result.returncode
+      print('histograms_to_csv.HistogramsToCsv returned %d' % result.returncode)
       return result.returncode
     else:
       with open(args.output_csv, 'w') as f:
         f.write(result.stdout.rstrip())
-      print 'Output CSV created in file://' + args.output_csv
+      print('Output CSV created in file://' + args.output_csv)
 
 
 if __name__ == '__main__':
diff --git a/tools/perf/contrib/cros_benchmarks/tab_switching_stories.py b/tools/perf/contrib/cros_benchmarks/tab_switching_stories.py
index be49288..9224a71 100644
--- a/tools/perf/contrib/cros_benchmarks/tab_switching_stories.py
+++ b/tools/perf/contrib/cros_benchmarks/tab_switching_stories.py
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from __future__ import print_function
+
 import logging
 import time
 
@@ -52,7 +54,7 @@
       except exceptions.DevtoolsTargetCrashException:
         logging.info('Navigate: devtools context lost')
       if i % 10 == 0:
-        print 'opening tab:', i
+        print('opening tab:', i)
 
     # Waiting for every tabs to be stable.
     for i, url in enumerate(url_list):
@@ -82,7 +84,7 @@
         time.sleep(self._pause_after_switch)
 
         if i % 10 == 0:
-          print 'switching tab:', i
+          print('switching tab:', i)
 
 
 class CrosMultiTabTypical24Story(CrosMultiTabStory):
diff --git a/tools/perf/core/find_dependencies.py b/tools/perf/core/find_dependencies.py
index b7a8f8bd..4c7e232 100644
--- a/tools/perf/core/find_dependencies.py
+++ b/tools/perf/core/find_dependencies.py
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from __future__ import print_function
+
 import fnmatch
 import imp
 import logging
@@ -217,7 +219,7 @@
     dependencies = FindDependencies(target_paths, args)
     if args.zip:
       ZipDependencies(target_paths, dependencies, args)
-      print 'Zip archive written to %s.' % args.zip
+      print('Zip archive written to %s.' % args.zip)
     else:
-      print '\n'.join(sorted(dependencies))
+      print('\n'.join(sorted(dependencies)))
     return 0
diff --git a/tools/perf/core/minidump_unittest.py b/tools/perf/core/minidump_unittest.py
index 04d5f03..c587707 100644
--- a/tools/perf/core/minidump_unittest.py
+++ b/tools/perf/core/minidump_unittest.py
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from __future__ import print_function
+
 import logging
 import os
 import time
@@ -83,7 +85,7 @@
     self.assertTrue(crash_function in sections[3])
     # If we actually have a valid Crashpad stack, make sure it contains the
     # crash function as well.
-    print sections[4][:80]
+    print(sections[4][:80])
     if '**EMPTY**' not in sections[4]:
       self.assertTrue(crash_function in sections[4])
 
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py
index da1d1e5..08afc13 100755
--- a/tools/perf/core/perf_data_generator.py
+++ b/tools/perf/core/perf_data_generator.py
@@ -12,6 +12,8 @@
 //testing/buildbot that are consumed by the chromium recipe code.
 """
 
+from __future__ import print_function
+
 import argparse
 import collections
 import csv
@@ -821,10 +823,10 @@
 
 
 def merge_dicts(*dict_args):
-    result = {}
-    for dictionary in dict_args:
-      result.update(dictionary)
-    return result
+  result = {}
+  for dictionary in dict_args:
+    result.update(dictionary)
+  return result
 
 
 class BenchmarkMetadata(object):
@@ -981,7 +983,7 @@
         '//tools/perf/core/perf_data_generator.py.' % test_name)
 
   for message in error_messages:
-    print >> outstream, '*', textwrap.fill(message, 70), '\n'
+    print('*', textwrap.fill(message, 70), '\n', file=outstream)
 
   return not error_messages
 
@@ -1289,11 +1291,11 @@
         and validate_docs(labs_docs_file)
         and is_perf_benchmarks_scheduling_valid(
             perf_waterfall_file, outstream=sys.stderr)):
-      print 'All the perf config files are up-to-date. \\o/'
+      print('All the perf config files are up-to-date. \\o/')
       return 0
     else:
-      print ('Not all perf config files are up-to-date. Please run %s '
-             'to update them.') % sys.argv[0]
+      print('Not all perf config files are up-to-date. Please run %s '
+            'to update them.' % sys.argv[0])
       return 1
   else:
     update_all_tests(FYI_BUILDERS, fyi_waterfall_file)
diff --git a/tools/perf/core/results_dashboard.py b/tools/perf/core/results_dashboard.py
index 61eef02..477decc5 100755
--- a/tools/perf/core/results_dashboard.py
+++ b/tools/perf/core/results_dashboard.py
@@ -10,6 +10,8 @@
 # That file is now deprecated and this one is
 # the new source of truth.
 
+from __future__ import print_function
+
 import calendar
 import datetime
 import httplib
@@ -92,8 +94,8 @@
 
   for i in xrange(1, num_retries + 1):
     try:
-      print 'Sending %s result of %s to dashboard (attempt %i out of %i).' % (
-          data_type, data_label, i, num_retries)
+      print('Sending %s result of %s to dashboard (attempt %i out of %i).' %
+            (data_type, data_label, i, num_retries))
       if send_as_histograms:
         _SendHistogramJson(url, dashboard_data_str, token_generator_callback)
       else:
@@ -117,9 +119,9 @@
       break
 
   for err in errors:
-    print err
+    print(err)
 
-  print 'Time spent sending results to %s: %s' % (url, time.time() - start)
+  print('Time spent sending results to %s: %s' % (url, time.time() - start))
 
   return all_data_uploaded
 
@@ -267,8 +269,8 @@
     A dictionary in the format accepted by the perf dashboard.
   """
   if not chart_json:
-    print 'Error: No json output from telemetry.'
-    print '@@@STEP_FAILURE@@@'
+    print('Error: No json output from telemetry.')
+    print('@@@STEP_FAILURE@@@')
 
   point_id, versions = _RevisionNumberColumns(revision_dict, prefix='')
 
diff --git a/tools/perf/core/results_merger.py b/tools/perf/core/results_merger.py
index d7cbee0..e54d64a 100644
--- a/tools/perf/core/results_merger.py
+++ b/tools/perf/core/results_merger.py
@@ -8,6 +8,8 @@
 # This file is responsbile for merging JSON test results in both the simplified
 # JSON format and the Chromium JSON test results format version 3.
 
+from __future__ import print_function
+
 import copy
 import json
 import sys
@@ -278,7 +280,7 @@
   for f in files[1:]:
     sys.stderr.write('Merging %s\n' % f)
     result = merge_test_results([result, json.load(open(f))])
-  print json.dumps(result)
+  print(json.dumps(result))
   return 0
 
 
diff --git a/tools/perf/core/upload_results_to_perf_dashboard.py b/tools/perf/core/upload_results_to_perf_dashboard.py
index c8c9bb8..7b75f027 100755
--- a/tools/perf/core/upload_results_to_perf_dashboard.py
+++ b/tools/perf/core/upload_results_to_perf_dashboard.py
@@ -8,6 +8,8 @@
 # with sections copied from:
 # //build/scripts/slave/slave_utils.py
 
+from __future__ import print_function
+
 import json
 import optparse
 import os
@@ -41,7 +43,7 @@
   reference_build = 'reference' in options.name
   stripped_test_name = options.name.replace('.reference', '')
   results = {}
-  print 'Opening results file %s' % options.results_file
+  print('Opening results file %s' % options.results_file)
   with open(options.results_file) as f:
     results = json.load(f)
   dashboard_json = {}
@@ -93,8 +95,8 @@
         output_dir=output_dir,
         max_bytes=max_bytes)
     end_time = time.time()
-    print 'Duration of adding diagnostics for %s: %d seconds' % (
-        stripped_test_name, end_time - begin_time)
+    print('Duration of adding diagnostics for %s: %d seconds' %
+          (stripped_test_name, end_time - begin_time))
 
     # Read all batch files from output_dir.
     dashboard_jsons = []
@@ -140,7 +142,7 @@
     parser.error('configuration_name and results_url are required.')
 
   if not options.perf_dashboard_machine_group:
-    print 'Error: Invalid perf dashboard machine group'
+    print('Error: Invalid perf dashboard machine group')
     return 1
 
   if not options.send_as_histograms:
@@ -180,7 +182,7 @@
         return 1
   else:
     # The upload didn't fail since there was no data to upload.
-    print 'Warning: No perf dashboard JSON was produced.'
+    print('Warning: No perf dashboard JSON was produced.')
   return 0
 
 if __name__ == '__main__':
diff --git a/tools/perf/diagnose_test_failure b/tools/perf/diagnose_test_failure
index b6b9ff7..fa96e40 100755
--- a/tools/perf/diagnose_test_failure
+++ b/tools/perf/diagnose_test_failure
@@ -3,6 +3,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from __future__ import print_function
+
 import argparse
 import re
 import sys
@@ -25,7 +27,7 @@
 
 
 def _PrintWithColor(text, *colors):
-  print ''.join(colors) + text + _Color.ENDC
+  print(''.join(colors) + text + _Color.ENDC)
 
 
 def _ExtractBuildRevisionRange(build_page_content, build_url, test_name):
@@ -47,10 +49,10 @@
   ]
   for failure in _GLOBAL_FAILURE:
     if failure in build_page_content:
-      print
+      print(
       _PrintWithColor(
           "Warning: %s has '%s'."
-          ' Skipping this build' % (build_url, failure), _Color.WARNING)
+          ' Skipping this build' % (build_url, failure), _Color.WARNING))
       return True
   return False
 
@@ -65,7 +67,7 @@
   while True:
     current_build_url = initial_build_url + str(build_number)
     build_number -= 1
-    print '\rProcess %s' % current_build_url,
+    print('\rProcess %s' % current_build_url,)
     sys.stdout.flush()
     build_page_content = urllib2.urlopen(current_build_url).read()
     if _ShouldSkipBuild(build_page_content, build_url):
@@ -89,8 +91,8 @@
   options = parser.parse_args(args)
   first_failure_revisions, first_failed_build = FindFirstFailureRange(
       options.build_url, options.test_name)
-  print
-  print
+  print()
+  print()
   _PrintWithColor(
       'First failure range: %s - %s CLs' % (
           (min(first_failure_revisions), max(first_failure_revisions)),
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index 4ad0ee1..904ed0fc 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -302,6 +302,7 @@
 crbug.com/934270 [ win ] system_health.common_desktop/multitab:misc:typical24:2018 [ Skip ]
 crbug.com/931185 [ win7 ] system_health.common_desktop/browse:media:youtubetv:2019 [ Skip ]
 crbug.com/958422 [ win7 ] system_health.common_desktop/browse:social:tumblr_infinite_scroll:2018 [ Skip ]
+crbug.com/1008028 [ desktop ] system_health.common_desktop/browse:news:hackernews:2018 [ Skip ]
 
 # Benchmark: system_health.common_mobile
 crbug.com/914390 [ android-nexus-5 ] system_health.common_mobile/browse:chrome:newtab [ Skip ]
@@ -402,6 +403,7 @@
 crbug.com/954959 [ linux ] v8.browsing_desktop/browse:tools:maps [ Skip ]
 crbug.com/958422 v8.browsing_desktop/browse:social:tumblr_infinite_scroll:2018 [ Skip ]
 crbug.com/958507 [ desktop ] v8.browsing_desktop/browse:media:imgur [ Skip ]
+crbug.com/1008028 [ desktop ] v8.browsing_desktop/browse:news:hackernews:2018 [ Skip ]
 
 # Benchmark v8.browsing_desktop-future
 crbug.com/788796 [ linux ] v8.browsing_desktop-future/browse:media:imgur [ Skip ]
@@ -411,6 +413,7 @@
 crbug.com/953371 [ win ] v8.browsing_desktop-future/browse:social:twitter_infinite_scroll:2018 [ Skip ]
 crbug.com/958422 v8.browsing_desktop-future/browse:social:tumblr_infinite_scroll:2018 [ Skip ]
 crbug.com/958507 [ desktop ] v8.browsing_desktop-future/browse:media:imgur [ Skip ]
+crbug.com/1008028 [ desktop ] v8.browsing_desktop-future/browse:news:hackernews:2018 [ Skip ]
 
 # Benchmark: v8.browsing_mobile
 crbug.com/958034 [ android-go android-webview ] v8.browsing_mobile/* [ Skip ]
diff --git a/tools/perf/generate_perf_sharding b/tools/perf/generate_perf_sharding
index 80d4869..cb2cf80 100755
--- a/tools/perf/generate_perf_sharding
+++ b/tools/perf/generate_perf_sharding
@@ -3,6 +3,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from __future__ import print_function
+
 import argparse
 import collections
 import json
@@ -145,7 +147,7 @@
   data = retrieve_story_timing.FetchAverageStortyTimingData(
       configurations=[builder_name], num_last_days=5)
   _DumpJson(data, timing_file_path)
-  print 'Finish retrieve story timing data for %s' % repr(builder_name)
+  print('Finish retrieve story timing data for %s' % repr(builder_name))
 
 
 def _GenerateShardMap(
@@ -176,10 +178,10 @@
              'perf-sheriffs@chromium.org and put a warning about expected '
              'false regressions in your CL '
              'description')
-  print textwrap.fill(message, 70), '\n'
+  print(textwrap.fill(message, 70), '\n')
   answer = raw_input("Enter 'y' to continue: ")
   if answer != 'y':
-    print 'Abort updating shard maps for benchmarks on perf waterfall'
+    print('Abort updating shard maps for benchmarks on perf waterfall')
     sys.exit(0)
 
 
@@ -197,7 +199,7 @@
     _PromptWarning()
 
   if not args.use_old_timing_data:
-    print 'Update shards timing data. May take a while...'
+    print('Update shards timing data. May take a while...')
     load_timing_args = []
     for b in builders:
       load_timing_args.append((b.name, b.timing_file_path))
@@ -207,7 +209,7 @@
   for b in builders:
     _GenerateShardMap(
         b, b.num_shards, b.shards_map_file_path, args.debug, benchmark=None)
-    print 'Updated sharding map for %s' % repr(b.name)
+    print('Updated sharding map for %s' % repr(b.name))
 
 
 def _CreateShardMapForBenchmark(args):
@@ -250,7 +252,7 @@
             del benchmarks[benchmark]
     os.remove(b.shards_map_file_path)
     _DumpJson(shards_map, b.shards_map_file_path)
-  print 'done.'
+  print('done.')
 
 
 def _ParseBenchmarks(shard_map_path):
@@ -313,7 +315,7 @@
                   'UNSCHEDULED_{benchmark}'.format(benchmark=benchmark))
 
   for error in errors:
-    print >> sys.stderr, '*', textwrap.fill(error, 70), '\n'
+    print('*', textwrap.fill(error, 70), '\n', file=sys.stderr)
   if errors:
     return 1
   return 0
diff --git a/tools/perf/list_benchmarks b/tools/perf/list_benchmarks
index 3e2c542..6a6f7ace 100755
--- a/tools/perf/list_benchmarks
+++ b/tools/perf/list_benchmarks
@@ -2,6 +2,9 @@
 # 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.
+
+from __future__ import print_function
+
 import optparse
 import sys
 
@@ -31,7 +34,7 @@
     benchmarks = benchmark_finders.GetOfficialBenchmarks()
 
   for b in benchmarks:
-    print '{:<60}'.format(b.Name())
+    print('{:<60}'.format(b.Name()))
 
 
 if __name__ == '__main__':
diff --git a/tools/perf/process_perf_results.py b/tools/perf/process_perf_results.py
index 40c2d98..f07ed5b 100755
--- a/tools/perf/process_perf_results.py
+++ b/tools/perf/process_perf_results.py
@@ -3,6 +3,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from __future__ import print_function
+
 import argparse
 import collections
 import json
@@ -195,7 +197,7 @@
             # Output is null meaning the test didn't produce any results.
             # Want to output an error and continue loading the rest of the
             # test results.
-            print 'No results produced for %s, skipping upload' % directory
+            print('No results produced for %s, skipping upload' % directory)
             continue
           if json_results.get('version') == 3:
             # Non-telemetry tests don't have written json results but
@@ -216,7 +218,8 @@
       if not enabled:
         # We don't upload disabled benchmarks or tests that are run
         # as a smoke test
-        print 'Benchmark %s ran no tests on at least one shard' % benchmark_name
+        print(
+            'Benchmark %s ran no tests on at least one shard' % benchmark_name)
         continue
       benchmark_enabled_map[benchmark_name] = True
 
@@ -432,8 +435,8 @@
       results_filename = os.path.join(directories[0], 'perf_results.json')
 
     results_size_in_mib = os.path.getsize(results_filename) / (2 ** 20)
-    print 'Uploading perf results from %s benchmark (size %s Mib)' % (
-        benchmark_name, results_size_in_mib)
+    print('Uploading perf results from %s benchmark (size %s Mib)' %
+          (benchmark_name, results_size_in_mib))
     with open(output_json_file, 'w') as oj:
       upload_return_code = _upload_perf_results(
         results_filename,
@@ -566,14 +569,14 @@
         json.dump(results, output_json_file,
                 indent=4, separators=(',', ': '))
       except ValueError:
-        print ('Error parsing perf results JSON for benchmark  %s' %
-               benchmark_name)
+        print('Error parsing perf results JSON for benchmark  %s' %
+              benchmark_name)
 
     output_json_file.close()
     viewer_url = output_json_file.get_viewer_url()
   else:
-    print ("Perf results JSON file doesn't exist for benchmark %s" %
-           benchmark_name)
+    print("Perf results JSON file doesn't exist for benchmark %s" %
+          benchmark_name)
 
   base_benchmark_name = benchmark_name.replace('.reference', '')
 
@@ -599,11 +602,12 @@
 
 
 def print_duration(step, start, end):
-  print 'Duration of %s: %d seconds' % (step, end-start)
+  print('Duration of %s: %d seconds' % (step, end - start))
+
 
 def main():
   """ See collect_task.collect_task for more on the merge script API. """
-  print sys.argv
+  print(sys.argv)
   parser = argparse.ArgumentParser()
   # configuration-name (previously perf-id) is the name of bot the tests run on
   # For example, buildbot-test is the name of the android-go-perf bot
diff --git a/tools/resources/find_unused_resources.py b/tools/resources/find_unused_resources.py
index eab5ba3..8bf838a 100755
--- a/tools/resources/find_unused_resources.py
+++ b/tools/resources/find_unused_resources.py
@@ -15,6 +15,8 @@
   tools/resources/find_unused_resouces.py chrome/browser/browser_resources.grd
 """
 
+from __future__ import print_function
+
 __author__ = 'jamescook@chromium.org (James Cook)'
 
 
@@ -87,7 +89,7 @@
   unused_resources = []
   grd_file = open(grd_filepath, 'r')
   grd_data = grd_file.read()
-  print 'Checking:'
+  print('Checking:')
   # Match the resource id and file path out of substrings like:
   # ...name="IDR_FOO_123" file="common/foo.png"...
   # by matching between the quotation marks.
@@ -113,7 +115,7 @@
     searched.add(key)
 
     # Print progress as we go along.
-    print resource_id
+    print(resource_id)
 
     # Ensure the resource isn't used anywhere by checking both for the resource
     # id (which should appear in C++ code) and the raw filename (in case the
@@ -124,7 +126,7 @@
     # other matching files, it is unused.
     if len(matching_files) == 1:
       # Give the user some happy news.
-      print 'Unused!'
+      print('Unused!')
       unused_resources.append([resource_id, filepath])
 
   return unused_resources
@@ -157,47 +159,47 @@
 def main():
   # The script requires exactly one parameter, the .grd file path.
   if len(sys.argv) != 2:
-    print 'Usage: tools/resources/find_unused_resources.py <path/to/grd>'
+    print('Usage: tools/resources/find_unused_resources.py <path/to/grd>')
     sys.exit(1)
   grd_filepath = sys.argv[1]
 
   # Try to ensure we are in a source checkout.
   current_dir = os.getcwd()
   if os.path.basename(current_dir) != 'src':
-    print 'Script must be run in your "src" directory.'
+    print('Script must be run in your "src" directory.')
     sys.exit(1)
 
   # We require a git checkout to use git grep.
   if not os.path.exists(current_dir + '/.git'):
-    print 'You must use a git checkout for this script to run.'
-    print current_dir + '/.git', 'not found.'
+    print('You must use a git checkout for this script to run.')
+    print(current_dir + '/.git', 'not found.')
     sys.exit(1)
 
   # Look up the scale-factor directories.
   resources_path = os.path.dirname(grd_filepath)
   scale_directories = GetScaleDirectories(resources_path)
   if not scale_directories:
-    print 'No scale directories (like "default_100_percent") found.'
+    print('No scale directories (like "default_100_percent") found.')
     sys.exit(1)
 
   # |unused_resources| stores pairs of [resource_id, filepath] for resource ids
   # that are not referenced in the code.
   unused_resources = GetUnusedResources(grd_filepath)
   if not unused_resources:
-    print 'All resources are used.'
+    print('All resources are used.')
     sys.exit(0)
 
   # Dump our output for the user.
-  print
-  print 'Unused resource ids:'
+  print()
+  print('Unused resource ids:')
   for resource_id, filepath in unused_resources:
-    print resource_id
+    print(resource_id)
   # Print a list of 'git rm' command lines to remove unused assets.
-  print
-  print 'Unused files:'
+  print()
+  print('Unused files:')
   for resource_id, filepath in unused_resources:
     for directory in scale_directories:
-      print 'git rm ' + os.path.join(directory, filepath)
+      print('git rm ' + os.path.join(directory, filepath))
 
 
 if __name__ == '__main__':
diff --git a/tools/resources/list_resources_removed_by_repack.py b/tools/resources/list_resources_removed_by_repack.py
index 0fb21f7..fb38531 100755
--- a/tools/resources/list_resources_removed_by_repack.py
+++ b/tools/resources/list_resources_removed_by_repack.py
@@ -3,6 +3,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from __future__ import print_function
 
 import os
 import re
@@ -78,16 +79,16 @@
         resource_id = int(match.group('resource_id'))
         resource_name = match.group('resource_name')
         if resource_id in resource_id_to_name_file_map:
-          print 'Duplicate:', resource_id
-          print (resource_name, f)
-          print resource_id_to_name_file_map[resource_id]
+          print('Duplicate:', resource_id)
+          print(resource_name, f)
+          print(resource_id_to_name_file_map[resource_id])
           raise
         resource_id_to_name_file_map[resource_id] = (resource_name, f)
 
   unused_resources = GetResourceIdsFromRepackMessage(sys.stdin)
   for resource_id in unused_resources:
     if resource_id not in resource_id_to_name_file_map:
-      print 'WARNING: Unknown resource id', resource_id
+      print('WARNING: Unknown resource id', resource_id)
       continue
     (resource_name, filename) = resource_id_to_name_file_map[resource_id]
     sys.stdout.write('%d: %s in %s\n' % (resource_id, resource_name, filename))
diff --git a/tools/resources/list_unused_grit_header.py b/tools/resources/list_unused_grit_header.py
index 2980310..a24fb44 100755
--- a/tools/resources/list_unused_grit_header.py
+++ b/tools/resources/list_unused_grit_header.py
@@ -10,6 +10,8 @@
   tools/resources/list_unused_grit_header.py ui/strings/ui_strings.grd chrome ui
 """
 
+from __future__ import print_function
+
 import os
 import sys
 import xml.etree.ElementTree
@@ -20,7 +22,7 @@
 
 
 def Usage(prog_name):
-  print prog_name, 'GRD_FILE PATHS_TO_SCAN'
+  print(prog_name, 'GRD_FILE PATHS_TO_SCAN')
 
 
 def FilterResourceIds(resource_id):
@@ -197,13 +199,13 @@
   paths_to_scan = argv[2:]
   for f in paths_to_scan:
     if not os.path.exists(f):
-      print 'Error: %s does not exist' % f
+      print('Error: %s does not exist' % f)
       return 1
 
   tree = xml.etree.ElementTree.parse(grd_file)
   grit_header = GetOutputHeaderFile(tree)
   if not grit_header:
-    print 'Error: %s does not generate any output headers.' % grd_file
+    print('Error: %s does not generate any output headers.' % grd_file)
     return 1
 
   resources = GetResourcesForGrdFile(tree, grd_file)
@@ -222,10 +224,10 @@
       if not NeedsGritInclude(grit_header, resources, path_to_scan):
         files_with_unneeded_grit_includes.append(path_to_scan)
     else:
-      print 'Warning: Skipping %s' % path_to_scan
+      print('Warning: Skipping %s' % path_to_scan)
 
   if files_with_unneeded_grit_includes:
-    print '\n'.join(files_with_unneeded_grit_includes)
+    print('\n'.join(files_with_unneeded_grit_includes))
     return 2
   return 0
 
diff --git a/tools/resources/svgo.py b/tools/resources/svgo.py
index 7b4089c..174b21c 100755
--- a/tools/resources/svgo.py
+++ b/tools/resources/svgo.py
@@ -3,6 +3,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from __future__ import print_function
+
 
 def Run(os_path=None, args=None):
   _HERE_PATH = os_path.dirname(os_path.realpath(__file__))
@@ -23,4 +25,4 @@
 if __name__ == '__main__':
   import os
   import sys
-  print Run(os_path=os.path, args=sys.argv[1:])
+  print(Run(os_path=os.path, args=sys.argv[1:]))
diff --git a/tools/safely-roll-deps.py b/tools/safely-roll-deps.py
index 15e3ab6..1081ae0 100755
--- a/tools/safely-roll-deps.py
+++ b/tools/safely-roll-deps.py
@@ -8,6 +8,8 @@
 commit-queue's checks.
 """
 
+from __future__ import print_function
+
 import logging
 import optparse
 import os
@@ -23,7 +25,7 @@
 
 
 def die_with_error(msg):
-  print >> sys.stderr, msg
+  print(msg, file=sys.stderr)
   sys.exit(1)
 
 
@@ -52,7 +54,7 @@
   """Wrapper for subprocess2 which prints out every command."""
   def __getattr__(self, attr):
     def _run_subprocess2(cmd, *args, **kwargs):
-      print cmd
+      print(cmd)
       sys.stdout.flush()
       return getattr(subprocess2, attr)(cmd, *args, **kwargs)
     return _run_subprocess2
@@ -130,7 +132,7 @@
   try:
     old_rev = process_deps(os.path.join(root_dir, 'DEPS'), project, new_rev,
                            options.dry_run)
-    print '%s roll %s:%s' % (project.title(), old_rev, new_rev)
+    print('%s roll %s:%s' % (project.title(), old_rev, new_rev))
 
     review_field = 'TBR' if options.commit else 'R'
     commit_msg = options.message or '%s roll %s:%s\n' % (project.title(),
@@ -138,7 +140,7 @@
     commit_msg += '\n%s=%s\n' % (review_field, options.reviewers)
 
     if options.dry_run:
-      print 'Commit message: ' + commit_msg
+      print('Commit message: ' + commit_msg)
       return 0
 
     prnt_subprocess.check_output(['git', 'commit', '-m', commit_msg, 'DEPS'])
diff --git a/tools/security/check_message_owners.py b/tools/security/check_message_owners.py
index b3793f6..251c0bc8 100755
--- a/tools/security/check_message_owners.py
+++ b/tools/security/check_message_owners.py
@@ -5,6 +5,8 @@
 
 """Make sure all of the per-file *_messages.h OWNERS are consistent"""
 
+from __future__ import print_function
+
 import os
 import re
 import sys
@@ -47,7 +49,8 @@
   for key in owner_dict:
     for owner in owner_set:
       if not owner in owner_dict[key]:
-        print key + " is missing " + owner
+        print(key + " is missing " + owner)
+
 
 if '__main__' == __name__:
   sys.exit(main())
diff --git a/tools/security/idn_test_case_generator.py b/tools/security/idn_test_case_generator.py
index 986d4beb..1d0eab6 100755
--- a/tools/security/idn_test_case_generator.py
+++ b/tools/security/idn_test_case_generator.py
@@ -9,6 +9,8 @@
 from Python shell (see make_case documentation).
 """
 
+from __future__ import print_function
+
 import argparse
 import codecs
 import doctest
diff --git a/tools/tcmalloc/print-live-objects.py b/tools/tcmalloc/print-live-objects.py
index dfed9c6..836a56b4 100755
--- a/tools/tcmalloc/print-live-objects.py
+++ b/tools/tcmalloc/print-live-objects.py
@@ -7,6 +7,8 @@
 HeapProfilerDumpLiveObjects.
 """
 
+from __future__ import print_function
+
 import os
 import re
 import subprocess
@@ -14,10 +16,11 @@
 import tempfile
 
 def usage():
-  print """\
+  print("""\
 Usage:
   tools/tcmalloc/print-live-objects.py out/Debug/chrome leaks.dmp
-"""
+""")
+
 
 def LoadDump(dump_file):
   result = []
@@ -29,7 +32,7 @@
       line_no = line_no + 1
       matches = leakfmt.match(line)
       if not matches:
-        print "%s: could not parse line %d, skipping" % (dump_file, line_no)
+        print("%s: could not parse line %d, skipping" % (dump_file, line_no))
       else:
         trace = { "size": int(matches.group(1)),
                   "address": matches.group(2),
@@ -67,7 +70,7 @@
 
 def Main(argv):
   if sys.platform != 'linux2':
-    print 'print-live-objects.py requires addr2line only present on Linux.'
+    print('print-live-objects.py requires addr2line only present on Linux.')
     sys.exit(1)
 
   if len(argv) != 3:
@@ -78,13 +81,13 @@
   Symbolize(argv[1], traces)
 
   if not traces:
-    print "No leaks found!"
+    print("No leaks found!")
 
   for trace in sorted(traces, key=lambda x: -x["size"]):
-    print "Leak of %d bytes at address %s" % (trace["size"], trace["address"])
+    print("Leak of %d bytes at address %s" % (trace["size"], trace["address"]))
     for frame in trace["frames"]:
-      print "  %s (%s)" % (frame["name"], frame["location"])
-    print ""
+      print("  %s (%s)" % (frame["name"], frame["location"]))
+    print("")
 
 
 if __name__ == '__main__':
diff --git a/ui/android/java/src/org/chromium/ui/base/Clipboard.java b/ui/android/java/src/org/chromium/ui/base/Clipboard.java
index 2b41f206..5aeee84 100644
--- a/ui/android/java/src/org/chromium/ui/base/Clipboard.java
+++ b/ui/android/java/src/org/chromium/ui/base/Clipboard.java
@@ -23,6 +23,7 @@
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.NativeMethods;
+import org.chromium.base.compat.ApiHelperForO;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.ui.R;
 import org.chromium.ui.widget.Toast;
@@ -226,7 +227,7 @@
         ClipDescription clipDescription = mClipboardManager.getPrimaryClipDescription();
         if (clipDescription == null) return;
 
-        long timestamp = clipDescription.getTimestamp();
+        long timestamp = ApiHelperForO.getTimestamp(clipDescription);
         ClipboardJni.get().onPrimaryClipTimestampInvalidated(
                 mNativeClipboard, Clipboard.this, timestamp);
     }
diff --git a/ui/events/blink/input_handler_proxy.cc b/ui/events/blink/input_handler_proxy.cc
index 56c68ae..5f260ead 100644
--- a/ui/events/blink/input_handler_proxy.cc
+++ b/ui/events/blink/input_handler_proxy.cc
@@ -521,7 +521,8 @@
         CHECK(input_handler_);
         cc::InputHandlerPointerResult pointer_result =
             input_handler_->MouseDown(
-                gfx::PointF(mouse_event.PositionInWidget()));
+                gfx::PointF(mouse_event.PositionInWidget()),
+                event.GetModifiers() & WebInputEvent::kShiftKey);
         if (pointer_result.type == cc::PointerResultType::kScrollbarScroll) {
           // Generate GSB and GSU events and add them to the
           // CompositorThreadEventQueue.
diff --git a/ui/events/blink/input_handler_proxy_unittest.cc b/ui/events/blink/input_handler_proxy_unittest.cc
index 838f22a..a2c3188 100644
--- a/ui/events/blink/input_handler_proxy_unittest.cc
+++ b/ui/events/blink/input_handler_proxy_unittest.cc
@@ -142,8 +142,8 @@
 
   void BindToClient(cc::InputHandlerClient* client) override {}
 
-  cc::InputHandlerPointerResult MouseDown(
-      const gfx::PointF& mouse_position) override {
+  cc::InputHandlerPointerResult MouseDown(const gfx::PointF& mouse_position,
+                                          const bool shift_modifier) override {
     cc::InputHandlerPointerResult pointer_result;
     pointer_result.type = cc::kScrollbarScroll;
     pointer_result.scroll_offset = gfx::ScrollOffset(0, 1);
diff --git a/ui/events/blink/prediction/input_predictor.h b/ui/events/blink/prediction/input_predictor.h
index fb68fb6..0dd238d 100644
--- a/ui/events/blink/prediction/input_predictor.h
+++ b/ui/events/blink/prediction/input_predictor.h
@@ -60,13 +60,13 @@
   static constexpr base::TimeDelta kTimeInterval =
       base::TimeDelta::FromMilliseconds(8);
   // Minimum time interval between events.
-  static constexpr base::TimeDelta kMinimumTimeInterval =
+  static constexpr base::TimeDelta kMinTimeInterval =
       base::TimeDelta::FromMillisecondsD(2.5);
 
-  // Maximum amount of prediction when resampling
+  // Maximum amount of prediction when resampling.
   static constexpr base::TimeDelta kMaxResampleTime =
       base::TimeDelta::FromMilliseconds(20);
-  // Maximum time delta for prediction
+  // Maximum time delta for prediction.
   static constexpr base::TimeDelta kMaxPredictionTime =
       base::TimeDelta::FromMilliseconds(25);
 };
diff --git a/ui/events/blink/prediction/kalman_predictor.cc b/ui/events/blink/prediction/kalman_predictor.cc
index dd3ff766..8a50f94 100644
--- a/ui/events/blink/prediction/kalman_predictor.cc
+++ b/ui/events/blink/prediction/kalman_predictor.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#define _USE_MATH_DEFINES  // For VC++ to get M_PI. This has to be first.
+
 #include "ui/events/blink/prediction/kalman_predictor.h"
 #include "ui/events/blink/prediction/predictor_factory.h"
 
@@ -20,9 +22,11 @@
 constexpr base::TimeDelta InputPredictor::kMaxResampleTime;
 constexpr base::TimeDelta InputPredictor::kMaxPredictionTime;
 constexpr base::TimeDelta InputPredictor::kTimeInterval;
-constexpr base::TimeDelta InputPredictor::kMinimumTimeInterval;
+constexpr base::TimeDelta InputPredictor::kMinTimeInterval;
+constexpr base::TimeDelta KalmanPredictor::kMaxTimeInQueue;
 
-KalmanPredictor::KalmanPredictor() = default;
+KalmanPredictor::KalmanPredictor(HeuristicsMode heuristics_mode)
+    : heuristics_mode_(heuristics_mode) {}
 
 KalmanPredictor::~KalmanPredictor() = default;
 
@@ -33,15 +37,15 @@
 void KalmanPredictor::Reset() {
   x_predictor_.Reset();
   y_predictor_.Reset();
-  last_point_.time_stamp = base::TimeTicks();
+  last_points_.clear();
   time_filter_.Reset();
 }
 
 void KalmanPredictor::Update(const InputData& cur_input) {
   base::TimeDelta dt;
-  if (!last_point_.time_stamp.is_null()) {
+  if (last_points_.size()) {
     // When last point is kMaxTimeDelta away, consider it is incontinuous.
-    dt = cur_input.time_stamp - last_point_.time_stamp;
+    dt = cur_input.time_stamp - last_points_.back().time_stamp;
     if (dt > kMaxTimeDelta)
       Reset();
     else
@@ -49,9 +53,14 @@
   }
 
   double dt_ms = time_filter_.GetPosition();
-  last_point_ = cur_input;
+  last_points_.push_back(cur_input);
   x_predictor_.Update(cur_input.pos.x(), dt_ms);
   y_predictor_.Update(cur_input.pos.y(), dt_ms);
+
+  while (last_points_.back().time_stamp - last_points_.front().time_stamp >
+         kMaxTimeInQueue) {
+    last_points_.pop_front();
+  }
 }
 
 bool KalmanPredictor::HasPrediction() const {
@@ -63,17 +72,37 @@
   if (!HasPrediction())
     return false;
 
-  float pred_dt = (predict_time - last_point_.time_stamp).InMillisecondsF();
+  DCHECK(last_points_.size());
+  float pred_dt =
+      (predict_time - last_points_.back().time_stamp).InMillisecondsF();
 
   std::vector<InputData> pred_points;
-  gfx::Vector2dF position(last_point_.pos.x(), last_point_.pos.y());
-  // gfx::Vector2dF position = PredictPosition();
+  gfx::Vector2dF position(last_points_.back().pos.x(),
+                          last_points_.back().pos.y());
   gfx::Vector2dF velocity = PredictVelocity();
   gfx::Vector2dF acceleration = PredictAcceleration();
 
-  position +=
-      ScaleVector2d(velocity, kVelocityInfluence * pred_dt) +
-      ScaleVector2d(acceleration, kAccelerationInfluence * pred_dt * pred_dt);
+  position += ScaleVector2d(velocity, kVelocityInfluence * pred_dt);
+
+  if (heuristics_mode_ == HeuristicsMode::kHeuristicsEnabled) {
+    float points_angle = 0.0f;
+    for (size_t i = 2; i < last_points_.size(); i++) {
+      gfx::Vector2dF first_dir =
+          last_points_[i - 1].pos - last_points_[i - 2].pos;
+      gfx::Vector2dF second_dir = last_points_[i].pos - last_points_[i - 1].pos;
+      if (first_dir.Length() && second_dir.Length()) {
+        points_angle += atan2(first_dir.x(), first_dir.y()) -
+                        atan2(second_dir.x(), second_dir.y());
+      }
+    }
+    if (abs(points_angle) * 180 / M_PI > 15) {
+      position += ScaleVector2d(acceleration,
+                                kAccelerationInfluence * pred_dt * pred_dt);
+    }
+  } else {
+    position +=
+        ScaleVector2d(acceleration, kAccelerationInfluence * pred_dt * pred_dt);
+  }
 
   result->pos.set_x(position.x());
   result->pos.set_y(position.y());
@@ -82,8 +111,8 @@
 
 base::TimeDelta KalmanPredictor::TimeInterval() const {
   return time_filter_.GetPosition()
-             ? std::max(kMinimumTimeInterval, base::TimeDelta::FromMilliseconds(
-                                                  time_filter_.GetPosition()))
+             ? std::max(kMinTimeInterval, base::TimeDelta::FromMilliseconds(
+                                              time_filter_.GetPosition()))
              : kTimeInterval;
 }
 
diff --git a/ui/events/blink/prediction/kalman_predictor.h b/ui/events/blink/prediction/kalman_predictor.h
index 1acfe0f..9109ed4 100644
--- a/ui/events/blink/prediction/kalman_predictor.h
+++ b/ui/events/blink/prediction/kalman_predictor.h
@@ -5,6 +5,7 @@
 #ifndef UI_EVENTS_BLINK_PREDICTION_KALMAN_PREDICTOR_H_
 #define UI_EVENTS_BLINK_PREDICTION_KALMAN_PREDICTOR_H_
 
+#include <deque>
 #include <vector>
 
 #include "ui/events/blink/prediction/input_predictor.h"
@@ -19,7 +20,9 @@
 // be used to predict one dimension (x, y).
 class KalmanPredictor : public InputPredictor {
  public:
-  explicit KalmanPredictor();
+  enum class HeuristicsMode { kHeuristicsDisabled, kHeuristicsEnabled };
+
+  explicit KalmanPredictor(HeuristicsMode heuristics_mode);
   ~KalmanPredictor() override;
 
   const char* GetName() const override;
@@ -54,8 +57,16 @@
   // Filter to smooth time intervals.
   KalmanFilter time_filter_;
 
-  // The last input point.
-  InputData last_point_;
+  // Most recent input data.
+  std::deque<InputData> last_points_;
+
+  // Maximum time interval between first and last events in last points queue.
+  static constexpr base::TimeDelta kMaxTimeInQueue =
+      base::TimeDelta::FromMilliseconds(40);
+
+  // Flag to determine heuristic behavior based on the accumulated angle between
+  // the last set of points.
+  const HeuristicsMode heuristics_mode_;
 
   DISALLOW_COPY_AND_ASSIGN(KalmanPredictor);
 };
diff --git a/ui/events/blink/prediction/kalman_predictor_unittest.cc b/ui/events/blink/prediction/kalman_predictor_unittest.cc
index 98a51a1f..ef63dba 100644
--- a/ui/events/blink/prediction/kalman_predictor_unittest.cc
+++ b/ui/events/blink/prediction/kalman_predictor_unittest.cc
@@ -44,7 +44,8 @@
   explicit KalmanPredictorTest() {}
 
   void SetUp() override {
-    predictor_ = std::make_unique<ui::KalmanPredictor>();
+    predictor_ = std::make_unique<ui::KalmanPredictor>(
+        ui::KalmanPredictor::HeuristicsMode::kHeuristicsDisabled);
   }
 
   DISALLOW_COPY_AND_ASSIGN(KalmanPredictorTest);
@@ -132,7 +133,6 @@
 
 // Tests the kalman predictor time interval filter.
 TEST_F(KalmanPredictorTest, TimeInterval) {
-  predictor_ = std::make_unique<ui::KalmanPredictor>();
   EXPECT_EQ(predictor_->TimeInterval(), kExpectedDefaultTimeInterval);
   std::vector<double> x = {0, 2, 8, 18};
   std::vector<double> y = {10, 11, 14, 19};
@@ -146,5 +146,41 @@
             base::TimeDelta::FromMilliseconds(7).InMillisecondsF());
 }
 
+// Test the benefit from the heuristic approach on noisy data.
+TEST_F(KalmanPredictorTest, HeuristicApproach) {
+  std::unique_ptr<InputPredictor> heuristic_predictor =
+      std::make_unique<ui::KalmanPredictor>(
+          ui::KalmanPredictor::HeuristicsMode::kHeuristicsEnabled);
+  std::vector<double> x_stabilizer = {-40, -32, -24, -16, -8, 0};
+  std::vector<double> y_stabilizer = {-40, -32, -24, -16, -8, 0};
+  std::vector<double> t_stabilizer = {-40, -32, -24, -16, -8, 0};
+  for (size_t i = 0; i < t_stabilizer.size(); i++) {
+    InputPredictor::InputData data = {
+        gfx::PointF(x_stabilizer[i], y_stabilizer[i]),
+        FromMilliseconds(t_stabilizer[i])};
+    predictor_->Update(data);
+    heuristic_predictor->Update(data);
+  }
+
+  std::vector<double> x = {7, 17, 23, 33, 39, 49, 60};
+  std::vector<double> y = {9, 15, 25, 31, 41, 47, 60};
+  std::vector<double> t = {8, 16, 24, 32, 40, 48, 60};
+  for (size_t i = 0; i < t.size(); i++) {
+    gfx::PointF point(x[i], y[i]);
+    if (heuristic_predictor->HasPrediction() && predictor_->HasPrediction()) {
+      ui::InputPredictor::InputData result, heuristic_result;
+      EXPECT_TRUE(heuristic_predictor->GeneratePrediction(
+          FromMilliseconds(t[i]), &heuristic_result));
+      EXPECT_TRUE(
+          predictor_->GeneratePrediction(FromMilliseconds(t[i]), &result));
+      EXPECT_LE((heuristic_result.pos - point).Length(),
+                (result.pos - point).Length());
+    }
+    InputPredictor::InputData data = {point, FromMilliseconds(t[i])};
+    heuristic_predictor->Update(data);
+    predictor_->Update(data);
+  }
+}
+
 }  // namespace test
 }  // namespace ui
diff --git a/ui/events/blink/prediction/least_squares_predictor.cc b/ui/events/blink/prediction/least_squares_predictor.cc
index fcb935a..9a5a1c3 100644
--- a/ui/events/blink/prediction/least_squares_predictor.cc
+++ b/ui/events/blink/prediction/least_squares_predictor.cc
@@ -100,7 +100,7 @@
 
 base::TimeDelta LeastSquaresPredictor::TimeInterval() const {
   if (time_.size() > 1) {
-    return std::max(kMinimumTimeInterval,
+    return std::max(kMinTimeInterval,
                     (time_.back() - time_.front()) / (time_.size() - 1));
   }
   return kTimeInterval;
diff --git a/ui/events/blink/prediction/linear_predictor.cc b/ui/events/blink/prediction/linear_predictor.cc
index e060db5..7e8e514 100644
--- a/ui/events/blink/prediction/linear_predictor.cc
+++ b/ui/events/blink/prediction/linear_predictor.cc
@@ -116,9 +116,9 @@
 
 base::TimeDelta LinearPredictor::TimeInterval() const {
   if (events_queue_.size() > 1) {
-    return std::max(kMinimumTimeInterval, (events_queue_.back().time_stamp -
-                                           events_queue_.front().time_stamp) /
-                                              (events_queue_.size() - 1));
+    return std::max(kMinTimeInterval, (events_queue_.back().time_stamp -
+                                       events_queue_.front().time_stamp) /
+                                          (events_queue_.size() - 1));
   }
   return kTimeInterval;
 }
diff --git a/ui/events/blink/prediction/predictor_factory.cc b/ui/events/blink/prediction/predictor_factory.cc
index bceef0693..7ac8f15 100644
--- a/ui/events/blink/prediction/predictor_factory.cc
+++ b/ui/events/blink/prediction/predictor_factory.cc
@@ -16,6 +16,7 @@
 
 const char kScrollPredictorNameLsq[] = "lsq";
 const char kScrollPredictorNameKalman[] = "kalman";
+const char kScrollPredictorNameKalmanHeuristic[] = "kalman_heuristic";
 const char kScrollPredictorNameLinearFirst[] = "linear_first";
 const char kScrollPredictorNameLinearSecond[] = "linear_second";
 const char kScrollPredictorNameLinearResampling[] = "linear_resampling";
@@ -35,6 +36,9 @@
     return PredictorType::kScrollPredictorTypeLsq;
   else if (predictor_name == input_prediction::kScrollPredictorNameKalman)
     return PredictorType::kScrollPredictorTypeKalman;
+  else if (predictor_name ==
+           input_prediction::kScrollPredictorNameKalmanHeuristic)
+    return PredictorType::kScrollPredictorTypeKalmanHeuristic;
   else if (predictor_name == input_prediction::kScrollPredictorNameLinearFirst)
     return PredictorType::kScrollPredictorTypeLinearFirst;
   else if (predictor_name == input_prediction::kScrollPredictorNameLinearSecond)
@@ -50,7 +54,11 @@
   else if (predictor_type == PredictorType::kScrollPredictorTypeLsq)
     return std::make_unique<LeastSquaresPredictor>();
   else if (predictor_type == PredictorType::kScrollPredictorTypeKalman)
-    return std::make_unique<KalmanPredictor>();
+    return std::make_unique<KalmanPredictor>(
+        KalmanPredictor::HeuristicsMode::kHeuristicsDisabled);
+  else if (predictor_type == PredictorType::kScrollPredictorTypeKalmanHeuristic)
+    return std::make_unique<KalmanPredictor>(
+        KalmanPredictor::HeuristicsMode::kHeuristicsEnabled);
   else if (predictor_type == PredictorType::kScrollPredictorTypeLinearFirst)
     return std::make_unique<LinearPredictor>(
         LinearPredictor::EquationOrder::kFirstOrder);
diff --git a/ui/events/blink/prediction/predictor_factory.h b/ui/events/blink/prediction/predictor_factory.h
index 5fca684..1835297 100644
--- a/ui/events/blink/prediction/predictor_factory.h
+++ b/ui/events/blink/prediction/predictor_factory.h
@@ -13,6 +13,7 @@
 
 extern const char kScrollPredictorNameLsq[];
 extern const char kScrollPredictorNameKalman[];
+extern const char kScrollPredictorNameKalmanHeuristic[];
 extern const char kScrollPredictorNameLinearFirst[];
 extern const char kScrollPredictorNameLinearSecond[];
 extern const char kScrollPredictorNameLinearResampling[];
@@ -21,6 +22,7 @@
 enum class PredictorType {
   kScrollPredictorTypeLsq,
   kScrollPredictorTypeKalman,
+  kScrollPredictorTypeKalmanHeuristic,
   kScrollPredictorTypeLinearFirst,
   kScrollPredictorTypeLinearSecond,
   kScrollPredictorTypeLinearResampling,
diff --git a/ui/gl/test/gl_surface_test_support.cc b/ui/gl/test/gl_surface_test_support.cc
index 0b446da..20a2715a 100644
--- a/ui/gl/test/gl_surface_test_support.cc
+++ b/ui/gl/test/gl_surface_test_support.cc
@@ -40,7 +40,6 @@
   ui::OzonePlatform::InitParams params;
   params.single_process = true;
   ui::OzonePlatform::InitializeForGPU(params);
-  ui::OzonePlatform::GetInstance()->AfterSandboxEntry();
 #endif
 
 #if defined(OS_LINUX)
@@ -119,7 +118,6 @@
   ui::OzonePlatform::InitParams params;
   params.single_process = true;
   ui::OzonePlatform::InitializeForGPU(params);
-  ui::OzonePlatform::GetInstance()->AfterSandboxEntry();
 #endif
 
   InitializeOneOffImplementation(kGLImplementationMockGL, false);
@@ -131,7 +129,6 @@
   ui::OzonePlatform::InitParams params;
   params.single_process = true;
   ui::OzonePlatform::InitializeForGPU(params);
-  ui::OzonePlatform::GetInstance()->AfterSandboxEntry();
 #endif
 
   InitializeOneOffImplementation(kGLImplementationStubGL, false);
diff --git a/ui/native_theme/native_theme_aura.cc b/ui/native_theme/native_theme_aura.cc
index fafcd27..66752fc 100644
--- a/ui/native_theme/native_theme_aura.cc
+++ b/ui/native_theme/native_theme_aura.cc
@@ -50,7 +50,7 @@
 const int kSliderThumbSize = 16;
 const SkScalar kSliderThumbBorderWidth = 1.f;
 const SkScalar kSliderThumbBorderHoveredWidth = 1.f;
-const SkScalar kMenuListArrowStrokeWidth = 1.f;
+const SkScalar kMenuListArrowStrokeWidth = 2.f;
 // The "dash" is 8x2 px by default (the checkbox is 13x13 px).
 const SkScalar kIndeterminateInsetWidthRatio = (13 - 8) / 2.0f / 13;
 const SkScalar kIndeterminateInsetHeightRatio = (13 - 2) / 2.0f / 13;
@@ -900,7 +900,7 @@
   flags.setStrokeWidth(kMenuListArrowStrokeWidth);
 
   float arrow_width = menu_list.arrow_size;
-  int arrow_height = arrow_width * 0.6;
+  int arrow_height = arrow_width * 0.5;
   gfx::Rect arrow(menu_list.arrow_x, menu_list.arrow_y - (arrow_height / 2),
                   arrow_width, arrow_height);
   arrow.Intersect(rect);
diff --git a/ui/ozone/demo/ozone_demo.cc b/ui/ozone/demo/ozone_demo.cc
index 15cb11d..937778b 100644
--- a/ui/ozone/demo/ozone_demo.cc
+++ b/ui/ozone/demo/ozone_demo.cc
@@ -81,7 +81,6 @@
       ->SetCurrentLayoutByName("us");
 
   ui::OzonePlatform::InitializeForGPU(params);
-  ui::OzonePlatform::GetInstance()->AfterSandboxEntry();
 
   std::unique_ptr<ui::OzoneGpuTestHelper> gpu_helper;
   if (!ui::OzonePlatform::GetInstance()
diff --git a/ui/ozone/demo/skia/skia_demo.cc b/ui/ozone/demo/skia/skia_demo.cc
index e3cd3f5..400f1e8 100644
--- a/ui/ozone/demo/skia/skia_demo.cc
+++ b/ui/ozone/demo/skia/skia_demo.cc
@@ -56,7 +56,6 @@
       ->SetCurrentLayoutByName("us");
 
   ui::OzonePlatform::InitializeForGPU(params);
-  ui::OzonePlatform::GetInstance()->AfterSandboxEntry();
 
   std::unique_ptr<ui::OzoneGpuTestHelper> gpu_helper;
   if (!ui::OzonePlatform::GetInstance()
diff --git a/ui/ozone/platform/drm/ozone_platform_gbm.cc b/ui/ozone/platform/drm/ozone_platform_gbm.cc
index ca41d8f..2e9bc19 100644
--- a/ui/ozone/platform/drm/ozone_platform_gbm.cc
+++ b/ui/ozone/platform/drm/ozone_platform_gbm.cc
@@ -184,7 +184,6 @@
     //   3. multi-process mode where host and viz components communicate
     //      via mojo IPC.
 
-    single_process_ = args.single_process;
     using_mojo_ = args.using_mojo;
     host_thread_ = base::PlatformThread::CurrentRef();
 
@@ -263,14 +262,19 @@
           std::make_unique<DrmOverlayManagerGpu>(drm_thread_proxy_.get());
     }
 
-    if (using_mojo_ && single_process_ &&
-        host_thread_ == base::PlatformThread::CurrentRef()) {
-      CHECK(host_drm_device_) << "Mojo single-thread mode requires "
-                                 "InitializeUI to be called first.";
+    // If gpu is in a separate process, rest of the initialization happens after
+    // entering the sandbox.
+    if (!single_process())
+      return;
 
-      // One-thread execution does not permit use of the sandbox.
-      AfterSandboxEntry();
+    // In single process/mojo mode we need to make sure DrainBindingRequest is
+    // executed on this thread before we start the drm device.
+    const bool block_for_drm_thread = using_mojo_;
+    StartDrmThread(block_for_drm_thread);
 
+    if (using_mojo_ && host_thread_ == base::PlatformThread::CurrentRef()) {
+      CHECK(has_initialized_ui()) << "Mojo single-thread mode requires "
+                                     "InitializeUI to be called first.";
       // Connect host and gpu here since OnGpuServiceLaunched() is not called in
       // the single-threaded mode.
       ui::ozone::mojom::DrmDevicePtr drm_device_ptr;
@@ -286,21 +290,28 @@
   }
 
   // The DRM thread needs to be started late because we need to wait for the
-  // sandbox to start. This entry point in the Ozne API gives platforms
+  // sandbox to start. This entry point in the Ozone API gives platforms
   // flexibility in handing this requirement.
   void AfterSandboxEntry() override {
-    CHECK(drm_thread_proxy_) << "AfterSandboxEntry before InitializeForGPU is "
-                                "invalid startup order.\n";
-    if (using_mojo_ && single_process_) {
-      // In single process/mojo mode we need to make sure DrainBindingRequest
-      // is executed on this thread before we start the drm device.
+    DCHECK(!single_process());
+    CHECK(has_initialized_gpu()) << "AfterSandboxEntry before InitializeForGPU "
+                                    "is invalid startup order.";
+
+    const bool block_for_drm_thread = false;
+    StartDrmThread(block_for_drm_thread);
+  }
+
+ private:
+  // Starts the DRM thread. |blocking| determines if the call should be blocked
+  // until the thread is started.
+  void StartDrmThread(bool blocking) {
+    if (blocking) {
       base::WaitableEvent done_event;
       drm_thread_proxy_->StartDrmThread(base::BindOnce(
           &base::WaitableEvent::Signal, base::Unretained(&done_event)));
       done_event.Wait();
       DrainBindingRequests();
     } else {
-      // Defer the actual startup of the DRM thread to here.
       auto safe_binding_resquest_drainer = CreateSafeOnceCallback(
           base::BindOnce(&OzonePlatformGbm::DrainBindingRequests,
                          weak_factory_.GetWeakPtr()));
@@ -309,9 +320,7 @@
     }
   }
 
- private:
   bool using_mojo_ = false;
-  bool single_process_ = false;
 
   // Objects in the GPU process.
   std::unique_ptr<DrmThreadProxy> drm_thread_proxy_;
diff --git a/ui/ozone/public/ozone_platform.cc b/ui/ozone/public/ozone_platform.cc
index d45de899..fc9651c 100644
--- a/ui/ozone/public/ozone_platform.cc
+++ b/ui/ozone/public/ozone_platform.cc
@@ -18,12 +18,7 @@
 namespace ui {
 
 namespace {
-
-bool g_platform_initialized_ui = false;
-bool g_platform_initialized_gpu = false;
-
 OzonePlatform* g_instance = nullptr;
-
 }  // namespace
 
 OzonePlatform::OzonePlatform() {
@@ -35,10 +30,12 @@
 
 // static
 void OzonePlatform::InitializeForUI(const InitParams& args) {
-  if (g_platform_initialized_ui)
+  EnsureInstance();
+  if (g_instance->initialized_ui_)
     return;
-  g_platform_initialized_ui = true;
-  EnsureInstance()->InitializeUI(args);
+  g_instance->initialized_ui_ = true;
+  g_instance->single_process_ = args.single_process;
+  g_instance->InitializeUI(args);
   // This is deliberately created after initializing so that the platform can
   // create its own version of DDM.
   DeviceDataManager::CreateInstance();
@@ -46,10 +43,12 @@
 
 // static
 void OzonePlatform::InitializeForGPU(const InitParams& args) {
-  if (g_platform_initialized_gpu)
+  EnsureInstance();
+  if (g_instance->initialized_gpu_)
     return;
-  g_platform_initialized_gpu = true;
-  EnsureInstance()->InitializeGPU(args);
+  g_instance->initialized_gpu_ = true;
+  g_instance->single_process_ = args.single_process;
+  g_instance->InitializeGPU(args);
 }
 
 // static
@@ -103,7 +102,7 @@
 
 const OzonePlatform::InitializedHostProperties&
 OzonePlatform::GetInitializedHostProperties() {
-  DCHECK(g_platform_initialized_ui);
+  DCHECK(initialized_ui_);
 
   static InitializedHostProperties host_properties;
   return host_properties;
@@ -111,11 +110,9 @@
 
 void OzonePlatform::AddInterfaces(service_manager::BinderRegistry* registry) {}
 
-void OzonePlatform::AfterSandboxEntry() {}
-
-// static
-bool OzonePlatform::has_initialized_ui() {
-  return g_platform_initialized_ui;
+void OzonePlatform::AfterSandboxEntry() {
+  // This should not be called in single-process mode.
+  DCHECK(!single_process_);
 }
 
 }  // namespace ui
diff --git a/ui/ozone/public/ozone_platform.h b/ui/ozone/public/ozone_platform.h
index 0e9d076..33a9467 100644
--- a/ui/ozone/public/ozone_platform.h
+++ b/ui/ozone/public/ozone_platform.h
@@ -186,20 +186,31 @@
 
   // The GPU-specific portion of Ozone would typically run in a sandboxed
   // process for additional security. Some startup might need to wait until
-  // after the sandbox has been configured. The embedder should use this method
-  // to specify that the sandbox is configured and that GPU-side setup should
-  // complete. A default do-nothing implementation is provided to permit
-  // platform implementations to ignore sandboxing and any associated launch
-  // ordering issues.
+  // after the sandbox has been configured.
+  // When the GPU is in a separate process, the embedder should call this method
+  // after it has configured (or failed to configure) the sandbox so that the
+  // GPU-side setup is completed. If the GPU is in-process, there is no
+  // sandboxing and the embedder should not call this method.
+  // A default do-nothing implementation is provided to permit platform
+  // implementations to ignore sandboxing and any associated launch ordering
+  // issues.
   virtual void AfterSandboxEntry();
 
  protected:
-  static bool has_initialized_ui();
+  bool has_initialized_ui() const { return initialized_ui_; }
+  bool has_initialized_gpu() const { return initialized_gpu_; }
+
+  bool single_process() const { return single_process_; }
 
  private:
   virtual void InitializeUI(const InitParams& params) = 0;
   virtual void InitializeGPU(const InitParams& params) = 0;
 
+  bool initialized_ui_ = false;
+  bool initialized_gpu_ = false;
+
+  bool single_process_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(OzonePlatform);
 };
 
diff --git a/ui/views/context_menu_controller.cc b/ui/views/context_menu_controller.cc
index 5d4ff83..5eaf4dd 100644
--- a/ui/views/context_menu_controller.cc
+++ b/ui/views/context_menu_controller.cc
@@ -8,6 +8,10 @@
 
 namespace views {
 
+ContextMenuController::ContextMenuController() = default;
+
+ContextMenuController::~ContextMenuController() = default;
+
 void ContextMenuController::ShowContextMenuForView(
     View* source,
     const gfx::Point& point,
@@ -15,9 +19,18 @@
   // Use a boolean flag to early-exit out of re-entrant behavior.
   if (is_opening_)
     return;
-  base::AutoReset<bool> auto_reset_is_opening(&is_opening_, true);
+
+  // We might get deleted while showing the context menu (including as a result
+  // of showing it). If so, we need to make sure we're not accessing
+  // |is_opening_|.
+  auto weak_ptr = weak_factory_.GetWeakPtr();
 
   ShowContextMenuForViewImpl(source, point, source_type);
+
+  if (!weak_ptr)
+    return;
+
+  is_opening_ = false;
 }
 
 }  // namespace views
diff --git a/ui/views/context_menu_controller.h b/ui/views/context_menu_controller.h
index 1e47b38..4dfe2fb 100644
--- a/ui/views/context_menu_controller.h
+++ b/ui/views/context_menu_controller.h
@@ -5,6 +5,8 @@
 #ifndef UI_VIEWS_CONTEXT_MENU_CONTROLLER_H_
 #define UI_VIEWS_CONTEXT_MENU_CONTROLLER_H_
 
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "ui/base/ui_base_types.h"
 #include "ui/views/views_export.h"
 
@@ -28,6 +30,8 @@
 // implementation for mouse processing.
 class VIEWS_EXPORT ContextMenuController {
  public:
+  ContextMenuController();
+
   // Invoked to show the context menu for |source|. |point| is in screen
   // coordinates. This method also prevents reentrant calls.
   void ShowContextMenuForView(View* source,
@@ -35,7 +39,7 @@
                               ui::MenuSourceType source_type);
 
  protected:
-  virtual ~ContextMenuController() = default;
+  virtual ~ContextMenuController();
 
  private:
   // Subclasses should override this method.
@@ -48,6 +52,10 @@
   // spins a nested message loop that processes input events, which may attempt
   // to trigger another context menu.
   bool is_opening_ = false;
+
+  base::WeakPtrFactory<ContextMenuController> weak_factory_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(ContextMenuController);
 };
 
 }  // namespace views
diff --git a/ui/views/controls/table/table_header.cc b/ui/views/controls/table/table_header.cc
index ea7d76f..17df8eca 100644
--- a/ui/views/controls/table/table_header.cc
+++ b/ui/views/controls/table/table_header.cc
@@ -57,10 +57,6 @@
 
 TableHeader::~TableHeader() = default;
 
-void TableHeader::Layout() {
-  SetBounds(x(), y(), table_->width(), GetPreferredSize().height());
-}
-
 void TableHeader::OnPaint(gfx::Canvas* canvas) {
   ui::NativeTheme* theme = GetNativeTheme();
   const SkColor text_color =
diff --git a/ui/views/controls/table/table_header.h b/ui/views/controls/table/table_header.h
index a4459ac..359bf68 100644
--- a/ui/views/controls/table/table_header.h
+++ b/ui/views/controls/table/table_header.h
@@ -34,7 +34,6 @@
                                TableView::AdvanceDirection direction);
 
   // views::View overrides.
-  void Layout() override;
   void OnPaint(gfx::Canvas* canvas) override;
   const char* GetClassName() const override;
   gfx::Size CalculatePreferredSize() const override;
diff --git a/ui/views/controls/table/table_view.cc b/ui/views/controls/table/table_view.cc
index 0fb712a..f8e19ec9 100644
--- a/ui/views/controls/table/table_view.cc
+++ b/ui/views/controls/table/table_view.cc
@@ -375,9 +375,8 @@
 }
 
 void TableView::Layout() {
-  // parent()->parent() is the scrollview. When its width changes we force
-  // recalculating column sizes.
-  View* scroll_view = parent() ? parent()->parent() : nullptr;
+  // When the scrollview's width changes we force recalculating column sizes.
+  ScrollView* scroll_view = ScrollView::GetScrollViewForContents(this);
   if (scroll_view) {
     const int scroll_view_width = scroll_view->GetContentsBounds().width();
     if (scroll_view_width != last_parent_width_) {
@@ -399,6 +398,11 @@
     height = std::max(parent()->height(), height);
   }
   SetBounds(x(), y(), width, height);
+  if (header_) {
+    header_->SetBoundsRect(
+        gfx::Rect(header_->bounds().origin(),
+                  gfx::Size(width, header_->GetPreferredSize().height())));
+  }
 
   if (focus_ring_)
     focus_ring_->Layout();
diff --git a/weblayer/browser/java/BUILD.gn b/weblayer/browser/java/BUILD.gn
index 035dc83..1c9db1f 100644
--- a/weblayer/browser/java/BUILD.gn
+++ b/weblayer/browser/java/BUILD.gn
@@ -8,6 +8,7 @@
 android_library("java") {
   java_files = [
     "org/chromium/weblayer_private/BrowserControllerImpl.java",
+    "org/chromium/weblayer_private/BrowserFragmentControllerImpl.java",
     "org/chromium/weblayer_private/BrowserObserverProxy.java",
     "org/chromium/weblayer_private/ContentView.java",
     "org/chromium/weblayer_private/ContentViewRenderView.java",
@@ -18,6 +19,7 @@
     "org/chromium/weblayer_private/TopControlsContainerView.java",
     "org/chromium/weblayer_private/WebLayerImpl.java",
     "org/chromium/weblayer_private/ChildProcessServiceImpl.java",
+    "org/chromium/weblayer_private/RemoteFragmentImpl.java",
   ]
 
   deps = [
@@ -54,6 +56,7 @@
 android_aidl("aidl") {
   import_include = [ "org/chromium/weblayer_private/aidl" ]
   sources = [
+    "org/chromium/weblayer_private/aidl/IBrowserFragmentController.aidl",
     "org/chromium/weblayer_private/aidl/IBrowserController.aidl",
     "org/chromium/weblayer_private/aidl/IBrowserControllerClient.aidl",
     "org/chromium/weblayer_private/aidl/IChildProcessService.aidl",
@@ -63,6 +66,8 @@
     "org/chromium/weblayer_private/aidl/INavigationControllerClient.aidl",
     "org/chromium/weblayer_private/aidl/IObjectWrapper.aidl",
     "org/chromium/weblayer_private/aidl/IProfile.aidl",
+    "org/chromium/weblayer_private/aidl/IRemoteFragment.aidl",
+    "org/chromium/weblayer_private/aidl/IRemoteFragmentClient.aidl",
     "org/chromium/weblayer_private/aidl/IWebLayer.aidl",
   ]
 }
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/BrowserControllerImpl.java b/weblayer/browser/java/org/chromium/weblayer_private/BrowserControllerImpl.java
index b01eb1d..184ae25 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/BrowserControllerImpl.java
+++ b/weblayer/browser/java/org/chromium/weblayer_private/BrowserControllerImpl.java
@@ -29,8 +29,10 @@
 public final class BrowserControllerImpl extends IBrowserController.Stub {
     private long mNativeBrowserController;
 
+    // TODO: move mWindowAndroid, mContentViewRenderView, mContentView, mTopControlsContainerView to
+    // BrowserFragmentControllerImpl.
     private ActivityWindowAndroid mWindowAndroid;
-    // This view is the main view (returned from OnCreateView()).
+    // This view is the main view (returned from the fragment's onCreateView()).
     private ContentViewRenderView mContentViewRenderView;
     // One of these is needed per WebContents.
     private ContentView mContentView;
@@ -125,7 +127,6 @@
         mBrowserObserverProxy = new BrowserObserverProxy(mNativeBrowserController, client);
     }
 
-    @Override
     public void destroy() {
         BrowserControllerImplJni.get().setTopControlsContainerView(
                 mNativeBrowserController, BrowserControllerImpl.this, 0);
@@ -138,18 +139,16 @@
         mNativeBrowserController = 0;
     }
 
-    @Override
     public void setTopView(IObjectWrapper viewWrapper) {
         View view = ObjectWrapper.unwrap(viewWrapper, View.class);
         mTopControlsContainerView.setView(view);
     }
 
-    @Override
-    public IObjectWrapper onCreateView() {
-        return ObjectWrapper.wrap(mContentViewRenderView);
+    /** Returns top-level View this Controller works with */
+    public View getView() {
+        return mContentViewRenderView;
     }
 
-    @Override
     public void setSupportsEmbedding(boolean enable, IObjectWrapper callback) {
         mContentViewRenderView.requestMode(enable ? ContentViewRenderView.MODE_TEXTURE_VIEW
                                                   : ContentViewRenderView.MODE_SURFACE_VIEW,
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/BrowserFragmentControllerImpl.java b/weblayer/browser/java/org/chromium/weblayer_private/BrowserFragmentControllerImpl.java
new file mode 100644
index 0000000..89aeba9
--- /dev/null
+++ b/weblayer/browser/java/org/chromium/weblayer_private/BrowserFragmentControllerImpl.java
@@ -0,0 +1,63 @@
+// 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.
+
+package org.chromium.weblayer_private;
+
+import android.view.View;
+
+import org.chromium.weblayer_private.aidl.IBrowserController;
+import org.chromium.weblayer_private.aidl.IBrowserFragmentController;
+import org.chromium.weblayer_private.aidl.IObjectWrapper;
+import org.chromium.weblayer_private.aidl.IRemoteFragment;
+import org.chromium.weblayer_private.aidl.IRemoteFragmentClient;
+
+/**
+ * Implementation of {@link IBrowserFragmentController}.
+ */
+public class BrowserFragmentControllerImpl extends IBrowserFragmentController.Stub {
+    private final BrowserControllerImpl mController;
+    private final BrowserRemoteFragmentImpl mRemoteFragmentImpl;
+
+    public BrowserFragmentControllerImpl(BrowserControllerImpl controller,
+            IRemoteFragmentClient fragmentClient) {
+        mController = controller;
+        mRemoteFragmentImpl = new BrowserRemoteFragmentImpl(fragmentClient);
+    }
+
+    @Override
+    public void setTopView(IObjectWrapper view) {
+        mController.setTopView(view);
+    }
+
+    @Override
+    public void setSupportsEmbedding(boolean enable, IObjectWrapper valueCallback) {
+        mController.setSupportsEmbedding(enable, valueCallback);
+    }
+
+    @Override
+    public IRemoteFragment getRemoteFragment() {
+        return mRemoteFragmentImpl;
+    }
+
+    @Override
+    public IBrowserController getBrowserController() {
+        return mController;
+    }
+
+    @Override
+    public void destroy() {
+        mController.destroy();
+    }
+
+    private class BrowserRemoteFragmentImpl extends RemoteFragmentImpl {
+        public BrowserRemoteFragmentImpl(IRemoteFragmentClient client) {
+            super(client);
+        }
+
+        @Override
+        public View onCreateView() {
+            return mController.getView();
+        }
+    }
+}
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/ProfileImpl.java b/weblayer/browser/java/org/chromium/weblayer_private/ProfileImpl.java
index 3e76f82..c0e4ad5 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/ProfileImpl.java
+++ b/weblayer/browser/java/org/chromium/weblayer_private/ProfileImpl.java
@@ -8,9 +8,10 @@
 
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.NativeMethods;
-import org.chromium.weblayer_private.aidl.IBrowserController;
+import org.chromium.weblayer_private.aidl.IBrowserFragmentController;
 import org.chromium.weblayer_private.aidl.IObjectWrapper;
 import org.chromium.weblayer_private.aidl.IProfile;
+import org.chromium.weblayer_private.aidl.IRemoteFragmentClient;
 import org.chromium.weblayer_private.aidl.ObjectWrapper;
 
 @JNINamespace("weblayer")
@@ -33,8 +34,12 @@
     }
 
     @Override
-    public IBrowserController createBrowserController(IObjectWrapper context) {
-        return new BrowserControllerImpl(ObjectWrapper.unwrap(context, Context.class), this);
+    public IBrowserFragmentController createBrowserFragmentController(IRemoteFragmentClient
+            fragmentClient,
+            IObjectWrapper context) {
+        BrowserControllerImpl browserController = new BrowserControllerImpl(
+                    ObjectWrapper.unwrap(context, Context.class), this);
+        return new BrowserFragmentControllerImpl(browserController, fragmentClient);
     }
 
     long getNativeProfile() {
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/RemoteFragmentImpl.java b/weblayer/browser/java/org/chromium/weblayer_private/RemoteFragmentImpl.java
new file mode 100644
index 0000000..585e1d4
--- /dev/null
+++ b/weblayer/browser/java/org/chromium/weblayer_private/RemoteFragmentImpl.java
@@ -0,0 +1,193 @@
+// 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.
+
+package org.chromium.weblayer_private;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.view.View;
+
+import org.chromium.weblayer_private.aidl.APICallException;
+import org.chromium.weblayer_private.aidl.IObjectWrapper;
+import org.chromium.weblayer_private.aidl.IRemoteFragment;
+import org.chromium.weblayer_private.aidl.IRemoteFragmentClient;
+import org.chromium.weblayer_private.aidl.ObjectWrapper;
+
+/**
+ * Base for the classes controlling a Fragment that exists in another ClassLoader. Extending this
+ * class is similar to extending Fragment: e.g. one can override lifecycle methods, not forgetting
+ * to call super, etc.
+ */
+public abstract class RemoteFragmentImpl extends IRemoteFragment.Stub {
+    private final IRemoteFragmentClient mClient;
+
+    protected RemoteFragmentImpl(IRemoteFragmentClient client) {
+        mClient = client;
+    }
+
+    public View onCreateView() {
+        return null;
+    }
+
+    public final Activity getActivity() {
+        try {
+            return ObjectWrapper.unwrap(mClient.getActivity(), Activity.class);
+        } catch (RemoteException e) {
+            throw new APICallException(e);
+        }
+    }
+
+    // TODO(pshmakov): add dependency to androidx.annotation and put @CallSuper here.
+    public void onCreate(Bundle savedInstanceState) {
+        try {
+            mClient.superOnCreate(ObjectWrapper.wrap(savedInstanceState));
+        } catch (RemoteException e) {
+            throw new APICallException(e);
+        }
+    }
+
+    public void onAttach(Context context) {
+        try {
+            mClient.superOnAttach(ObjectWrapper.wrap(context));
+        } catch (RemoteException e) {
+            throw new APICallException(e);
+        }
+    }
+
+    public void onActivityCreated(Bundle savedInstanceState) {
+        try {
+            mClient.superOnActivityCreated(ObjectWrapper.wrap(savedInstanceState));
+        } catch (RemoteException e) {
+            throw new APICallException(e);
+        }
+    }
+
+    public void onStart() {
+        try {
+            mClient.superOnStart();
+        } catch (RemoteException e) {
+            throw new APICallException(e);
+        }
+    }
+
+    public void onDestroy() {
+        try {
+            mClient.superOnDestroy();
+        } catch (RemoteException e) {
+            throw new APICallException(e);
+        }
+    }
+
+    public void onDetach() {
+        try {
+            mClient.superOnDetach();
+        } catch (RemoteException e) {
+            throw new APICallException(e);
+        }
+    }
+
+    public void onResume() {
+        try {
+            mClient.superOnResume();
+        } catch (RemoteException e) {
+            throw new APICallException(e);
+        }
+    }
+
+    public void onDestroyView() {
+        try {
+            mClient.superOnDestroyView();
+        } catch (RemoteException e) {
+            throw new APICallException(e);
+        }
+    }
+
+    public void onStop() {
+        try {
+            mClient.superOnStop();
+        } catch (RemoteException e) {
+            throw new APICallException(e);
+        }
+    }
+
+    public void onPause() {
+        try {
+            mClient.superOnPause();
+        } catch (RemoteException e) {
+            throw new APICallException(e);
+        }
+    }
+
+    public void onSaveInstaceState(Bundle outState) {
+        try {
+            mClient.superOnSaveInstanceState(ObjectWrapper.wrap(outState));
+        } catch (RemoteException e) {
+            throw new APICallException(e);
+        }
+    }
+
+    // IRemoteFragment implementation below.
+
+    @Override
+    public final IObjectWrapper handleOnCreateView() {
+        return ObjectWrapper.wrap(onCreateView());
+    }
+
+    @Override
+    public final void handleOnStart() {
+        onStart();
+    }
+
+    @Override
+    public final void handleOnCreate(IObjectWrapper savedInstanceState) {
+        onCreate(ObjectWrapper.unwrap(savedInstanceState, Bundle.class));
+    }
+
+    @Override
+    public final void handleOnAttach(IObjectWrapper context) {
+        onAttach(ObjectWrapper.unwrap(context, Context.class));
+    }
+
+    @Override
+    public final void handleOnActivityCreated(IObjectWrapper savedInstanceState) {
+        onActivityCreated(ObjectWrapper.unwrap(savedInstanceState, Bundle.class));
+    }
+
+    @Override
+    public final void handleOnResume()  {
+        onResume();
+    }
+
+    @Override
+    public final void handleOnPause()  {
+        onPause();
+    }
+
+    @Override
+    public final void handleOnStop()  {
+        onStop();
+    }
+
+    @Override
+    public final void handleOnDestroyView()  {
+        onDestroyView();
+    }
+
+    @Override
+    public final void handleOnDetach()  {
+        onDetach();
+    }
+
+    @Override
+    public final void handleOnDestroy()  {
+        onDestroy();
+    }
+
+    @Override
+    public final void handleOnSaveInstanceState(IObjectWrapper outState)  {
+        onSaveInstaceState(ObjectWrapper.unwrap(outState, Bundle.class));
+    }
+}
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/aidl/IBrowserController.aidl b/weblayer/browser/java/org/chromium/weblayer_private/aidl/IBrowserController.aidl
index 829cea7..fdbf9c2 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/aidl/IBrowserController.aidl
+++ b/weblayer/browser/java/org/chromium/weblayer_private/aidl/IBrowserController.aidl
@@ -5,21 +5,11 @@
 package org.chromium.weblayer_private.aidl;
 
 import org.chromium.weblayer_private.aidl.IBrowserControllerClient;
-import org.chromium.weblayer_private.aidl.IObjectWrapper;
+import org.chromium.weblayer_private.aidl.INavigationController;
+import org.chromium.weblayer_private.aidl.INavigationControllerClient;
 
 interface IBrowserController {
   void setClient(in IBrowserControllerClient client) = 0;
 
   INavigationController createNavigationController(in INavigationControllerClient client) = 1;
-
-  void setTopView(in IObjectWrapper view) = 2;
-
-  void destroy() = 3;
-
-  IObjectWrapper onCreateView() = 4;
-
-  // |valueCallback| is a wrapped ValueCallback<Boolean> instead. The bool value in |valueCallback|
-  // indicates is whether the request was successful. Request might fail if it is subsumed by a
-  // following request, or if this object is destroyed.
-  void setSupportsEmbedding(in boolean enable, in IObjectWrapper valueCallback) = 5;
 }
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/aidl/IBrowserFragmentController.aidl b/weblayer/browser/java/org/chromium/weblayer_private/aidl/IBrowserFragmentController.aidl
new file mode 100644
index 0000000..db474ae
--- /dev/null
+++ b/weblayer/browser/java/org/chromium/weblayer_private/aidl/IBrowserFragmentController.aidl
@@ -0,0 +1,21 @@
+// 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.
+
+package org.chromium.weblayer_private.aidl;
+
+import org.chromium.weblayer_private.aidl.IBrowserController;
+import org.chromium.weblayer_private.aidl.IObjectWrapper;
+import org.chromium.weblayer_private.aidl.IRemoteFragment;
+
+interface IBrowserFragmentController {
+  void destroy() = 0;
+  IBrowserController getBrowserController() = 1;
+  IRemoteFragment getRemoteFragment() = 2;
+  void setTopView(IObjectWrapper view) = 3;
+
+  // |valueCallback| is a wrapped ValueCallback<Boolean> instead. The bool value in |valueCallback|
+  // indicates is whether the request was successful. Request might fail if it is subsumed by a
+  // following request, or if this object is destroyed.
+  void setSupportsEmbedding(in boolean enable, in IObjectWrapper valueCallback) = 4;
+}
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/aidl/IProfile.aidl b/weblayer/browser/java/org/chromium/weblayer_private/aidl/IProfile.aidl
index 3e8e2af..98d7c21a 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/aidl/IProfile.aidl
+++ b/weblayer/browser/java/org/chromium/weblayer_private/aidl/IProfile.aidl
@@ -4,7 +4,8 @@
 
 package org.chromium.weblayer_private.aidl;
 
-import org.chromium.weblayer_private.aidl.IBrowserController;
+import org.chromium.weblayer_private.aidl.IBrowserFragmentController;
+import org.chromium.weblayer_private.aidl.IRemoteFragmentClient;
 import org.chromium.weblayer_private.aidl.IObjectWrapper;
 
 interface IProfile {
@@ -13,8 +14,11 @@
   void clearBrowsingData() = 1;
 
   /**
-   * Creates a new IBrowserController.
+   * Creates a new IBrowserFragmentController.
+   * @param fragmentClient IRemoteFragmentClient that will host the Fragment implemented on the
+   * weblayer side.
    * @param context Context that refers the the weblayer implementation
    */
-  IBrowserController createBrowserController(in IObjectWrapper context) = 2;
+  IBrowserFragmentController createBrowserFragmentController(
+          in IRemoteFragmentClient fragmentClient, in IObjectWrapper context) = 2;
 }
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/aidl/IRemoteFragment.aidl b/weblayer/browser/java/org/chromium/weblayer_private/aidl/IRemoteFragment.aidl
new file mode 100644
index 0000000..ed2eede0
--- /dev/null
+++ b/weblayer/browser/java/org/chromium/weblayer_private/aidl/IRemoteFragment.aidl
@@ -0,0 +1,23 @@
+// 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.
+
+package org.chromium.weblayer_private.aidl;
+
+import org.chromium.weblayer_private.aidl.IObjectWrapper;
+
+interface IRemoteFragment {
+  // Using IObjectWrapper instead of Bundle to pass by reference instead of by value.
+  void handleOnCreate(in IObjectWrapper savedInstanceState) = 0;
+  void handleOnAttach(in IObjectWrapper context) = 1;
+  void handleOnActivityCreated(in IObjectWrapper savedInstanceState) = 2;
+  IObjectWrapper handleOnCreateView() = 3;
+  void handleOnStart() = 4;
+  void handleOnResume() = 5;
+  void handleOnPause() = 6;
+  void handleOnStop() = 7;
+  void handleOnDestroyView() = 8;
+  void handleOnDetach() = 9;
+  void handleOnDestroy() = 10;
+  void handleOnSaveInstanceState(in IObjectWrapper outState) = 11;
+}
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/aidl/IRemoteFragmentClient.aidl b/weblayer/browser/java/org/chromium/weblayer_private/aidl/IRemoteFragmentClient.aidl
new file mode 100644
index 0000000..fbc69cb
--- /dev/null
+++ b/weblayer/browser/java/org/chromium/weblayer_private/aidl/IRemoteFragmentClient.aidl
@@ -0,0 +1,21 @@
+// 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.
+
+package org.chromium.weblayer_private.aidl;
+
+interface IRemoteFragmentClient {
+  void superOnCreate(in IObjectWrapper savedInstanceState) = 0;
+  void superOnAttach(in IObjectWrapper context) = 1;
+  void superOnActivityCreated(in IObjectWrapper savedInstanceState) = 2;
+  void superOnStart() = 3;
+  void superOnResume() = 4;
+  void superOnPause() = 5;
+  void superOnStop() = 6;
+  void superOnDestroyView() = 7;
+  void superOnDetach() = 8;
+  void superOnDestroy() = 9;
+  void superOnSaveInstanceState(in IObjectWrapper outState) = 10;
+
+  IObjectWrapper getActivity() = 11;
+}
diff --git a/weblayer/public/java/BUILD.gn b/weblayer/public/java/BUILD.gn
index 58bab32..6dc3923 100644
--- a/weblayer/public/java/BUILD.gn
+++ b/weblayer/public/java/BUILD.gn
@@ -21,8 +21,9 @@
 
 android_library("java") {
   java_files = [
+    "org/chromium/weblayer/RemoteFragmentClient.java",
     "org/chromium/weblayer/BrowserController.java",
-    "org/chromium/weblayer/BrowserFragmentImpl.java",
+    "org/chromium/weblayer/BrowserFragmentController.java",
     "org/chromium/weblayer/BrowserObserver.java",
     "org/chromium/weblayer/Callback.java",
     "org/chromium/weblayer/ListenableResult.java",
@@ -38,6 +39,10 @@
   deps = [
     ":client_resources",
     "//weblayer/browser/java:client_java",
+
+    # TODO(pshmakov): Exclude this from the artifact and make sure we can depend on other version
+    # than Chrome.
+    "//third_party/android_deps:android_support_v4_java",
   ]
 
   # Needed for android.webkit.WebViewDelegate.
diff --git a/weblayer/public/java/org/chromium/weblayer/BrowserController.java b/weblayer/public/java/org/chromium/weblayer/BrowserController.java
index 334774f..8d512a40 100644
--- a/weblayer/public/java/org/chromium/weblayer/BrowserController.java
+++ b/weblayer/public/java/org/chromium/weblayer/BrowserController.java
@@ -6,12 +6,10 @@
 
 import android.net.Uri;
 import android.os.RemoteException;
-import android.view.View;
 
 import org.chromium.weblayer_private.aidl.APICallException;
 import org.chromium.weblayer_private.aidl.IBrowserController;
 import org.chromium.weblayer_private.aidl.IBrowserControllerClient;
-import org.chromium.weblayer_private.aidl.ObjectWrapper;
 
 public final class BrowserController {
     private final IBrowserController mImpl;
@@ -47,23 +45,6 @@
         mObservers.removeObserver(observer);
     }
 
-    // Only called from BrowserFragmentImpl.
-    void destroy() {
-        try {
-            mImpl.destroy();
-        } catch (RemoteException e) {
-            throw new APICallException(e);
-        }
-    }
-
-    public View onCreateView() {
-        try {
-            return ObjectWrapper.unwrap(mImpl.onCreateView(), View.class);
-        } catch (RemoteException e) {
-            throw new APICallException(e);
-        }
-    }
-
     IBrowserController getIBrowserController() {
         return mImpl;
     }
diff --git a/weblayer/public/java/org/chromium/weblayer/BrowserFragmentImpl.java b/weblayer/public/java/org/chromium/weblayer/BrowserFragmentController.java
similarity index 65%
rename from weblayer/public/java/org/chromium/weblayer/BrowserFragmentImpl.java
rename to weblayer/public/java/org/chromium/weblayer/BrowserFragmentController.java
index 038999ca..34b8a4d 100644
--- a/weblayer/public/java/org/chromium/weblayer/BrowserFragmentImpl.java
+++ b/weblayer/public/java/org/chromium/weblayer/BrowserFragmentController.java
@@ -5,43 +5,54 @@
 package org.chromium.weblayer;
 
 import android.os.RemoteException;
+import android.support.v4.app.Fragment;
 import android.view.View;
 import android.webkit.ValueCallback;
 
 import org.chromium.weblayer_private.aidl.APICallException;
-import org.chromium.weblayer_private.aidl.IBrowserController;
+import org.chromium.weblayer_private.aidl.IBrowserFragmentController;
 import org.chromium.weblayer_private.aidl.ObjectWrapper;
 
 /**
- * Provides an API similar to that of Fragment. To avoid depending upon a particular Fragment
- * implementation, this class does not actually extend Fragment. It is expected that consumers of
- * this provide an implementation of Fragment that calls through to the similarly named methods in
- * this class.
- *
- * BrowserFragmentImpl is created from Profile.
+ * Represents a browser fragment. Created from Profile.
  */
-public final class BrowserFragmentImpl {
-    private BrowserController mBrowserController;
+public final class BrowserFragmentController {
+    private final IBrowserFragmentController mImpl;
+    private final RemoteFragmentClient mFragment;
+    private BrowserController mController;
 
-    BrowserFragmentImpl(IBrowserController iBrowserController) {
-        mBrowserController = new BrowserController(iBrowserController);
+    BrowserFragmentController(IBrowserFragmentController impl, RemoteFragmentClient fragment) {
+        mImpl = impl;
+        mFragment = fragment;
     }
 
     public void destroy() {
-        mBrowserController.destroy();
-    }
-
-    public void setTopView(View view) {
         try {
-            getIBrowserController().setTopView(ObjectWrapper.wrap(view));
+            mImpl.destroy();
         } catch (RemoteException e) {
             throw new APICallException(e);
         }
     }
 
-    public View onCreateView() {
+    // TODO(pshmakov): rename this to BrowserTabController.
+    public BrowserController getBrowserController() {
+        if (mController == null) {
+            try {
+                mController = new BrowserController(mImpl.getBrowserController());
+            } catch (RemoteException e) {
+                throw new APICallException(e);
+            }
+        }
+        return mController;
+    }
+
+    public Fragment getFragment() {
+        return mFragment;
+    }
+
+    public void setTopView(View view) {
         try {
-            return ObjectWrapper.unwrap(getIBrowserController().onCreateView(), View.class);
+            mImpl.setTopView(ObjectWrapper.wrap(view));
         } catch (RemoteException e) {
             throw new APICallException(e);
         }
@@ -59,7 +70,7 @@
     public ListenableResult<Boolean> setSupportsEmbedding(boolean enable) {
         try {
             final ListenableResult<Boolean> listenableResult = new ListenableResult<Boolean>();
-            getIBrowserController().setSupportsEmbedding(
+            mImpl.setSupportsEmbedding(
                     enable, ObjectWrapper.wrap(new ValueCallback<Boolean>() {
                         @Override
                         public void onReceiveValue(Boolean result) {
@@ -71,12 +82,4 @@
             throw new APICallException(e);
         }
     }
-
-    public BrowserController getBrowserController() {
-        return mBrowserController;
-    }
-
-    private IBrowserController getIBrowserController() {
-        return mBrowserController.getIBrowserController();
-    }
 }
diff --git a/weblayer/public/java/org/chromium/weblayer/Profile.java b/weblayer/public/java/org/chromium/weblayer/Profile.java
index 10d5a2d..685bdd4 100644
--- a/weblayer/public/java/org/chromium/weblayer/Profile.java
+++ b/weblayer/public/java/org/chromium/weblayer/Profile.java
@@ -8,6 +8,7 @@
 import android.os.RemoteException;
 
 import org.chromium.weblayer_private.aidl.APICallException;
+import org.chromium.weblayer_private.aidl.IBrowserFragmentController;
 import org.chromium.weblayer_private.aidl.IProfile;
 import org.chromium.weblayer_private.aidl.ObjectWrapper;
 
@@ -43,10 +44,14 @@
         }
     }
 
-    public BrowserFragmentImpl createBrowserFragment(Context context) {
+    public BrowserFragmentController createBrowserFragmentController(Context context) {
         try {
-            return new BrowserFragmentImpl(mImpl.createBrowserController(
-                    ObjectWrapper.wrap(WebLayer.createRemoteContext(context))));
+            RemoteFragmentClient fragmentClient = new RemoteFragmentClient();
+            IBrowserFragmentController browserFragmentImpl = mImpl.createBrowserFragmentController(
+                    fragmentClient.asIRemoteFragmentClient(),
+                    ObjectWrapper.wrap(WebLayer.createRemoteContext(context)));
+            fragmentClient.setRemoteFragment(browserFragmentImpl.getRemoteFragment());
+            return new BrowserFragmentController(browserFragmentImpl, fragmentClient);
         } catch (RemoteException e) {
             throw new APICallException(e);
         }
diff --git a/weblayer/public/java/org/chromium/weblayer/RemoteFragmentClient.java b/weblayer/public/java/org/chromium/weblayer/RemoteFragmentClient.java
new file mode 100644
index 0000000..644585e4
--- /dev/null
+++ b/weblayer/public/java/org/chromium/weblayer/RemoteFragmentClient.java
@@ -0,0 +1,223 @@
+// 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.
+
+package org.chromium.weblayer;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import org.chromium.weblayer_private.aidl.APICallException;
+import org.chromium.weblayer_private.aidl.IObjectWrapper;
+import org.chromium.weblayer_private.aidl.IRemoteFragment;
+import org.chromium.weblayer_private.aidl.IRemoteFragmentClient;
+import org.chromium.weblayer_private.aidl.ObjectWrapper;
+
+/**
+ * Hosts a "remote fragment" (represented by {@link IRemoteFragment}) that lives in another
+ * ClassLoader. The remote fragment has all the actual logic (e.g. handling lifecycle events), while
+ * this class actually extends {@link Fragment}, forwarding the calls to and from the remote
+ * fragment. Thus it is "hosting" the fragment implemented elsewhere.
+ */
+public final class RemoteFragmentClient extends Fragment {
+    private final IRemoteFragmentClient mClientImpl = new IRemoteFragmentClient.Stub() {
+        @Override
+        public void superOnCreate(IObjectWrapper savedInstanceState) {
+            RemoteFragmentClient.super.onCreate(ObjectWrapper.unwrap(savedInstanceState,
+                    Bundle.class));
+        }
+
+        @Override
+        public void superOnAttach(IObjectWrapper context) {
+            RemoteFragmentClient.super.onAttach(ObjectWrapper.unwrap(context, Context.class));
+        }
+
+        @Override
+        public void superOnActivityCreated(IObjectWrapper savedInstanceState) {
+            RemoteFragmentClient.super.onCreate(ObjectWrapper.unwrap(savedInstanceState,
+                    Bundle.class));
+        }
+
+        @Override
+        public void superOnStart() {
+            RemoteFragmentClient.super.onStart();
+        }
+
+        @Override
+        public void superOnResume() {
+            RemoteFragmentClient.super.onResume();
+        }
+
+        @Override
+        public void superOnPause() {
+            RemoteFragmentClient.super.onPause();
+        }
+
+        @Override
+        public void superOnStop() {
+            RemoteFragmentClient.super.onStop();
+        }
+
+        @Override
+        public void superOnDestroyView() {
+            RemoteFragmentClient.super.onDestroyView();
+        }
+
+        @Override
+        public void superOnDetach() {
+            RemoteFragmentClient.super.onDetach();
+        }
+
+        @Override
+        public void superOnDestroy() {
+            RemoteFragmentClient.super.onDestroy();
+        }
+
+        @Override
+        public void superOnSaveInstanceState(IObjectWrapper outState) {
+            RemoteFragmentClient.super.onSaveInstanceState(ObjectWrapper.unwrap(outState,
+                    Bundle.class));
+        }
+
+        @Override
+        public IObjectWrapper getActivity() {
+            return ObjectWrapper.wrap(RemoteFragmentClient.this.getActivity());
+        }
+    };
+
+    private IRemoteFragment mRemoteFragment;
+
+    // TODO(pshmakov): how do we deal with FragmentManager restoring this Fragment on its own?
+    /* package */ void setRemoteFragment(IRemoteFragment remoteFragment) {
+        mRemoteFragment = remoteFragment;
+    }
+
+    /* package */ IRemoteFragmentClient asIRemoteFragmentClient() {
+        return mClientImpl;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        try {
+            return ObjectWrapper.unwrap(mRemoteFragment.handleOnCreateView(), View.class);
+        } catch (RemoteException e) {
+            throw new APICallException(e);
+        }
+    }
+
+    @SuppressWarnings("MissingSuperCall")
+    @Override
+    public void onAttach(Context context) {
+        try {
+            mRemoteFragment.handleOnAttach(ObjectWrapper.wrap(context));
+        } catch (RemoteException e) {
+            throw new APICallException(e);
+        }
+    }
+
+    @SuppressWarnings("MissingSuperCall")
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        try {
+            mRemoteFragment.handleOnCreate(ObjectWrapper.wrap(savedInstanceState));
+        } catch (RemoteException e) {
+            throw new APICallException(e);
+        }
+    }
+
+    @SuppressWarnings("MissingSuperCall")
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        try {
+            mRemoteFragment.handleOnActivityCreated(ObjectWrapper.wrap(savedInstanceState));
+        } catch (RemoteException e) {
+            throw new APICallException(e);
+        }
+    }
+
+    @SuppressWarnings("MissingSuperCall")
+    @Override
+    public void onStart() {
+        try {
+            mRemoteFragment.handleOnStart();
+        } catch (RemoteException e) {
+            throw new APICallException(e);
+        }
+    }
+
+    @SuppressWarnings("MissingSuperCall")
+    @Override
+    public void onResume() {
+        try {
+            mRemoteFragment.handleOnResume();
+        } catch (RemoteException e) {
+            throw new APICallException(e);
+        }
+    }
+
+    @SuppressWarnings("MissingSuperCall")
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        try {
+            mRemoteFragment.handleOnSaveInstanceState(ObjectWrapper.wrap(outState));
+        } catch (RemoteException e) {
+            throw new APICallException(e);
+        }
+    }
+
+    @SuppressWarnings("MissingSuperCall")
+    @Override
+    public void onPause() {
+        try {
+            mRemoteFragment.handleOnPause();
+        } catch (RemoteException e) {
+            throw new APICallException(e);
+        }
+    }
+
+    @SuppressWarnings("MissingSuperCall")
+    @Override
+    public void onStop() {
+        try {
+            mRemoteFragment.handleOnStop();
+        } catch (RemoteException e) {
+            throw new APICallException(e);
+        }
+    }
+
+    @SuppressWarnings("MissingSuperCall")
+    @Override
+    public void onDestroyView() {
+        try {
+            mRemoteFragment.handleOnDestroyView();
+        } catch (RemoteException e) {
+            throw new APICallException(e);
+        }
+    }
+
+    @SuppressWarnings("MissingSuperCall")
+    @Override
+    public void onDestroy() {
+        try {
+            mRemoteFragment.handleOnDestroy();
+        } catch (RemoteException e) {
+            throw new APICallException(e);
+        }
+    }
+
+    @SuppressWarnings("MissingSuperCall")
+    @Override
+    public void onDetach() {
+        try {
+            mRemoteFragment.handleOnDetach();
+        } catch (RemoteException e) {
+            throw new APICallException(e);
+        }
+    }
+}
diff --git a/weblayer/shell/android/demo_apk/src/org/chromium/weblayer/demo/WebLayerAnimationDemoActivity.java b/weblayer/shell/android/demo_apk/src/org/chromium/weblayer/demo/WebLayerAnimationDemoActivity.java
index 55f04851..5f0433e 100644
--- a/weblayer/shell/android/demo_apk/src/org/chromium/weblayer/demo/WebLayerAnimationDemoActivity.java
+++ b/weblayer/shell/android/demo_apk/src/org/chromium/weblayer/demo/WebLayerAnimationDemoActivity.java
@@ -7,15 +7,12 @@
 import android.content.Context;
 import android.net.Uri;
 import android.os.Bundle;
-import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentActivity;
 import android.support.v4.app.FragmentTransaction;
 import android.text.InputType;
 import android.view.KeyEvent;
-import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.inputmethod.EditorInfo;
 import android.webkit.WebSettings;
 import android.webkit.WebView;
@@ -26,7 +23,7 @@
 import android.widget.TextView.OnEditorActionListener;
 
 import org.chromium.weblayer.BrowserController;
-import org.chromium.weblayer.BrowserFragmentImpl;
+import org.chromium.weblayer.BrowserFragmentController;
 import org.chromium.weblayer.BrowserObserver;
 import org.chromium.weblayer.Profile;
 import org.chromium.weblayer.WebLayer;
@@ -40,38 +37,26 @@
     private static final boolean USE_WEBVIEW = false;
 
     private Profile mProfile;
-    private final BrowserFragmentImpl mBrowserFragments[] = new BrowserFragmentImpl[4];
+    private final BrowserFragmentController mBrowserFragmentControllers[] =
+            new BrowserFragmentController[4];
     private final ContainerFrameLayout mContainerViews[] = new ContainerFrameLayout[4];
     private final MyWebView mWebViews[] = new MyWebView[4];
     private FrameLayout mMainView;
 
-    public static class ShellFragment extends Fragment {
-        private BrowserFragmentImpl mBrowserFragment;
-
-        ShellFragment(BrowserFragmentImpl browserFragment) {
-            mBrowserFragment = browserFragment;
-        }
-
-        @Override
-        public View onCreateView(
-                LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-            return mBrowserFragment.onCreateView();
-        }
-    }
-
     public static class ContainerFrameLayout extends FrameLayout {
-        private final BrowserFragmentImpl mFragment;
+        private final BrowserFragmentController mFragmentController;
         private int mIndex;
         private boolean mInterceptTouchEvent;
 
-        public ContainerFrameLayout(Context context, BrowserFragmentImpl fragment, int index) {
+        public ContainerFrameLayout(Context context, BrowserFragmentController fragmentController,
+                int index) {
             super(context);
-            mFragment = fragment;
+            mFragmentController = fragmentController;
             mIndex = index;
         }
 
-        public BrowserFragmentImpl getFragment() {
-            return mFragment;
+        public BrowserFragmentController getFragmentController() {
+            return mFragmentController;
         }
 
         public void setInterceptTouchEvent(boolean intercept) {
@@ -130,18 +115,20 @@
     }
 
     private void createNewFragment(int index) {
-        mBrowserFragments[index] = mProfile.createBrowserFragment(this);
-        final BrowserController controller = mBrowserFragments[index].getBrowserController();
+        mBrowserFragmentControllers[index] = mProfile.createBrowserFragmentController(this);
+        final BrowserController controller = mBrowserFragmentControllers[index]
+                .getBrowserController();
 
         ContainerFrameLayout container =
-                new ContainerFrameLayout(this, mBrowserFragments[index], index);
+                new ContainerFrameLayout(this, mBrowserFragmentControllers[index],
+                        index);
         mContainerViews[index] = container;
         int viewId = View.generateViewId();
         container.setId(viewId);
         mMainView.addView(container);
 
         FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
-        transaction.add(viewId, new ShellFragment(mBrowserFragments[index]));
+        transaction.add(viewId, mBrowserFragmentControllers[index].getFragment());
         transaction.commit();
 
         EditText urlView = new EditText(this);
@@ -164,7 +151,7 @@
                 return true;
             }
         });
-        mBrowserFragments[index].setTopView(urlView);
+        mBrowserFragmentControllers[index].setTopView(urlView);
 
         controller.addObserver(new BrowserObserver() {
             @Override
@@ -216,21 +203,21 @@
             createNewFragment(1);
             createNewFragment(2);
 
-            mBrowserFragments[0].getBrowserController().getNavigationController().navigate(
-                    Uri.parse(sanitizeUrl("https://www.google.com")));
-            mBrowserFragments[1].getBrowserController().getNavigationController().navigate(
-                    Uri.parse(sanitizeUrl("https://en.wikipedia.org")));
-            mBrowserFragments[2].getBrowserController().getNavigationController().navigate(
-                    Uri.parse(sanitizeUrl("https://www.chromium.org")));
+            mBrowserFragmentControllers[0].getBrowserController().getNavigationController()
+                    .navigate(Uri.parse(sanitizeUrl("https://www.google.com")));
+            mBrowserFragmentControllers[1].getBrowserController().getNavigationController()
+                    .navigate(Uri.parse(sanitizeUrl("https://en.wikipedia.org")));
+            mBrowserFragmentControllers[2].getBrowserController().getNavigationController()
+                    .navigate(Uri.parse(sanitizeUrl("https://www.chromium.org")));
         }
     }
 
     @Override
     protected void onDestroy() {
-        for (int i = 0; i < mBrowserFragments.length; ++i) {
-            BrowserFragmentImpl fragment = mBrowserFragments[i];
+        for (int i = 0; i < mBrowserFragmentControllers.length; ++i) {
+            BrowserFragmentController fragment = mBrowserFragmentControllers[i];
             if (fragment != null) fragment.destroy();
-            mBrowserFragments[i] = null;
+            mBrowserFragmentControllers[i] = null;
         }
         if (mProfile != null) mProfile.destroy();
         super.onDestroy();
@@ -260,11 +247,11 @@
             mContainerViews[1].setOnClickListener(new OnClickImpl());
             mContainerViews[2].setOnClickListener(new OnClickImpl());
             mContainerViews[0].post(() -> {
-                mBrowserFragments[0].setSupportsEmbedding(true).addCallback(
+                mBrowserFragmentControllers[0].setSupportsEmbedding(true).addCallback(
                         (Boolean result) -> animateDown(mContainerViews[0]));
-                mBrowserFragments[1].setSupportsEmbedding(true).addCallback(
+                mBrowserFragmentControllers[1].setSupportsEmbedding(true).addCallback(
                         (Boolean result) -> animateDown(mContainerViews[1]));
-                mBrowserFragments[2].setSupportsEmbedding(true).addCallback(
+                mBrowserFragmentControllers[2].setSupportsEmbedding(true).addCallback(
                         (Boolean result) -> animateDown(mContainerViews[2]));
             });
         }
@@ -310,17 +297,18 @@
     private static void animateDown(ContainerFrameLayout container) {
         // Start animation after fullying switched from SurfaceView to TextureView.
         int index = container.getIndex();
-        container.getFragment().setSupportsEmbedding(true).addCallback((Boolean result) -> {
-            container.animate()
-                    .scaleX(1.0f / 3)
-                    .scaleY(1.0f / 3)
-                    .translationX(
-                            -container.getWidth() / 3.0f + (container.getWidth() / 3.0f * index))
-                    .translationY(container.getHeight() / 3.0f)
-                    .alpha(0.8f)
-                    .setDuration(500);
-            container.setInterceptTouchEvent(true);
-        });
+        container.getFragmentController().setSupportsEmbedding(true)
+                .addCallback((Boolean result) -> {
+                    container.animate()
+                            .scaleX(1.0f / 3)
+                            .scaleY(1.0f / 3)
+                            .translationX(-container.getWidth() / 3.0f
+                                    + (container.getWidth() / 3.0f * index))
+                            .translationY(container.getHeight() / 3.0f)
+                            .alpha(0.8f)
+                            .setDuration(500);
+                    container.setInterceptTouchEvent(true);
+                });
     }
 
     private static void animateUp(ContainerFrameLayout container) {
@@ -332,7 +320,7 @@
                 .alpha(1.0f)
                 .setDuration(500)
                 .withEndAction(() -> {
-                    container.getFragment().setSupportsEmbedding(false);
+                    container.getFragmentController().setSupportsEmbedding(false);
                     container.setInterceptTouchEvent(false);
                 });
     }
diff --git a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/RenderingTest.java b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/RenderingTest.java
index 3f62ea3..bf46c51 100644
--- a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/RenderingTest.java
+++ b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/RenderingTest.java
@@ -32,11 +32,11 @@
         String url = "data:text,foo";
 
         TestThreadUtils.runOnUiThreadBlocking(() -> {
-            activity.getBrowserFragmentImpl().setSupportsEmbedding(true).addCallback(
+            activity.getBrowserFragmentController().setSupportsEmbedding(true).addCallback(
                     (Boolean result) -> {
                         Assert.assertTrue(result);
-                        activity.getBrowserFragmentImpl().setSupportsEmbedding(false).addCallback(
-                                (Boolean result2) -> {
+                        activity.getBrowserFragmentController().setSupportsEmbedding(false)
+                                .addCallback((Boolean result2) -> {
                                     Assert.assertTrue(result2);
                                     mActivityTestRule.loadUrl(url);
                                     latch.countDown();
@@ -61,12 +61,12 @@
         CountDownLatch latch = new CountDownLatch(2);
         String url = "data:text,foo";
         TestThreadUtils.runOnUiThreadBlocking(() -> {
-            activity.getBrowserFragmentImpl().setSupportsEmbedding(true).addCallback(
+            activity.getBrowserFragmentController().setSupportsEmbedding(true).addCallback(
                     (Boolean result) -> {
                         Assert.assertTrue(result);
                         latch.countDown();
                     });
-            activity.getBrowserFragmentImpl().setSupportsEmbedding(true).addCallback(
+            activity.getBrowserFragmentController().setSupportsEmbedding(true).addCallback(
                     (Boolean result) -> {
                         Assert.assertTrue(result);
                         latch.countDown();
diff --git a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/SmokeTest.java b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/SmokeTest.java
index 16a8a071..0475055 100644
--- a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/SmokeTest.java
+++ b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/SmokeTest.java
@@ -28,11 +28,14 @@
         WebLayerShellActivity activity = mActivityTestRule.launchShellWithUrl("about:blank");
         Assert.assertNotNull(activity);
 
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> { activity.getBrowserFragmentController().setSupportsEmbedding(true); });
+
         CountDownLatch latch = new CountDownLatch(1);
         String url = "data:text,foo";
 
         TestThreadUtils.runOnUiThreadBlocking(() -> {
-            activity.getBrowserFragmentImpl().setSupportsEmbedding(true).addCallback(
+            activity.getBrowserFragmentController().setSupportsEmbedding(true).addCallback(
                     (Boolean result) -> {
                         Assert.assertTrue(result);
                         mActivityTestRule.loadUrl(url);
diff --git a/weblayer/shell/android/shell_apk/src/org/chromium/weblayer/shell/WebLayerShellActivity.java b/weblayer/shell/android/shell_apk/src/org/chromium/weblayer/shell/WebLayerShellActivity.java
index ae9a579..f8aa33d 100644
--- a/weblayer/shell/android/shell_apk/src/org/chromium/weblayer/shell/WebLayerShellActivity.java
+++ b/weblayer/shell/android/shell_apk/src/org/chromium/weblayer/shell/WebLayerShellActivity.java
@@ -7,15 +7,12 @@
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
-import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentActivity;
 import android.support.v4.app.FragmentTransaction;
 import android.text.InputType;
 import android.text.TextUtils;
 import android.view.KeyEvent;
-import android.view.LayoutInflater;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.view.inputmethod.EditorInfo;
 import android.widget.EditText;
@@ -26,7 +23,7 @@
 import android.widget.TextView.OnEditorActionListener;
 
 import org.chromium.weblayer.BrowserController;
-import org.chromium.weblayer.BrowserFragmentImpl;
+import org.chromium.weblayer.BrowserFragmentController;
 import org.chromium.weblayer.BrowserObserver;
 import org.chromium.weblayer.Profile;
 import org.chromium.weblayer.WebLayer;
@@ -38,32 +35,18 @@
     private static final String TAG = "WebLayerShell";
 
     private Profile mProfile;
-    private BrowserFragmentImpl mBrowserFragment;
+    private BrowserFragmentController mBrowserFragmentController;
     private BrowserController mBrowserController;
     private EditText mUrlView;
     private ProgressBar mLoadProgressBar;
     private View mMainView;
 
-    public static class ShellFragment extends Fragment {
-        private BrowserFragmentImpl mBrowserFragment;
-
-        ShellFragment(BrowserFragmentImpl browserFragment) {
-            mBrowserFragment = browserFragment;
-        }
-
-        @Override
-        public View onCreateView(
-                LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-            return mBrowserFragment.onCreateView();
-        }
-    }
-
     public BrowserController getBrowserController() {
         return mBrowserController;
     }
 
-    public BrowserFragmentImpl getBrowserFragmentImpl() {
-        return mBrowserFragment;
+    public BrowserFragmentController getBrowserFragmentController() {
+        return mBrowserFragmentController;
     }
 
     @Override
@@ -118,15 +101,16 @@
         topContentsContainer.addView(mLoadProgressBar, progressLayoutParams);
 
         mProfile = WebLayer.getInstance().createProfile(null);
-        mBrowserFragment = mProfile.createBrowserFragment(this);
-        mBrowserController = mBrowserFragment.getBrowserController();
+
+        mBrowserFragmentController = mProfile.createBrowserFragmentController(this);
 
         FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
-        transaction.add(viewId, new ShellFragment(mBrowserFragment));
+        transaction.add(viewId, mBrowserFragmentController.getFragment());
         transaction.commit();
 
-        mBrowserFragment.setTopView(topContentsContainer);
+        mBrowserFragmentController.setTopView(topContentsContainer);
 
+        mBrowserController = mBrowserFragmentController.getBrowserController();
         String startupUrl = getUrlFromIntent(getIntent());
         if (TextUtils.isEmpty(startupUrl)) {
             startupUrl = "http://google.com";
@@ -154,7 +138,7 @@
     @Override
     protected void onDestroy() {
         if (mProfile != null) mProfile.destroy();
-        if (mBrowserFragment != null) mBrowserFragment.destroy();
+        if (mBrowserFragmentController != null) mBrowserFragmentController.destroy();
         super.onDestroy();
     }