diff --git a/.gitignore b/.gitignore
index c75691e2..f6164b32 100644
--- a/.gitignore
+++ b/.gitignore
@@ -295,6 +295,7 @@
 /tools/metrics/actions/actions.old.xml
 /tools/metrics/histograms/histograms.before.pretty-print.xml
 /tools/metrics/histograms/histograms_xml/*.before.pretty-print.xml
+/tools/metrics/histograms/histograms_xml/*/*.before.pretty-print.xml
 /tools/metrics/histograms/enums.before.pretty-print.xml
 /tools/page_cycler/acid3
 /tools/reclient
diff --git a/DEPS b/DEPS
index 7b9045e..334a5d8 100644
--- a/DEPS
+++ b/DEPS
@@ -204,11 +204,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': 'c0c5106bd4d4f5c0142221109563eee45663eef5',
+  'skia_revision': 'fa8d6915cbbf8cc7f6bc11c2c6bb7eaa36c2b5df',
   # 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': '04e154e4ca48094b482c0f1d77803987ec7b7cc6',
+  'v8_revision': 'ab473c140fe5b583fe97ecb319840f23168f425a',
   # 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.
@@ -279,7 +279,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': '63989d27ead708330f28ebce558f547cee3e4300',
+  'devtools_frontend_revision': 'b917ab64e84b7b91b925c1fc7c187e95b6602085',
   # 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.
@@ -331,7 +331,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': '10cb17e079e14f4f9a1bdaea9b46b343c82c4679',
+  'dawn_revision': 'ab5821d0166feabf7690b7d2399ad36870501e72',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -370,7 +370,7 @@
   'ukey2_revision': '0275885d8e6038c39b8a8ca55e75d1d4d1727f47',
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'tint_revision': '76d12f0f5a330e613a068059a19915182144069b',
+  'tint_revision': '00b77a80ab137229b2024fcf0e98c5e38ffc05fd',
 
   # TODO(crbug.com/941824): The values below need to be kept in sync
   # between //DEPS and //buildtools/DEPS, so if you're updating one,
@@ -923,7 +923,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '968b1fe7d7cb848e250ffb62e27f547450f5b9e9',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '079a95bc72408f034a8ffbcb1ae70b54ef155aa0',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1545,7 +1545,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '3c2fe3888658d82b47ca831d59a2e07579619c2d',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '31d3b217d3b5c9e98559bb0ef9612659b36e88e5',
+    Var('webrtc_git') + '/src.git' + '@' + 'ad70609509a98138cd6391828e4adafeb2f35b3d',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1617,7 +1617,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@d472d834dbda0e46609e789bd5336f1e245e37e9',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@1df52ed5909b6872b8d7a76269c0e6247d4a101d',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index a81d5c4..4f3456c 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -5214,3 +5214,115 @@
         'in a way that is not backward-compatible.',
         long_text=error)]
   return []
+
+def CheckDeprecationOfPreferences(input_api, output_api):
+  """Removing a preference should come with a deprecation."""
+
+  def FilterFile(affected_file):
+    """Accept only .cc files and the like."""
+    file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
+    files_to_skip = (_EXCLUDED_PATHS +
+                     _TEST_CODE_EXCLUDED_PATHS +
+                     input_api.DEFAULT_FILES_TO_SKIP)
+    return input_api.FilterSourceFile(
+      affected_file,
+      files_to_check=file_inclusion_pattern,
+      files_to_skip=files_to_skip)
+
+  def ModifiedLines(affected_file):
+    """Returns a list of tuples (line number, line text) of added and removed
+    lines.
+
+    Deleted lines share the same line number as the previous line.
+
+    This relies on the scm diff output describing each changed code section
+    with a line of the form
+
+    ^@@ <old line num>,<old size> <new line num>,<new size> @@$
+    """
+    line_num = 0
+    modified_lines = []
+    for line in affected_file.GenerateScmDiff().splitlines():
+      # Extract <new line num> of the patch fragment (see format above).
+      m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@', line)
+      if m:
+        line_num = int(m.groups(1)[0])
+        continue
+      if ((line.startswith('+') and not line.startswith('++')) or
+          (line.startswith('-') and not line.startswith('--'))):
+        modified_lines.append((line_num, line))
+
+      if not line.startswith('-'):
+        line_num += 1
+    return modified_lines
+
+  def FindLineWith(lines, needle):
+    """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
+
+    If 0 or >1 lines contain `needle`, -1 is returned.
+    """
+    matching_line_numbers = [
+        # + 1 for 1-based counting of line numbers.
+        i + 1 for i, line
+        in enumerate(lines)
+        if needle in line]
+    return matching_line_numbers[0] if len(matching_line_numbers) == 1 else -1
+
+  def ModifiedPrefMigration(affected_file):
+    """Returns whether the MigrateObsolete.*Pref functions were modified."""
+    # Determine first and last lines of MigrateObsolete.*Pref functions.
+    new_contents = affected_file.NewContents();
+    range_1 = (
+        FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
+        FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
+    range_2 = (
+        FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
+        FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
+    if (-1 in range_1 + range_2):
+      raise Exception(
+          'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.')
+
+    # Check whether any of the modified lines are part of the
+    # MigrateObsolete.*Pref functions.
+    for line_nr, line in ModifiedLines(affected_file):
+      if (range_1[0] <= line_nr <= range_1[1] or
+          range_2[0] <= line_nr <= range_2[1]):
+        return True
+    return False
+
+  register_pref_pattern = input_api.re.compile(r'Register.+Pref')
+  browser_prefs_file_pattern = input_api.re.compile(
+      r'chrome/browser/prefs/browser_prefs.cc')
+
+  changes = input_api.AffectedFiles(include_deletes=True,
+                                    file_filter=FilterFile)
+  potential_problems = []
+  for f in changes:
+    for line in f.GenerateScmDiff().splitlines():
+      # Check deleted lines for pref registrations.
+      if (line.startswith('-') and not line.startswith('--') and
+          register_pref_pattern.search(line)):
+        potential_problems.append('%s: %s' % (f.LocalPath(), line))
+
+    if browser_prefs_file_pattern.search(f.LocalPath()):
+      # If the developer modified the MigrateObsolete.*Prefs() functions, we
+      # assume that they knew that they have to deprecate preferences and don't
+      # warn.
+      try:
+        if ModifiedPrefMigration(f):
+          return []
+      except Exception as e:
+        return [output_api.PresubmitError(str(e))]
+
+  if potential_problems:
+    return [output_api.PresubmitPromptWarning(
+      'Discovered possible removal of preference registrations.\n\n'
+      'Please make sure to properly deprecate preferences by clearing their\n'
+      'value for a couple of milestones before finally removing the code.\n'
+      'Otherwise data may stay in the preferences files forever. See\n'
+      'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc for examples.\n'
+      'This may be a false positive warning (e.g. if you move preference\n'
+      'registrations to a different place).\n',
+      potential_problems
+    )]
+  return []
diff --git a/PRESUBMIT_test.py b/PRESUBMIT_test.py
index 2dfa78a..3dbbb77b 100755
--- a/PRESUBMIT_test.py
+++ b/PRESUBMIT_test.py
@@ -3658,5 +3658,156 @@
     self.assertEqual([], errors)
 
 
+class CheckDeprecationOfPreferencesTest(unittest.TestCase):
+  # Test that a warning is generated if a preference registration is removed
+  # from a random file.
+  def testWarning(self):
+    mock_input_api = MockInputApi()
+    mock_input_api.files = [
+        MockAffectedFile(
+            'foo.cc',
+            ['A', 'B'],
+            ['A', 'prefs->RegisterStringPref("foo", "default");', 'B'],
+            scm_diff='\n'.join([
+                '--- foo.cc.old  2020-12-02 20:40:54.430676385 +0100',
+                '+++ foo.cc.new  2020-12-02 20:41:02.086700197 +0100',
+                '@@ -1,3 +1,2 @@',
+                ' A',
+                '-prefs->RegisterStringPref("foo", "default");',
+                ' B']),
+            action='M')
+    ]
+    mock_output_api = MockOutputApi()
+    errors = PRESUBMIT.CheckDeprecationOfPreferences(mock_input_api,
+                                                     mock_output_api)
+    self.assertEqual(1, len(errors))
+    self.assertTrue(
+        'Discovered possible removal of preference registrations' in
+        errors[0].message)
+
+  # Test that a warning is inhibited if the preference registration was moved
+  # to the deprecation functions in browser prefs.
+  def testNoWarningForMigration(self):
+    mock_input_api = MockInputApi()
+    mock_input_api.files = [
+        # RegisterStringPref was removed from foo.cc.
+        MockAffectedFile(
+            'foo.cc',
+            ['A', 'B'],
+            ['A', 'prefs->RegisterStringPref("foo", "default");', 'B'],
+            scm_diff='\n'.join([
+                '--- foo.cc.old  2020-12-02 20:40:54.430676385 +0100',
+                '+++ foo.cc.new  2020-12-02 20:41:02.086700197 +0100',
+                '@@ -1,3 +1,2 @@',
+                ' A',
+                '-prefs->RegisterStringPref("foo", "default");',
+                ' B']),
+            action='M'),
+        # But the preference was properly migrated.
+        MockAffectedFile(
+            'chrome/browser/prefs/browser_prefs.cc',
+            [
+                 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
+                 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
+                 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
+                 'prefs->RegisterStringPref("foo", "default");',
+                 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
+            ],
+            [
+                 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
+                 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
+                 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
+                 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
+            ],
+            scm_diff='\n'.join([
+                 '--- browser_prefs.cc.old 2020-12-02 20:51:40.812686731 +0100',
+                 '+++ browser_prefs.cc.new 2020-12-02 20:52:02.936755539 +0100',
+                 '@@ -2,3 +2,4 @@',
+                 ' // END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
+                 ' // BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
+                 '+prefs->RegisterStringPref("foo", "default");',
+                 ' // END_MIGRATE_OBSOLETE_PROFILE_PREFS']),
+            action='M'),
+    ]
+    mock_output_api = MockOutputApi()
+    errors = PRESUBMIT.CheckDeprecationOfPreferences(mock_input_api,
+                                                     mock_output_api)
+    self.assertEqual(0, len(errors))
+
+  # Test that a warning is NOT inhibited if the preference registration was
+  # moved to a place outside of the migration functions in browser_prefs.cc
+  def testWarningForImproperMigration(self):
+    mock_input_api = MockInputApi()
+    mock_input_api.files = [
+        # RegisterStringPref was removed from foo.cc.
+        MockAffectedFile(
+            'foo.cc',
+            ['A', 'B'],
+            ['A', 'prefs->RegisterStringPref("foo", "default");', 'B'],
+            scm_diff='\n'.join([
+                '--- foo.cc.old  2020-12-02 20:40:54.430676385 +0100',
+                '+++ foo.cc.new  2020-12-02 20:41:02.086700197 +0100',
+                '@@ -1,3 +1,2 @@',
+                ' A',
+                '-prefs->RegisterStringPref("foo", "default");',
+                ' B']),
+            action='M'),
+        # The registration call was moved to a place in browser_prefs.cc that
+        # is outside the migration functions.
+        MockAffectedFile(
+            'chrome/browser/prefs/browser_prefs.cc',
+            [
+                 'prefs->RegisterStringPref("foo", "default");',
+                 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
+                 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
+                 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
+                 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
+            ],
+            [
+                 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
+                 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
+                 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
+                 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
+            ],
+            scm_diff='\n'.join([
+                 '--- browser_prefs.cc.old 2020-12-02 20:51:40.812686731 +0100',
+                 '+++ browser_prefs.cc.new 2020-12-02 20:52:02.936755539 +0100',
+                 '@@ -1,2 +1,3 @@',
+                 '+prefs->RegisterStringPref("foo", "default");',
+                 ' // BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
+                 ' // END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS']),
+            action='M'),
+    ]
+    mock_output_api = MockOutputApi()
+    errors = PRESUBMIT.CheckDeprecationOfPreferences(mock_input_api,
+                                                     mock_output_api)
+    self.assertEqual(1, len(errors))
+    self.assertTrue(
+        'Discovered possible removal of preference registrations' in
+        errors[0].message)
+
+  # Check that the presubmit fails if a marker line in brower_prefs.cc is
+  # deleted.
+  def testDeletedMarkerRaisesError(self):
+    mock_input_api = MockInputApi()
+    mock_input_api.files = [
+        MockAffectedFile('chrome/browser/prefs/browser_prefs.cc',
+                         [
+                           '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
+                           '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
+                           '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
+                           # The following line is deleted for this test
+                           # '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
+                         ])
+    ]
+    mock_output_api = MockOutputApi()
+    errors = PRESUBMIT.CheckDeprecationOfPreferences(mock_input_api,
+                                                     mock_output_api)
+    self.assertEqual(1, len(errors))
+    self.assertEqual(
+        'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.',
+        errors[0].message)
+
+
 if __name__ == '__main__':
   unittest.main()
diff --git a/PRESUBMIT_test_mocks.py b/PRESUBMIT_test_mocks.py
index 0a9e5a5..f8143ae 100644
--- a/PRESUBMIT_test_mocks.py
+++ b/PRESUBMIT_test_mocks.py
@@ -179,16 +179,21 @@
   MockInputApi for presubmit unittests.
   """
 
-  def __init__(self, local_path, new_contents, old_contents=None, action='A'):
+  def __init__(self, local_path, new_contents, old_contents=None, action='A',
+               scm_diff=None):
     self._local_path = local_path
     self._new_contents = new_contents
     self._changed_contents = [(i + 1, l) for i, l in enumerate(new_contents)]
     self._action = action
-    self._scm_diff = "--- /dev/null\n+++ %s\n@@ -0,0 +1,%d @@\n" % (local_path,
-      len(new_contents))
+    if scm_diff:
+      self._scm_diff = scm_diff
+    else:
+      self._scm_diff = (
+        "--- /dev/null\n+++ %s\n@@ -0,0 +1,%d @@\n" %
+            (local_path, len(new_contents)))
+      for l in new_contents:
+        self._scm_diff += "+%s\n" % l
     self._old_contents = old_contents
-    for l in new_contents:
-      self._scm_diff += "+%s\n" % l
 
   def Action(self):
     return self._action
diff --git a/ash/ash_prefs.cc b/ash/ash_prefs.cc
index 4ffdb57..720ed04 100644
--- a/ash/ash_prefs.cc
+++ b/ash/ash_prefs.cc
@@ -88,6 +88,9 @@
     registry->RegisterBooleanPref(
         chromeos::prefs::kSuggestedContentEnabled, true,
         user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
+    registry->RegisterBooleanPref(
+        prefs::kLiveCaptionEnabled, false,
+        user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
   }
 }
 
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 2f3e670..70df28a 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -1701,6 +1701,17 @@
         Mic jack
       </message>
 
+      <!-- Status tray Live Caption strings. -->
+      <message name="IDS_ASH_STATUS_TRAY_LIVE_CAPTION_TOGGLE_TOOLTIP" desc="The tooltip text used for the button in the status tray to toggle the Live Caption feature on or off.">
+        Toggle Live Caption. <ph name="STATE_TEXT">$1<ex>Live Caption is on.</ex></ph>
+      </message>
+      <message name="IDS_ASH_STATUS_TRAY_LIVE_CAPTION_ENABLED_STATE_TOOLTIP" desc="The tooltip text indicating the Live Caption feature is on.">
+        Live Caption is on.
+      </message>
+      <message name="IDS_ASH_STATUS_TRAY_LIVE_CAPTION_DISABLED_STATE_TOOLTIP" desc="The tooltip text indicating the Live Caption feature is off.">
+        Live Caption is off.
+      </message>
+
       <message name="IDS_AURA_SET_DESKTOP_WALLPAPER" desc="The label used for change wallpaper in context menu">
         Set wallpaper
       </message>
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_LIVE_CAPTION_DISABLED_STATE_TOOLTIP.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_LIVE_CAPTION_DISABLED_STATE_TOOLTIP.png.sha1
new file mode 100644
index 0000000..35f1f85
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_LIVE_CAPTION_DISABLED_STATE_TOOLTIP.png.sha1
@@ -0,0 +1 @@
+22cea29cf438b1550a0c70d262e23977fbc7c970
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_LIVE_CAPTION_ENABLED_STATE_TOOLTIP.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_LIVE_CAPTION_ENABLED_STATE_TOOLTIP.png.sha1
new file mode 100644
index 0000000..168a6ea
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_LIVE_CAPTION_ENABLED_STATE_TOOLTIP.png.sha1
@@ -0,0 +1 @@
+83265cf1191c34a9015b0ac7baf743a75a06fb56
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_LIVE_CAPTION_TOGGLE_TOOLTIP.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_LIVE_CAPTION_TOGGLE_TOOLTIP.png.sha1
new file mode 100644
index 0000000..168a6ea
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_LIVE_CAPTION_TOGGLE_TOOLTIP.png.sha1
@@ -0,0 +1 @@
+83265cf1191c34a9015b0ac7baf743a75a06fb56
\ No newline at end of file
diff --git a/ash/clipboard/clipboard_history_menu_model_adapter.cc b/ash/clipboard/clipboard_history_menu_model_adapter.cc
index 8cbe91be..d6acdff 100644
--- a/ash/clipboard/clipboard_history_menu_model_adapter.cc
+++ b/ash/clipboard/clipboard_history_menu_model_adapter.cc
@@ -12,8 +12,6 @@
 #include "base/metrics/histogram_macros.h"
 #include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/base/clipboard/clipboard.h"
-#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
-#include "ui/base/data_transfer_policy/data_transfer_policy_controller.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/ui_base_types.h"
 #include "ui/gfx/geometry/rect.h"
@@ -27,17 +25,6 @@
 
 namespace ash {
 
-namespace {
-bool IsDataReadAllowed(const ui::DataTransferEndpoint* source,
-                       const ui::DataTransferEndpoint* destination) {
-  ui::DataTransferPolicyController* policy_controller =
-      ui::DataTransferPolicyController::Get();
-  if (!policy_controller)
-    return true;
-  return policy_controller->IsDataReadAllowed(source, destination);
-}
-}  // namespace
-
 // static
 std::unique_ptr<ClipboardHistoryMenuModelAdapter>
 ClipboardHistoryMenuModelAdapter::Create(
@@ -74,14 +61,6 @@
                                           /*notify_if_restricted=*/false);
   for (const auto& item : items) {
     model_->AddItem(command_id, base::string16());
-
-    // Enable or disable the command depending on whether its corresponding
-    // clipboard history item is allowed to read or not.
-    // This clipboard read isn't initiated by the user, that's why it shouldn't
-    // notify if the clipboard is restricted.
-    model_->SetEnabledAt(model_->GetIndexOfCommandId(command_id),
-                         IsDataReadAllowed(item.data().source(), &data_dst));
-
     item_snapshots_.emplace(command_id, item);
     ++command_id;
   }
@@ -274,34 +253,26 @@
   SelectMenuItemWithCommandId(next_selected_item_command);
 }
 
-base::Optional<int>
-ClipboardHistoryMenuModelAdapter::CalculateSelectedCommandIdAfterDeletion(
+int ClipboardHistoryMenuModelAdapter::CalculateSelectedCommandIdAfterDeletion(
     int command_id) const {
   // If the menu item view to be deleted is the last one, Cancel()
   // should be called so this function should not be hit.
   DCHECK_GT(item_snapshots_.size(), 1u);
 
-  auto start_item = item_snapshots_.find(command_id);
-  DCHECK(start_item != item_snapshots_.cend());
+  auto item_to_delete = item_snapshots_.find(command_id);
+  DCHECK(item_to_delete != item_snapshots_.cend());
 
-  // Search in the forward direction.
-  auto check_function = [this](const auto& key_value) -> bool {
-    return model_->IsEnabledAt(model_->GetIndexOfCommandId(key_value.first));
-  };
-  auto selectable_iter_forward = std::find_if(
-      std::next(start_item, 1), item_snapshots_.cend(), check_function);
-  if (selectable_iter_forward != item_snapshots_.cend())
-    return selectable_iter_forward->first;
+  // Use the menu item right after the one to be deleted if any. Otherwise,
+  // select the previous one.
 
-  // If no selectable item is found, then search in the reverse direction.
-  auto selectable_iter_reverse =
-      std::find_if(std::make_reverse_iterator(start_item),
-                   item_snapshots_.crend(), check_function);
-  if (selectable_iter_reverse != item_snapshots_.crend())
-    return selectable_iter_reverse->first;
+  auto next_item_iter = item_to_delete;
+  ++next_item_iter;
+  if (next_item_iter != item_snapshots_.cend())
+    return next_item_iter->first;
 
-  // No other selectable item, then returns the invalid id.
-  return base::nullopt;
+  auto previous_item_iter = item_to_delete;
+  --previous_item_iter;
+  return previous_item_iter->first;
 }
 
 void ClipboardHistoryMenuModelAdapter::RemoveItemView(int command_id) {
diff --git a/ash/clipboard/clipboard_history_menu_model_adapter.h b/ash/clipboard/clipboard_history_menu_model_adapter.h
index 8b88d80..d995d20 100644
--- a/ash/clipboard/clipboard_history_menu_model_adapter.h
+++ b/ash/clipboard/clipboard_history_menu_model_adapter.h
@@ -105,11 +105,9 @@
   // `reverse` is true).
   void AdvancePseudoFocusFromSelectedItem(bool reverse);
 
-  // Returns the command id of the menu item to be selected if any after the
-  // menu item specified by `command_id` is deleted. If no menu item is
-  // selectable after deletion, an absent value is returned.
-  base::Optional<int> CalculateSelectedCommandIdAfterDeletion(
-      int command_id) const;
+  // Returns the command id of the menu item to be selected after the
+  // menu item specified by `command_id` is deleted.
+  int CalculateSelectedCommandIdAfterDeletion(int command_id) const;
 
   // Removes the item view specified by `command_id` from the root menu.
   void RemoveItemView(int command_id);
diff --git a/ash/clipboard/views/clipboard_history_bitmap_item_view.cc b/ash/clipboard/views/clipboard_history_bitmap_item_view.cc
index 658b8d17..60c287a5 100644
--- a/ash/clipboard/views/clipboard_history_bitmap_item_view.cc
+++ b/ash/clipboard/views/clipboard_history_bitmap_item_view.cc
@@ -19,7 +19,6 @@
 #include "ui/compositor/layer_animation_observer.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
 #include "ui/gfx/image/image_skia.h"
-#include "ui/gfx/image/image_skia_operations.h"
 #include "ui/strings/grit/ui_strings.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/layout/box_layout.h"
@@ -51,13 +50,11 @@
  public:
   FadeImageView(const ClipboardHistoryItem* clipboard_history_item,
                 const ClipboardHistoryResourceManager* resource_manager,
-                float opacity,
                 base::RepeatingClosure update_callback)
       : RoundedImageView(ClipboardHistoryViews::kImageRoundedCornerRadius,
                          RoundedImageView::Alignment::kCenter),
         resource_manager_(resource_manager),
         clipboard_history_item_(*clipboard_history_item),
-        opacity_(opacity),
         update_callback_(update_callback) {
     resource_manager_->AddObserver(this);
     SetImageFromModel();
@@ -119,12 +116,7 @@
         *(resource_manager_->GetImageModel(clipboard_history_item_)
               .GetImage()
               .ToImageSkia());
-    if (opacity_ != 1.f) {
-      SetImage(
-          gfx::ImageSkiaOperations::CreateTransparentImage(image, opacity_));
-    } else {
       SetImage(image);
-    }
 
     // When fading in a new image, the ImageView's image has likely changed
     // sizes.
@@ -149,9 +141,6 @@
   // The ClipboardHistoryItem represented by this class.
   const ClipboardHistoryItem clipboard_history_item_;
 
-  // The opacity of the image content.
-  const float opacity_;
-
   // Used to notify of image changes.
   base::RepeatingClosure update_callback_;
 };
@@ -231,16 +220,11 @@
     // if menu items have their own layers, the part beyond the container's
     // bounds is still visible when the context menu is in overflow.
 
-    const float image_opacity =
-        container_->IsItemEnabled()
-            ? 1.f
-            : ClipboardHistoryViews::kDisabledImageAlpha;
     const auto* clipboard_history_item = container_->clipboard_history_item();
     switch (container_->data_format_) {
       case ui::ClipboardInternalFormat::kHtml:
         return std::make_unique<FadeImageView>(
             clipboard_history_item, container_->resource_manager_,
-            image_opacity,
             base::BindRepeating(&BitmapContentsView::UpdateImageViewSize,
                                 weak_ptr_factory_.GetWeakPtr()));
       case ui::ClipboardInternalFormat::kBitmap: {
@@ -249,10 +233,6 @@
             RoundedImageView::Alignment::kCenter);
         gfx::ImageSkia bitmap_image = gfx::ImageSkia::CreateFrom1xBitmap(
             clipboard_history_item->data().bitmap());
-        if (image_opacity != 1.f) {
-          bitmap_image = gfx::ImageSkiaOperations::CreateTransparentImage(
-              bitmap_image, image_opacity);
-        }
         image_view->SetImage(bitmap_image);
         return image_view;
       }
diff --git a/ash/clipboard/views/clipboard_history_item_view.cc b/ash/clipboard/views/clipboard_history_item_view.cc
index f57e815..4c46dee5 100644
--- a/ash/clipboard/views/clipboard_history_item_view.cc
+++ b/ash/clipboard/views/clipboard_history_item_view.cc
@@ -234,10 +234,6 @@
   }
 }
 
-bool ClipboardHistoryItemView::IsItemEnabled() const {
-  return container_->GetEnabled();
-}
-
 gfx::Size ClipboardHistoryItemView::CalculatePreferredSize() const {
   const int preferred_width =
       views::MenuConfig::instance().touchable_menu_width;
@@ -283,7 +279,7 @@
 }
 
 bool ClipboardHistoryItemView::ShouldHighlight() const {
-  return pseudo_focus_ == PseudoFocus::kMainButton && IsItemEnabled();
+  return pseudo_focus_ == PseudoFocus::kMainButton;
 }
 
 bool ClipboardHistoryItemView::ShouldShowDeleteButton() const {
diff --git a/ash/clipboard/views/clipboard_history_item_view.h b/ash/clipboard/views/clipboard_history_item_view.h
index bc4e948..c081d42f 100644
--- a/ash/clipboard/views/clipboard_history_item_view.h
+++ b/ash/clipboard/views/clipboard_history_item_view.h
@@ -109,10 +109,6 @@
   // Returns the name of the accessible node.
   virtual base::string16 GetAccessibleName() const = 0;
 
-  // Returns whether the item view is enabled. The item view is disabled when
-  // it is not allowed to read clipboard data.
-  bool IsItemEnabled() const;
-
   const ClipboardHistoryItem* clipboard_history_item() const {
     return clipboard_history_item_;
   }
diff --git a/ash/clipboard/views/clipboard_history_label.cc b/ash/clipboard/views/clipboard_history_label.cc
index c7802fc9..9662b46 100644
--- a/ash/clipboard/views/clipboard_history_label.cc
+++ b/ash/clipboard/views/clipboard_history_label.cc
@@ -32,12 +32,8 @@
   // TODO(andrewxu): remove this line after https://crbug.com/1143009 is fixed.
   ash::ScopedLightModeAsDefault scoped_light_mode_as_default;
 
-  const auto color_type =
-      GetEnabled()
-          ? ash::AshColorProvider::ContentLayerType::kTextColorPrimary
-          : ash::AshColorProvider::ContentLayerType::kTextColorSecondary;
-  SetEnabledColor(
-      ash::AshColorProvider::Get()->GetContentLayerColor(color_type));
+  SetEnabledColor(ash::AshColorProvider::Get()->GetContentLayerColor(
+      ash::AshColorProvider::ContentLayerType::kTextColorPrimary));
 }
 
 }  // namespace ash
diff --git a/ash/clipboard/views/clipboard_history_text_item_view.cc b/ash/clipboard/views/clipboard_history_text_item_view.cc
index 3c13c6e..7903ec9 100644
--- a/ash/clipboard/views/clipboard_history_text_item_view.cc
+++ b/ash/clipboard/views/clipboard_history_text_item_view.cc
@@ -33,7 +33,6 @@
     auto* label =
         AddChildView(std::make_unique<ClipboardHistoryLabel>(container->text_));
     layout->SetFlexForView(label, /*flex_weight=*/1);
-    label->SetEnabled(container->IsItemEnabled());
 
     InstallDeleteButton();
   }
diff --git a/ash/clipboard/views/clipboard_history_view_constants.h b/ash/clipboard/views/clipboard_history_view_constants.h
index 3443c49..71f65c3 100644
--- a/ash/clipboard/views/clipboard_history_view_constants.h
+++ b/ash/clipboard/views/clipboard_history_view_constants.h
@@ -41,9 +41,6 @@
 // The thickness of the image border.
 constexpr int kImageBorderThickness = 1;
 
-// The opacity of the image shown in a disabled item view.
-constexpr float kDisabledImageAlpha = 0.38f;
-
 }  // namespace ClipboardHistoryViews
 }  // namespace ash
 
diff --git a/ash/public/cpp/ash_pref_names.cc b/ash/public/cpp/ash_pref_names.cc
index c374cb1..7d3a3c2 100644
--- a/ash/public/cpp/ash_pref_names.cc
+++ b/ash/public/cpp/ash_pref_names.cc
@@ -135,6 +135,9 @@
     "settings.a11y.tablet_mode_shelf_nav_buttons_enabled";
 // A boolean pref which determines whether dictation is enabled.
 const char kAccessibilityDictationEnabled[] = "settings.a11y.dictation";
+// Whether the Live Caption feature is enabled.
+const char kLiveCaptionEnabled[] =
+    "accessibility.captions.live_caption_enabled";
 // A boolean pref which determines whether the accessibility menu shows
 // regardless of the state of a11y features.
 const char kShouldAlwaysShowAccessibilityMenu[] = "settings.a11y.enable_menu";
diff --git a/ash/public/cpp/ash_pref_names.h b/ash/public/cpp/ash_pref_names.h
index 2fd3d29e..e86ac4ad 100644
--- a/ash/public/cpp/ash_pref_names.h
+++ b/ash/public/cpp/ash_pref_names.h
@@ -52,6 +52,7 @@
 ASH_PUBLIC_EXPORT extern const char
     kAccessibilityTabletModeShelfNavigationButtonsEnabled[];
 ASH_PUBLIC_EXPORT extern const char kAccessibilityDictationEnabled[];
+ASH_PUBLIC_EXPORT extern const char kLiveCaptionEnabled[];
 ASH_PUBLIC_EXPORT extern const char kShouldAlwaysShowAccessibilityMenu[];
 
 ASH_PUBLIC_EXPORT extern const char kContextualTooltips[];
diff --git a/ash/system/audio/unified_volume_view.cc b/ash/system/audio/unified_volume_view.cc
index 78e2f1a..74641e3 100644
--- a/ash/system/audio/unified_volume_view.cc
+++ b/ash/system/audio/unified_volume_view.cc
@@ -4,14 +4,23 @@
 
 #include "ash/system/audio/unified_volume_view.h"
 
+#include <cmath>
+#include <memory>
+#include <utility>
+
 #include "ash/public/cpp/ash_features.h"
+#include "ash/public/cpp/ash_pref_names.h"
 #include "ash/resources/vector_icons/vector_icons.h"
+#include "ash/session/session_controller_impl.h"
+#include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/ash_color_provider.h"
 #include "ash/system/tray/tray_popup_utils.h"
 #include "base/i18n/rtl.h"
 #include "base/stl_util.h"
+#include "components/prefs/pref_service.h"
 #include "components/vector_icons/vector_icons.h"
+#include "media/base/media_switches.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/image/image_skia_operations.h"
@@ -21,6 +30,7 @@
 #include "ui/views/animation/ink_drop_impl.h"
 #include "ui/views/animation/ink_drop_mask.h"
 #include "ui/views/background.h"
+#include "ui/views/controls/button/image_button_factory.h"
 #include "ui/views/controls/highlight_path_generator.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/layout/box_layout.h"
@@ -53,15 +63,125 @@
   return *kVolumeLevelIcons[index];
 }
 
-SkColor GetBackgroundColorOfMoreButton() {
-  return AshColorProvider::Get()->GetControlsLayerColor(
-      AshColorProvider::ControlsLayerType::kControlBackgroundColorInactive);
-}
+// A template class for the UnifiedVolumeView buttons, used by the More and
+// Live Caption buttons. |T| must be a subtype of |views::Button|.
+template <typename T>
+class UnifiedVolumeViewButton : public T {
+ public:
+  static_assert(std::is_base_of<views::Button, T>::value,
+                "T must be a subtype of views::Button");
 
-class MoreButton : public views::Button {
+  // A constructor that forwards |args| to |T|'s constructor, so |args| are the
+  // exact same as required by |T|'s constructor. It sets up the ink drop on the
+  // view.
+  template <typename... Args>
+  explicit UnifiedVolumeViewButton(Args... args)
+      : T(std::forward<Args>(args)...) {
+    TrayPopupUtils::ConfigureTrayPopupButton(this);
+
+    views::InstallRoundRectHighlightPathGenerator(this, gfx::Insets(),
+                                                  kTrayItemCornerRadius);
+    T::SetBackground(views::CreateRoundedRectBackground(GetBackgroundColor(),
+                                                        kTrayItemCornerRadius));
+  }
+
+  ~UnifiedVolumeViewButton() override = default;
+
+  std::unique_ptr<views::InkDrop> CreateInkDrop() override {
+    return TrayPopupUtils::CreateInkDrop(this);
+  }
+
+  std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override {
+    return TrayPopupUtils::CreateInkDropRipple(
+        TrayPopupInkDropStyle::FILL_BOUNDS, this,
+        T::GetInkDropCenterBasedOnLastEvent());
+  }
+
+  std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight()
+      const override {
+    return TrayPopupUtils::CreateInkDropHighlight(this);
+  }
+
+  void OnThemeChanged() override {
+    T::OnThemeChanged();
+    auto* color_provider = AshColorProvider::Get();
+    T::focus_ring()->SetColor(color_provider->GetControlsLayerColor(
+        AshColorProvider::ControlsLayerType::kFocusRingColor));
+    T::background()->SetNativeControlColor(GetBackgroundColor());
+  }
+
+  SkColor GetIconColor() {
+    return AshColorProvider::Get()->GetContentLayerColor(
+        AshColorProvider::ContentLayerType::kButtonIconColor);
+  }
+
+  SkColor GetBackgroundColor() {
+    return AshColorProvider::Get()->GetControlsLayerColor(
+        AshColorProvider::ControlsLayerType::kControlBackgroundColorInactive);
+  }
+};
+
+class LiveCaptionButton
+    : public UnifiedVolumeViewButton<views::ToggleImageButton> {
+ public:
+  explicit LiveCaptionButton(PressedCallback callback)
+      : UnifiedVolumeViewButton(std::move(callback)) {
+    DCHECK_EQ(GetDefaultSizeOfVectorIcon(vector_icons::kLiveCaptionOffIcon),
+              GetDefaultSizeOfVectorIcon(vector_icons::kLiveCaptionOnIcon));
+    int icon_size =
+        GetDefaultSizeOfVectorIcon(vector_icons::kLiveCaptionOnIcon);
+    SetBorder(
+        views::CreateEmptyBorder(gfx::Insets((kTrayItemSize - icon_size) / 2)));
+    SetImageHorizontalAlignment(ALIGN_CENTER);
+    SetImageVerticalAlignment(ALIGN_MIDDLE);
+
+    SetTooltipText(l10n_util::GetStringFUTF16(
+        IDS_ASH_STATUS_TRAY_LIVE_CAPTION_TOGGLE_TOOLTIP,
+        l10n_util::GetStringUTF16(
+            IDS_ASH_STATUS_TRAY_LIVE_CAPTION_DISABLED_STATE_TOOLTIP)));
+    SetToggledTooltipText(l10n_util::GetStringFUTF16(
+        IDS_ASH_STATUS_TRAY_LIVE_CAPTION_TOGGLE_TOOLTIP,
+        l10n_util::GetStringUTF16(
+            IDS_ASH_STATUS_TRAY_LIVE_CAPTION_ENABLED_STATE_TOOLTIP)));
+
+    SetToggledBackground(views::CreateRoundedRectBackground(
+        GetToggledBackgroundColor(), kTrayItemCornerRadius));
+  }
+
+  ~LiveCaptionButton() override = default;
+
+  const char* GetClassName() const override { return "LiveCaptionButton"; }
+
+  void OnThemeChanged() override {
+    UnifiedVolumeViewButton::OnThemeChanged();
+    const int icon_size =
+        GetDefaultSizeOfVectorIcon(vector_icons::kLiveCaptionOnIcon);
+    views::SetImageFromVectorIconWithColor(
+        this, vector_icons::kLiveCaptionOffIcon, icon_size, GetIconColor());
+    views::SetToggledImageFromVectorIconWithColor(
+        this, vector_icons::kLiveCaptionOnIcon, icon_size,
+        GetToggledIconColor(), GetToggledIconColor());
+    toggled_background()->SetNativeControlColor(GetToggledBackgroundColor());
+  }
+
+  SkColor GetToggledIconColor() {
+    return AshColorProvider::Get()->GetContentLayerColor(
+        AshColorProvider::ContentLayerType::kButtonIconColorPrimary);
+  }
+
+  SkColor GetToggledBackgroundColor() {
+    return AshColorProvider::Get()->GetControlsLayerColor(
+        AshColorProvider::ControlsLayerType::kControlBackgroundColorActive);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LiveCaptionButton);
+};
+
+class MoreButton : public UnifiedVolumeViewButton<views::Button> {
  public:
   explicit MoreButton(PressedCallback callback)
-      : views::Button(std::move(callback)) {
+      : UnifiedVolumeViewButton(std::move(callback)) {
     SetLayoutManager(std::make_unique<views::BoxLayout>(
         views::BoxLayout::Orientation::kHorizontal,
         gfx::Insets((kTrayItemSize -
@@ -76,38 +196,15 @@
     more_image_ = AddChildView(std::make_unique<views::ImageView>());
     more_image_->SetCanProcessEventsWithinSubtree(false);
     SetTooltipText(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_AUDIO));
-    TrayPopupUtils::ConfigureTrayPopupButton(this);
-
-    views::InstallRoundRectHighlightPathGenerator(this, gfx::Insets(),
-                                                  kTrayItemCornerRadius);
-    SetBackground(views::CreateRoundedRectBackground(
-        GetBackgroundColorOfMoreButton(), kTrayItemCornerRadius));
   }
 
   ~MoreButton() override = default;
 
-  std::unique_ptr<views::InkDrop> CreateInkDrop() override {
-    return TrayPopupUtils::CreateInkDrop(this);
-  }
-
-  std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override {
-    return TrayPopupUtils::CreateInkDropRipple(
-        TrayPopupInkDropStyle::FILL_BOUNDS, this,
-        GetInkDropCenterBasedOnLastEvent());
-  }
-
-  std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight()
-      const override {
-    return TrayPopupUtils::CreateInkDropHighlight(this);
-  }
-
   const char* GetClassName() const override { return "MoreButton"; }
 
   void OnThemeChanged() override {
-    views::Button::OnThemeChanged();
-    auto* color_provider = AshColorProvider::Get();
-    const SkColor icon_color = color_provider->GetContentLayerColor(
-        AshColorProvider::ContentLayerType::kIconColorPrimary);
+    UnifiedVolumeViewButton::OnThemeChanged();
+    const SkColor icon_color = GetIconColor();
     if (headset_image_) {
       headset_image_->SetImage(
           CreateVectorIcon(vector_icons::kHeadsetIcon, icon_color));
@@ -118,9 +215,6 @@
                              : SkBitmapOperations::ROTATION_90_CW;
     more_image_->SetImage(gfx::ImageSkiaOperations::CreateRotatedImage(
         CreateVectorIcon(kUnifiedMenuExpandIcon, icon_color), icon_rotation));
-    focus_ring()->SetColor(color_provider->GetControlsLayerColor(
-        AshColorProvider::ControlsLayerType::kFocusRingColor));
-    background()->SetNativeControlColor(GetBackgroundColorOfMoreButton());
   }
 
  private:
@@ -141,11 +235,15 @@
                         controller,
                         kSystemMenuVolumeHighIcon,
                         IDS_ASH_STATUS_TRAY_VOLUME_SLIDER_LABEL),
+      live_caption_button_(new LiveCaptionButton(
+          base::BindRepeating(&UnifiedVolumeView::OnLiveCaptionButtonPressed,
+                              base::Unretained(this)))),
       more_button_(new MoreButton(
           base::BindRepeating(&UnifiedVolumeSliderController::Delegate::
                                   OnAudioSettingsButtonClicked,
                               base::Unretained(delegate)))) {
   CrasAudioHandler::Get()->AddAudioObserver(this);
+  AddChildViewAt(live_caption_button_, 0);
   AddChildView(more_button_);
   Update(false /* by_user */);
 }
@@ -178,6 +276,12 @@
   button()->SetTooltipText(l10n_util::GetStringFUTF16(
       IDS_ASH_STATUS_TRAY_VOLUME, state_tooltip_text));
 
+  live_caption_button_->SetVisible(
+      base::FeatureList::IsEnabled(media::kLiveCaption));
+  live_caption_button_->SetToggled(
+      Shell::Get()->session_controller()->GetActivePrefService()->GetBoolean(
+          prefs::kLiveCaptionEnabled));
+
   more_button_->SetVisible(CrasAudioHandler::Get()->has_alternative_input() ||
                            CrasAudioHandler::Get()->has_alternative_output() ||
                            features::IsSystemTrayMicGainSettingEnabled());
@@ -220,4 +324,12 @@
   Layout();
 }
 
+void UnifiedVolumeView::OnLiveCaptionButtonPressed() {
+  PrefService* prefs =
+      Shell::Get()->session_controller()->GetActivePrefService();
+  bool enabled = !prefs->GetBoolean(prefs::kLiveCaptionEnabled);
+  prefs->SetBoolean(prefs::kLiveCaptionEnabled, enabled);
+  live_caption_button_->SetToggled(enabled);
+}
+
 }  // namespace ash
diff --git a/ash/system/audio/unified_volume_view.h b/ash/system/audio/unified_volume_view.h
index f19ce53..5ca0fed5 100644
--- a/ash/system/audio/unified_volume_view.h
+++ b/ash/system/audio/unified_volume_view.h
@@ -35,6 +35,10 @@
   // UnifiedSliderView:
   void ChildVisibilityChanged(views::View* child) override;
 
+  // views::Button::PressedCallback
+  void OnLiveCaptionButtonPressed();
+
+  views::ToggleImageButton* const live_caption_button_;
   views::Button* const more_button_;
 
   DISALLOW_COPY_AND_ASSIGN(UnifiedVolumeView);
diff --git a/ash/system/holding_space/holding_space_item_view.cc b/ash/system/holding_space/holding_space_item_view.cc
index f4098ca..bed6b9c 100644
--- a/ash/system/holding_space/holding_space_item_view.cc
+++ b/ash/system/holding_space/holding_space_item_view.cc
@@ -75,7 +75,7 @@
 HoldingSpaceItemView::HoldingSpaceItemView(
     HoldingSpaceItemViewDelegate* delegate,
     const HoldingSpaceItem* item)
-    : delegate_(delegate), item_(item) {
+    : delegate_(delegate), item_(item), item_id_(item->id()) {
   SetProperty(kIsHoldingSpaceItemViewProperty, true);
 
   set_context_menu_controller(delegate_);
diff --git a/ash/system/holding_space/holding_space_item_view.h b/ash/system/holding_space/holding_space_item_view.h
index edc51ad0..f61c97b 100644
--- a/ash/system/holding_space/holding_space_item_view.h
+++ b/ash/system/holding_space/holding_space_item_view.h
@@ -20,8 +20,10 @@
 class HoldingSpaceItem;
 class HoldingSpaceItemViewDelegate;
 
-// Base class for HoldingSpaceItemChipView and
-// HoldingSpaceItemScreenCaptureView.
+// Base class for `HoldingSpaceItemChipView` and
+// `HoldingSpaceItemScreenCaptureView`. Note that `HoldingSpaceItemView` may
+// temporarily outlive its associated `HoldingSpaceItem` when it is being
+// animated out.
 class ASH_EXPORT HoldingSpaceItemView : public views::InkDropHostView {
  public:
   METADATA_HEADER(HoldingSpaceItemView);
@@ -57,6 +59,7 @@
                  ui::mojom::DragEventSource source);
 
   const HoldingSpaceItem* item() const { return item_; }
+  const std::string& item_id() const { return item_id_; }
 
   void SetSelected(bool selected);
   bool selected() const { return selected_; }
@@ -73,7 +76,13 @@
 
   HoldingSpaceItemViewDelegate* const delegate_;
   const HoldingSpaceItem* const item_;
-  views::ToggleImageButton* pin_ = nullptr;
+
+  // Cache the id of the associated holding space item so that it can be
+  // accessed even after `item_` has been destroyed. Note that `item_` may be
+  // destroyed if this view is in the process of animating out.
+  const std::string item_id_;
+
+  views::ToggleImageButton* pin_ = nullptr;  // Owned by view hierarchy.
 
   // Owners for the layers used to paint focused and selected states.
   std::unique_ptr<ui::LayerOwner> selected_layer_owner_;
diff --git a/ash/system/holding_space/holding_space_item_view_delegate.cc b/ash/system/holding_space/holding_space_item_view_delegate.cc
index 7a20f1f..f770e4a 100644
--- a/ash/system/holding_space/holding_space_item_view_delegate.cc
+++ b/ash/system/holding_space/holding_space_item_view_delegate.cc
@@ -56,6 +56,20 @@
 
 }  // namespace
 
+// HoldingSpaceItemViewDelegate::ScopedSelectionRestore ------------------------
+
+HoldingSpaceItemViewDelegate::ScopedSelectionRestore::ScopedSelectionRestore(
+    HoldingSpaceItemViewDelegate* delegate)
+    : delegate_(delegate) {
+  for (const HoldingSpaceItemView* view : delegate_->GetSelection())
+    selected_item_ids_.push_back(view->item_id());
+}
+
+HoldingSpaceItemViewDelegate::ScopedSelectionRestore::
+    ~ScopedSelectionRestore() {
+  delegate_->SetSelection(selected_item_ids_);
+}
+
 // HoldingSpaceItemViewDelegate ------------------------------------------------
 
 HoldingSpaceItemViewDelegate::HoldingSpaceItemViewDelegate() {
@@ -391,4 +405,10 @@
     view->SetSelected(view == selection);
 }
 
+void HoldingSpaceItemViewDelegate::SetSelection(
+    const std::vector<std::string>& item_ids) {
+  for (HoldingSpaceItemView* view : views_)
+    view->SetSelected(base::Contains(item_ids, view->item_id()));
+}
+
 }  // namespace ash
diff --git a/ash/system/holding_space/holding_space_item_view_delegate.h b/ash/system/holding_space/holding_space_item_view_delegate.h
index 006f224..36d83f6 100644
--- a/ash/system/holding_space/holding_space_item_view_delegate.h
+++ b/ash/system/holding_space/holding_space_item_view_delegate.h
@@ -41,6 +41,20 @@
       public views::ViewObserver,
       public ui::SimpleMenuModel::Delegate {
  public:
+  // A class which caches the current selection of holding space item views on
+  // creation and restores that selection on destruction.
+  class ScopedSelectionRestore {
+   public:
+    explicit ScopedSelectionRestore(HoldingSpaceItemViewDelegate* delegate);
+    ScopedSelectionRestore(const ScopedSelectionRestore&) = delete;
+    ScopedSelectionRestore& operator=(const ScopedSelectionRestore&) = delete;
+    ~ScopedSelectionRestore();
+
+   private:
+    HoldingSpaceItemViewDelegate* const delegate_;
+    std::vector<std::string> selected_item_ids_;
+  };
+
   HoldingSpaceItemViewDelegate();
   HoldingSpaceItemViewDelegate(const HoldingSpaceItemViewDelegate&) = delete;
   HoldingSpaceItemViewDelegate& operator=(const HoldingSpaceItemViewDelegate&) =
@@ -103,6 +117,10 @@
   // Marks `view` as selected. All other `views_` are marked unselected.
   void SetSelection(views::View* view);
 
+  // Marks any `views_` whose associated holding space items are contained in
+  // `item_ids` as selected. All other `views_` are marked unselected.
+  void SetSelection(const std::vector<std::string>& item_ids);
+
   std::unique_ptr<ui::SimpleMenuModel> context_menu_model_;
   std::unique_ptr<views::MenuRunner> context_menu_runner_;
 
diff --git a/ash/system/holding_space/holding_space_item_views_container.cc b/ash/system/holding_space/holding_space_item_views_container.cc
index bdf1915b..351b0d67 100644
--- a/ash/system/holding_space/holding_space_item_views_container.cc
+++ b/ash/system/holding_space/holding_space_item_views_container.cc
@@ -5,11 +5,73 @@
 #include "ash/system/holding_space/holding_space_item_views_container.h"
 
 #include "ash/public/cpp/holding_space/holding_space_item.h"
+#include "ash/system/holding_space/holding_space_item_view.h"
+#include "ash/system/holding_space/holding_space_item_view_delegate.h"
+#include "ui/compositor/layer_animation_observer.h"
+#include "ui/compositor/scoped_layer_animation_settings.h"
 
 namespace ash {
 
-HoldingSpaceItemViewsContainer::HoldingSpaceItemViewsContainer() {
+namespace {
+
+using AnimatableProperty = ui::LayerAnimationElement::AnimatableProperty;
+
+// CallbackAnimationObserver ---------------------------------------------------
+
+// An implicit animation observer which invokes a `callback` on animation
+// completion. The `callback` will be notified whether the animation completed
+// due to abort or if the animation completed normally.
+class CallbackAnimationObserver : public ui::ImplicitAnimationObserver {
+ public:
+  using Callback = base::RepeatingCallback<void(bool aborted)>;
+
+  explicit CallbackAnimationObserver(Callback callback) : callback_(callback) {}
+  CallbackAnimationObserver(const CallbackAnimationObserver&) = delete;
+  CallbackAnimationObserver& operator=(const CallbackAnimationObserver&) =
+      delete;
+  ~CallbackAnimationObserver() override = default;
+
+ private:
+  // ui::ImplicitAnimationObserver:
+  void OnImplicitAnimationsCompleted() override {
+    bool aborted = false;
+    for (int i = AnimatableProperty::FIRST_PROPERTY;
+         i < AnimatableProperty::SENTINEL; ++i) {
+      const AnimatableProperty property = static_cast<AnimatableProperty>(i);
+      if (WasAnimationAbortedForProperty(property)) {
+        aborted = true;
+        break;
+      }
+    }
+    callback_.Run(aborted);
+  }
+
+  Callback callback_;
+};
+
+}  // namespace
+
+// HoldingSpaceItemViewsContainer ----------------------------------------------
+
+HoldingSpaceItemViewsContainer::HoldingSpaceItemViewsContainer(
+    HoldingSpaceItemViewDelegate* delegate)
+    : delegate_(delegate),
+      animate_in_observer_(
+          std::make_unique<CallbackAnimationObserver>(base::BindRepeating(
+              &HoldingSpaceItemViewsContainer::OnAnimateInCompleted,
+              base::Unretained(this)))),
+      animate_out_observer_(
+          std::make_unique<CallbackAnimationObserver>(base::BindRepeating(
+              &HoldingSpaceItemViewsContainer::OnAnimateOutCompleted,
+              base::Unretained(this)))) {
   controller_observer_.Add(HoldingSpaceController::Get());
+
+  // The holding space views container will attach `animate_in_observer_` and
+  // `animate_out_observer_` to a `ui::ScopedLayerAnimationSettings` associated
+  // with itself in order to determine when animations are completed. To do so,
+  // the holding space item views container must have a layer.
+  SetPaintToLayer();
+  layer()->SetFillsBoundsOpaquely(false);
 }
 
 HoldingSpaceItemViewsContainer::~HoldingSpaceItemViewsContainer() = default;
@@ -32,34 +94,121 @@
 void HoldingSpaceItemViewsContainer::OnHoldingSpaceModelAttached(
     HoldingSpaceModel* model) {
   model_observer_.Add(model);
-  for (const auto& item : model->items()) {
-    if (item->IsFinalized())
-      AddHoldingSpaceItemView(item.get(), /*due_to_finalization=*/false);
-  }
+  for (const auto& item : model->items())
+    OnHoldingSpaceItemAdded(item.get());
 }
 
 void HoldingSpaceItemViewsContainer::OnHoldingSpaceModelDetached(
     HoldingSpaceModel* model) {
   model_observer_.Remove(model);
-  RemoveAllHoldingSpaceItemViews();
+  if (ContainsHoldingSpaceItemViews())
+    MaybeAnimateOut();
 }
 
 void HoldingSpaceItemViewsContainer::OnHoldingSpaceItemAdded(
     const HoldingSpaceItem* item) {
   if (!item->IsFinalized())
     return;
-
-  AddHoldingSpaceItemView(item, /*due_to_finalization=*/false);
+  if (WillAddHoldingSpaceItemView(item))
+    MaybeAnimateOut();
 }
 
 void HoldingSpaceItemViewsContainer::OnHoldingSpaceItemRemoved(
     const HoldingSpaceItem* item) {
-  RemoveHoldingSpaceItemView(item);
+  if (ContainsHoldingSpaceItemView(item))
+    MaybeAnimateOut();
 }
 
 void HoldingSpaceItemViewsContainer::OnHoldingSpaceItemFinalized(
     const HoldingSpaceItem* item) {
-  AddHoldingSpaceItemView(item, /*due_to_finalization=*/true);
+  if (WillAddHoldingSpaceItemView(item))
+    MaybeAnimateOut();
+}
+
+void HoldingSpaceItemViewsContainer::MaybeAnimateIn() {
+  if (animation_state_ & AnimationState::kAnimatingIn)
+    return;
+
+  animation_state_ |= AnimationState::kAnimatingIn;
+
+  // In the event that the call to `AnimateIn()` did not result in an animation
+  // being scheduled, `OnAnimateInCompleted()` should still be called. To ensure
+  // this occurs, add the animation observer to a scoped settings doing nothing.
+  ui::ScopedLayerAnimationSettings animation_settings(layer()->GetAnimator());
+  animation_settings.AddObserver(animate_in_observer_.get());
+
+  AnimateIn(animate_in_observer_.get());
+}
+
+void HoldingSpaceItemViewsContainer::MaybeAnimateOut() {
+  if (animation_state_ & AnimationState::kAnimatingOut)
+    return;
+
+  animation_state_ |= AnimationState::kAnimatingOut;
+
+  // Don't allow event processing while animating out. The views being animated
+  // out may be associated with holding space items that no longer exist and
+  // so should not be acted upon by the user during this time.
+  SetCanProcessEventsWithinSubtree(false);
+
+  // In the event that the call to `AnimateOut()` did not result in an animation
+  // being scheduled, `OnAnimateOutCompleted()` should still be called. To
+  // ensure this occurs, add the animation observer to a scoped settings doing
+  // nothing.
+  ui::ScopedLayerAnimationSettings animation_settings(layer()->GetAnimator());
+  animation_settings.AddObserver(animate_out_observer_.get());
+
+  AnimateOut(animate_out_observer_.get());
+}
+
+void HoldingSpaceItemViewsContainer::OnAnimateInCompleted(bool aborted) {
+  DCHECK(animation_state_ & AnimationState::kAnimatingIn);
+  animation_state_ &= ~AnimationState::kAnimatingIn;
+
+  if (aborted)
+    return;
+
+  DCHECK_EQ(animation_state_, AnimationState::kNotAnimating);
+
+  // Restore event processing that was disabled while animating out. The views
+  // that have been animated in should all be associated with holding space
+  // items that exist in the model.
+  SetCanProcessEventsWithinSubtree(true);
+}
+
+void HoldingSpaceItemViewsContainer::OnAnimateOutCompleted(bool aborted) {
+  DCHECK(animation_state_ & AnimationState::kAnimatingOut);
+  animation_state_ &= ~AnimationState::kAnimatingOut;
+
+  if (aborted)
+    return;
+
+  DCHECK_EQ(animation_state_, AnimationState::kNotAnimating);
+
+  // All holding space item views are going to be removed after which views will
+  // be re-added for those items which still exist. A `ScopedSelectionRestore`
+  // will serve to persist the current selection during this modification.
+  HoldingSpaceItemViewDelegate::ScopedSelectionRestore scoped_selection_restore(
+      delegate_);
+
+  if (ContainsHoldingSpaceItemViews())
+    RemoveAllHoldingSpaceItemViews();
+
+  HoldingSpaceModel* model = HoldingSpaceController::Get()->model();
+  if (!model)
+    return;
+
+  bool is_empty = true;
+
+  for (const auto& item : model->items()) {
+    if (item->IsFinalized() && WillAddHoldingSpaceItemView(item.get())) {
+      AddHoldingSpaceItemView(item.get());
+      is_empty = false;
+    }
+  }
+
+  if (!is_empty)
+    MaybeAnimateIn();
 }
 
 }  // namespace ash
diff --git a/ash/system/holding_space/holding_space_item_views_container.h b/ash/system/holding_space/holding_space_item_views_container.h
index 5510e47..a32b0962 100644
--- a/ash/system/holding_space/holding_space_item_views_container.h
+++ b/ash/system/holding_space/holding_space_item_views_container.h
@@ -13,15 +13,20 @@
 #include "base/scoped_observer.h"
 #include "ui/views/view.h"
 
+namespace ui {
+class ImplicitAnimationObserver;
+}  // namespace ui
+
 namespace ash {
 
 class HoldingSpaceItem;
+class HoldingSpaceItemViewDelegate;
 
 class HoldingSpaceItemViewsContainer : public views::View,
                                        public HoldingSpaceControllerObserver,
                                        public HoldingSpaceModelObserver {
  public:
-  HoldingSpaceItemViewsContainer();
+  explicit HoldingSpaceItemViewsContainer(HoldingSpaceItemViewDelegate*);
   HoldingSpaceItemViewsContainer(const HoldingSpaceItemViewsContainer& other) =
       delete;
   HoldingSpaceItemViewsContainer& operator=(
@@ -33,11 +38,6 @@
   // items are created while the bubble widget is being asynchronously closed.
   void Reset();
 
-  virtual void AddHoldingSpaceItemView(const HoldingSpaceItem* item,
-                                       bool due_to_finalization) = 0;
-  virtual void RemoveAllHoldingSpaceItemViews() = 0;
-  virtual void RemoveHoldingSpaceItemView(const HoldingSpaceItem* item) = 0;
-
   // views::View:
   void ChildPreferredSizeChanged(views::View* child) override;
   void ChildVisibilityChanged(views::View* child) override;
@@ -51,7 +51,73 @@
   void OnHoldingSpaceItemRemoved(const HoldingSpaceItem* item) override;
   void OnHoldingSpaceItemFinalized(const HoldingSpaceItem* item) override;
 
+ protected:
+  // Returns whether a view for the specified `item` exists in this holding
+  // space item views container. Note that returning true will result in a call
+  // to `RemoveAllHoldingSpaceItemViews()` after which views for existing
+  // holding space items will be re-added via call to
+  // `AddHoldingSpaceItemView()`.
+  virtual bool ContainsHoldingSpaceItemView(const HoldingSpaceItem* item) = 0;
+
+  // Returns whether any views associated with holding space items exist which
+  // in this holding space item views container. Note that returning true will
+  // result in a call to `RemoveAllHoldingSpaceItemViews()`.
+  virtual bool ContainsHoldingSpaceItemViews() = 0;
+
+  // Returns whether a view for the specified `item` will be added to this
+  // holding space item views container. Note that `AddHoldingSpaceItemView()`
+  // will only be invoked if this method returns true for the given `item`.
+  virtual bool WillAddHoldingSpaceItemView(const HoldingSpaceItem* item) = 0;
+
+  // Invoked to add a view to this holding space item views container for the
+  // specified `item`.
+  virtual void AddHoldingSpaceItemView(const HoldingSpaceItem* item) = 0;
+
+  // Invoked to remove all views associated with holding space items from this
+  // holding space item views container.
+  virtual void RemoveAllHoldingSpaceItemViews() = 0;
+
+  // Invoked to initiate animate in of the contents of this holding space item
+  // views container. Any animations created must be associated with `observer`.
+  virtual void AnimateIn(ui::ImplicitAnimationObserver* observer) = 0;
+
+  // Invoked to initiate animate out of the contents of this holding space item
+  // views container. Any animations created must be associated with `observer`.
+  virtual void AnimateOut(ui::ImplicitAnimationObserver* observer) = 0;
+
+  HoldingSpaceItemViewDelegate* delegate() { return delegate_; }
+
  private:
+  enum AnimationState : uint32_t {
+    kNotAnimating = 0,
+    kAnimatingIn = 1 << 1,
+    kAnimatingOut = 1 << 2,
+  };
+
+  // Invoke to start animating in the contents of this holding space item views
+  // container. No-ops if animate in is already in progress.
+  void MaybeAnimateIn();
+
+  // Invoke to start animating out the contents of this holding space item views
+  // container. No-ops if animate out is already in progress.
+  void MaybeAnimateOut();
+
+  // Invoked when an animate in/out of the contents of this holding space item
+  // views container has been completed. If `aborted` is true, the animation
+  // completed due to abort, otherwise the animation completed normally.
+  void OnAnimateInCompleted(bool aborted);
+  void OnAnimateOutCompleted(bool aborted);
+
+  HoldingSpaceItemViewDelegate* const delegate_;
+
+  std::unique_ptr<ui::ImplicitAnimationObserver> animate_in_observer_;
+  std::unique_ptr<ui::ImplicitAnimationObserver> animate_out_observer_;
+
+  // Bit flag representation of current `AnimationState`. Note that it is
+  // briefly possible to be both `kAnimatingIn` and `kAnimatingOut` when one
+  // animation is preempting another.
+  uint32_t animation_state_ = AnimationState::kNotAnimating;
+
   ScopedObserver<HoldingSpaceController, HoldingSpaceControllerObserver>
       controller_observer_{this};
   ScopedObserver<HoldingSpaceModel, HoldingSpaceModelObserver> model_observer_{
diff --git a/ash/system/holding_space/pinned_files_container.cc b/ash/system/holding_space/pinned_files_container.cc
index 3b67ea6..9887ce2a 100644
--- a/ash/system/holding_space/pinned_files_container.cc
+++ b/ash/system/holding_space/pinned_files_container.cc
@@ -82,7 +82,7 @@
 
 PinnedFilesContainer::PinnedFilesContainer(
     HoldingSpaceItemViewDelegate* delegate)
-    : delegate_(delegate) {
+    : HoldingSpaceItemViewsContainer(delegate) {
   SetID(kHoldingSpacePinnedFilesContainerId);
 
   SetLayoutManager(std::make_unique<views::BoxLayout>(
@@ -151,31 +151,28 @@
   SetVisible(details.is_add);
 }
 
-void PinnedFilesContainer::AddHoldingSpaceItemView(const HoldingSpaceItem* item,
-                                                   bool due_to_finalization) {
-  DCHECK(!base::Contains(views_by_item_id_, item->id()));
+bool PinnedFilesContainer::ContainsHoldingSpaceItemView(
+    const HoldingSpaceItem* item) {
+  return base::Contains(views_by_item_id_, item->id());
+}
+
+bool PinnedFilesContainer::ContainsHoldingSpaceItemViews() {
+  return !views_by_item_id_.empty();
+}
+
+bool PinnedFilesContainer::WillAddHoldingSpaceItemView(
+    const HoldingSpaceItem* item) {
+  return item->type() == HoldingSpaceItem::Type::kPinnedFile;
+}
+
+void PinnedFilesContainer::AddHoldingSpaceItemView(
+    const HoldingSpaceItem* item) {
   DCHECK(item->IsFinalized());
-
-  if (item->type() != HoldingSpaceItem::Type::kPinnedFile)
-    return;
-
-  size_t index = 0;
-
-  if (due_to_finalization) {
-    // Find the position at which the view should be added.
-    for (const auto& candidate :
-         base::Reversed(HoldingSpaceController::Get()->model()->items())) {
-      if (candidate->id() == item->id())
-        break;
-      if (candidate->IsFinalized() &&
-          candidate->type() == HoldingSpaceItem::Type::kPinnedFile) {
-        ++index;
-      }
-    }
-  }
+  DCHECK_EQ(item->type(), HoldingSpaceItem::Type::kPinnedFile);
+  DCHECK(!base::Contains(views_by_item_id_, item->id()));
 
   views_by_item_id_[item->id()] = item_chips_container_->AddChildViewAt(
-      std::make_unique<HoldingSpaceItemChipView>(delegate_, item), index);
+      std::make_unique<HoldingSpaceItemChipView>(delegate(), item), 0);
 }
 
 void PinnedFilesContainer::RemoveAllHoldingSpaceItemViews() {
@@ -183,14 +180,14 @@
   item_chips_container_->RemoveAllChildViews(true);
 }
 
-void PinnedFilesContainer::RemoveHoldingSpaceItemView(
-    const HoldingSpaceItem* item) {
-  auto it = views_by_item_id_.find(item->id());
-  if (it == views_by_item_id_.end())
-    return;
+// TODO(dmblack): Implement.
+void PinnedFilesContainer::AnimateIn(ui::ImplicitAnimationObserver* observer) {
+  NOTIMPLEMENTED();
+}
 
-  item_chips_container_->RemoveChildViewT(it->second);
-  views_by_item_id_.erase(it->first);
+// TODO(dmblack): Implement.
+void PinnedFilesContainer::AnimateOut(ui::ImplicitAnimationObserver* observer) {
+  NOTIMPLEMENTED();
 }
 
 }  // namespace ash
diff --git a/ash/system/holding_space/pinned_files_container.h b/ash/system/holding_space/pinned_files_container.h
index 5f12183..828a489 100644
--- a/ash/system/holding_space/pinned_files_container.h
+++ b/ash/system/holding_space/pinned_files_container.h
@@ -16,7 +16,6 @@
 namespace ash {
 
 class HoldingSpaceItemChipsContainer;
-class HoldingSpaceItemViewDelegate;
 
 // Container for pinned files that the user adds to the holding space bubble.
 class PinnedFilesContainer : public HoldingSpaceItemViewsContainer {
@@ -28,14 +27,16 @@
 
   // HoldingSpaceItemViewsContainer:
   void ViewHierarchyChanged(const views::ViewHierarchyChangedDetails&) override;
-  void AddHoldingSpaceItemView(const HoldingSpaceItem* item,
-                               bool due_to_finalization) override;
+  bool ContainsHoldingSpaceItemView(const HoldingSpaceItem* item) override;
+  bool ContainsHoldingSpaceItemViews() override;
+  bool WillAddHoldingSpaceItemView(const HoldingSpaceItem* item) override;
+  void AddHoldingSpaceItemView(const HoldingSpaceItem* item) override;
   void RemoveAllHoldingSpaceItemViews() override;
-  void RemoveHoldingSpaceItemView(const HoldingSpaceItem* item) override;
+  void AnimateIn(ui::ImplicitAnimationObserver* observer) override;
+  void AnimateOut(ui::ImplicitAnimationObserver* observer) override;
 
  private:
-  HoldingSpaceItemViewDelegate* const delegate_;
-
+  // Owned by view hierarchy.
   views::Label* empty_prompt_label_ = nullptr;
   HoldingSpaceItemChipsContainer* item_chips_container_ = nullptr;
 
diff --git a/ash/system/holding_space/recent_files_container.cc b/ash/system/holding_space/recent_files_container.cc
index 417230d..fe0540d 100644
--- a/ash/system/holding_space/recent_files_container.cc
+++ b/ash/system/holding_space/recent_files_container.cc
@@ -61,15 +61,6 @@
          type == HoldingSpaceItem::Type::kScreenRecording;
 }
 
-// Returns if items of the specified types belong to the same section.
-bool BelongToSameSection(HoldingSpaceItem::Type type,
-                         HoldingSpaceItem::Type other_type) {
-  return (BelongsToScreenCaptureSection(type) &&
-          BelongsToScreenCaptureSection(other_type)) ||
-         (BelongsToDownloadsSection(type) &&
-          BelongsToDownloadsSection(other_type));
-}
-
 // DownloadsHeader--------------------------------------------------------------
 
 class DownloadsHeader : public views::Button {
@@ -114,7 +105,7 @@
 
 RecentFilesContainer::RecentFilesContainer(
     HoldingSpaceItemViewDelegate* delegate)
-    : delegate_(delegate) {
+    : HoldingSpaceItemViewsContainer(delegate) {
   SetID(kHoldingSpaceRecentFilesContainerId);
   SetVisible(false);
 
@@ -170,34 +161,31 @@
     OnDownloadsContainerViewHierarchyChanged(details);
 }
 
-void RecentFilesContainer::AddHoldingSpaceItemView(const HoldingSpaceItem* item,
-                                                   bool due_to_finalization) {
+bool RecentFilesContainer::ContainsHoldingSpaceItemView(
+    const HoldingSpaceItem* item) {
+  return base::Contains(views_by_item_id_, item->id());
+}
+
+bool RecentFilesContainer::ContainsHoldingSpaceItemViews() {
+  return !views_by_item_id_.empty();
+}
+
+bool RecentFilesContainer::WillAddHoldingSpaceItemView(
+    const HoldingSpaceItem* item) {
+  return BelongsToDownloadsSection(item->type()) ||
+         BelongsToScreenCaptureSection(item->type());
+}
+
+void RecentFilesContainer::AddHoldingSpaceItemView(
+    const HoldingSpaceItem* item) {
   DCHECK(item->IsFinalized());
 
-  if (!BelongsToScreenCaptureSection(item->type()) &&
-      !BelongsToDownloadsSection(item->type())) {
-    return;
-  }
-
-  size_t index = 0;
-
-  if (due_to_finalization) {
-    // Find the position at which the view should be added.
-    for (const auto& candidate :
-         base::Reversed(HoldingSpaceController::Get()->model()->items())) {
-      if (candidate->id() == item->id())
-        break;
-      if (candidate->IsFinalized() &&
-          BelongToSameSection(candidate->type(), item->type())) {
-        ++index;
-      }
-    }
-  }
-
   if (BelongsToScreenCaptureSection(item->type()))
-    AddHoldingSpaceScreenCaptureView(item, index);
+    AddHoldingSpaceScreenCaptureView(item);
   else if (BelongsToDownloadsSection(item->type()))
-    AddHoldingSpaceDownloadView(item, index);
+    AddHoldingSpaceDownloadView(item);
+  else
+    NOTREACHED();
 }
 
 void RecentFilesContainer::RemoveAllHoldingSpaceItemViews() {
@@ -206,23 +194,21 @@
   downloads_container_->RemoveAllChildViews(true);
 }
 
-void RecentFilesContainer::RemoveHoldingSpaceItemView(
-    const HoldingSpaceItem* item) {
-  if (BelongsToScreenCaptureSection(item->type()))
-    RemoveHoldingSpaceScreenCaptureView(item);
-  else if (BelongsToDownloadsSection(item->type()))
-    RemoveHoldingSpaceDownloadView(item);
+// TODO(dmblack): Implement.
+void RecentFilesContainer::AnimateIn(ui::ImplicitAnimationObserver* observer) {
+  NOTIMPLEMENTED();
+}
+
+// TODO(dmblack): Implement.
+void RecentFilesContainer::AnimateOut(ui::ImplicitAnimationObserver* observer) {
+  NOTIMPLEMENTED();
 }
 
 void RecentFilesContainer::AddHoldingSpaceScreenCaptureView(
-    const HoldingSpaceItem* item,
-    size_t index) {
+    const HoldingSpaceItem* item) {
   DCHECK(BelongsToScreenCaptureSection(item->type()));
   DCHECK(!base::Contains(views_by_item_id_, item->id()));
 
-  if (index >= kMaxScreenCaptures)
-    return;
-
   // Remove the last screen capture view if we are already at max capacity.
   if (screen_captures_container_->children().size() == kMaxScreenCaptures) {
     std::unique_ptr<views::View> view =
@@ -234,51 +220,14 @@
 
   // Add the screen capture view to the front in order to sort by recency.
   views_by_item_id_[item->id()] = screen_captures_container_->AddChildViewAt(
-      std::make_unique<HoldingSpaceItemScreenCaptureView>(delegate_, item),
-      index);
-}
-
-void RecentFilesContainer::RemoveHoldingSpaceScreenCaptureView(
-    const HoldingSpaceItem* item) {
-  DCHECK(BelongsToScreenCaptureSection(item->type()));
-
-  auto it = views_by_item_id_.find(item->id());
-  if (it == views_by_item_id_.end())
-    return;
-
-  // Remove the screen capture view associated with `item`.
-  screen_captures_container_->RemoveChildViewT(it->second);
-  views_by_item_id_.erase(it);
-
-  // Verify that we are *not* at max capacity.
-  DCHECK_LT(screen_captures_container_->children().size(), kMaxScreenCaptures);
-
-  // Since we are under max capacity, we can add at most one screen capture view
-  // to replace the view we just removed. Note that we add the replacement to
-  // the back in order to maintain sort by recency.
-  for (const auto& candidate :
-       base::Reversed(HoldingSpaceController::Get()->model()->items())) {
-    if (candidate->IsFinalized() &&
-        BelongsToScreenCaptureSection(item->type()) &&
-        !base::Contains(views_by_item_id_, candidate->id())) {
-      views_by_item_id_[candidate->id()] =
-          screen_captures_container_->AddChildView(
-              std::make_unique<HoldingSpaceItemScreenCaptureView>(
-                  delegate_, candidate.get()));
-      return;
-    }
-  }
+      std::make_unique<HoldingSpaceItemScreenCaptureView>(delegate(), item), 0);
 }
 
 void RecentFilesContainer::AddHoldingSpaceDownloadView(
-    const HoldingSpaceItem* item,
-    size_t index) {
+    const HoldingSpaceItem* item) {
   DCHECK(BelongsToDownloadsSection(item->type()));
   DCHECK(!base::Contains(views_by_item_id_, item->id()));
 
-  if (index >= kMaxDownloads)
-    return;
-
   // Remove the last download view if we are already at max capacity.
   if (downloads_container_->children().size() == kMaxDownloads) {
     std::unique_ptr<views::View> view = downloads_container_->RemoveChildViewT(
@@ -289,37 +238,7 @@
 
   // Add the download view to the front in order to sort by recency.
   views_by_item_id_[item->id()] = downloads_container_->AddChildViewAt(
-      std::make_unique<HoldingSpaceItemChipView>(delegate_, item), index);
-}
-
-void RecentFilesContainer::RemoveHoldingSpaceDownloadView(
-    const HoldingSpaceItem* item) {
-  DCHECK(BelongsToDownloadsSection(item->type()));
-
-  auto it = views_by_item_id_.find(item->id());
-  if (it == views_by_item_id_.end())
-    return;
-
-  // Remove the download view associated with `item`.
-  downloads_container_->RemoveChildViewT(it->second);
-  views_by_item_id_.erase(it);
-
-  // Verify that we are *not* at max capacity.
-  DCHECK_LT(downloads_container_->children().size(), kMaxDownloads);
-
-  // Since we are under max capacity, we can add at most one download view to
-  // replace the view we just removed. Note that we add the replacement to the
-  // back in order to maintain sort by recency.
-  for (const auto& candidate :
-       base::Reversed(HoldingSpaceController::Get()->model()->items())) {
-    if (candidate->IsFinalized() && BelongsToDownloadsSection(item->type()) &&
-        !base::Contains(views_by_item_id_, candidate->id())) {
-      views_by_item_id_[candidate->id()] = downloads_container_->AddChildView(
-          std::make_unique<HoldingSpaceItemChipView>(delegate_,
-                                                     candidate.get()));
-      return;
-    }
-  }
+      std::make_unique<HoldingSpaceItemChipView>(delegate(), item), 0);
 }
 
 void RecentFilesContainer::OnScreenCapturesContainerViewHierarchyChanged(
diff --git a/ash/system/holding_space/recent_files_container.h b/ash/system/holding_space/recent_files_container.h
index 7f94ea67..dde4c0af 100644
--- a/ash/system/holding_space/recent_files_container.h
+++ b/ash/system/holding_space/recent_files_container.h
@@ -16,7 +16,6 @@
 namespace ash {
 
 class HoldingSpaceItemChipsContainer;
-class HoldingSpaceItemViewDelegate;
 
 // Container for the recent files (e.g. screen captures, downloads, etc).
 class RecentFilesContainer : public HoldingSpaceItemViewsContainer {
@@ -29,24 +28,23 @@
   // HoldingSpaceItemViewsContainer:
   void ChildVisibilityChanged(views::View* child) override;
   void ViewHierarchyChanged(const views::ViewHierarchyChangedDetails&) override;
-  void AddHoldingSpaceItemView(const HoldingSpaceItem* item,
-                               bool due_to_finalization) override;
+  bool ContainsHoldingSpaceItemView(const HoldingSpaceItem* item) override;
+  bool ContainsHoldingSpaceItemViews() override;
+  bool WillAddHoldingSpaceItemView(const HoldingSpaceItem* item) override;
+  void AddHoldingSpaceItemView(const HoldingSpaceItem* item) override;
   void RemoveAllHoldingSpaceItemViews() override;
-  void RemoveHoldingSpaceItemView(const HoldingSpaceItem* item) override;
+  void AnimateIn(ui::ImplicitAnimationObserver* observer) override;
+  void AnimateOut(ui::ImplicitAnimationObserver* observer) override;
 
  private:
-  void AddHoldingSpaceScreenCaptureView(const HoldingSpaceItem* item,
-                                        size_t index);
-  void RemoveHoldingSpaceScreenCaptureView(const HoldingSpaceItem* item);
-  void AddHoldingSpaceDownloadView(const HoldingSpaceItem* item, size_t index);
-  void RemoveHoldingSpaceDownloadView(const HoldingSpaceItem* item);
+  void AddHoldingSpaceScreenCaptureView(const HoldingSpaceItem* item);
+  void AddHoldingSpaceDownloadView(const HoldingSpaceItem* item);
   void OnScreenCapturesContainerViewHierarchyChanged(
       const views::ViewHierarchyChangedDetails& details);
   void OnDownloadsContainerViewHierarchyChanged(
       const views::ViewHierarchyChangedDetails& details);
 
-  HoldingSpaceItemViewDelegate* const delegate_;
-
+  // Owned by view hierarchy.
   views::View* screen_captures_container_ = nullptr;
   views::Label* screen_captures_label_ = nullptr;
   HoldingSpaceItemChipsContainer* downloads_container_ = nullptr;
diff --git a/base/allocator/partition_allocator/page_allocator_internals_posix.h b/base/allocator/partition_allocator/page_allocator_internals_posix.h
index 2a784d3..503fa7dd 100644
--- a/base/allocator/partition_allocator/page_allocator_internals_posix.h
+++ b/base/allocator/partition_allocator/page_allocator_internals_posix.h
@@ -247,14 +247,20 @@
     void* address,
     size_t length,
     PageAccessibilityDisposition accessibility_disposition) {
-  if (accessibility_disposition == PageUpdatePermissions) {
-    SetSystemPagesAccess(address, length, PageInaccessible);
-  }
-
   // In POSIX, there is no decommit concept. Discarding is an effective way of
   // implementing the Windows semantics where the OS is allowed to not swap the
   // pages in the region.
   DiscardSystemPages(address, length);
+
+  // Make pages inaccessible, unless the caller requested to keep permissions.
+  //
+  // Note, there is a small window between these calls when the pages can be
+  // incorrectly touched and brought back to memory. Not ideal, but doing those
+  // operaions in the opposite order resulted in PMF regression on Mac (see
+  // crbug.com/1153021).
+  if (accessibility_disposition == PageUpdatePermissions) {
+    SetSystemPagesAccess(address, length, PageInaccessible);
+  }
 }
 
 void RecommitSystemPagesInternal(
@@ -262,12 +268,6 @@
     size_t length,
     PageAccessibilityConfiguration accessibility,
     PageAccessibilityDisposition accessibility_disposition) {
-#if defined(OS_APPLE)
-  // On macOS, to update accounting, we need to make another syscall. For more
-  // details, see https://crbug.com/823915.
-  madvise(address, length, MADV_FREE_REUSE);
-#endif
-
   // On POSIX systems, the caller need simply read the memory to recommit it.
   // This has the correct behavior because the API requires the permissions to
   // be the same as before decommitting and all configurations can read.
@@ -276,6 +276,12 @@
   if (accessibility_disposition == PageUpdatePermissions) {
     SetSystemPagesAccess(address, length, accessibility);
   }
+
+#if defined(OS_APPLE)
+  // On macOS, to update accounting, we need to make another syscall. For more
+  // details, see https://crbug.com/823915.
+  madvise(address, length, MADV_FREE_REUSE);
+#endif
 }
 
 void DiscardSystemPagesInternal(void* address, size_t length) {
diff --git a/base/allocator/partition_allocator/partition_alloc_unittest.cc b/base/allocator/partition_allocator/partition_alloc_unittest.cc
index 1c15ce3..8bfad3543 100644
--- a/base/allocator/partition_allocator/partition_alloc_unittest.cc
+++ b/base/allocator/partition_allocator/partition_alloc_unittest.cc
@@ -1432,7 +1432,12 @@
       allocator.root()->AdjustPointerForExtrasSubtract(ptr));
   EXPECT_EQ(nullptr, bucket->empty_slot_spans_head);
   EXPECT_EQ(1, slot_span->num_allocated_slots);
+#if defined(OS_WIN)
+  // Windows uses lazy commit, thus committing only needed pages.
   size_t expected_committed_size = SystemPageSize();
+#else
+  size_t expected_committed_size = PartitionPageSize();
+#endif
   EXPECT_EQ(expected_committed_size,
             allocator.root()->get_total_size_of_committed_pages());
   allocator.root()->Free(ptr);
@@ -1446,7 +1451,15 @@
   EXPECT_FALSE(slot_span->freelist_head);
   EXPECT_EQ(-1, slot_span->empty_cache_index);
   EXPECT_EQ(0, slot_span->num_allocated_slots);
+#if defined(OS_WIN)
   size_t expected_size = SystemPageSize();
+#else
+  PartitionBucket<base::internal::ThreadSafe>* cycle_free_cache_bucket =
+      &allocator.root()->buckets[test_bucket_index_];
+  size_t expected_size =
+      cycle_free_cache_bucket->num_system_pages_per_slot_span *
+      SystemPageSize();
+#endif
   EXPECT_EQ(expected_size,
             allocator.root()->get_total_size_of_committed_pages());
 
@@ -2565,7 +2578,12 @@
 
   // A full slot span of size 1 partition page is committed.
   void* ptr = root.Alloc(small_size - kExtraAllocSize, type_name);
+#if defined(OS_WIN)
+  // Windows uses lazy commit, thus committing only needed pages.
   size_t expected_committed_size = SystemPageSize();
+#else
+  size_t expected_committed_size = PartitionPageSize();
+#endif
   size_t expected_super_pages_size = kSuperPageSize;
   EXPECT_EQ(expected_committed_size, root.total_size_of_committed_pages);
   EXPECT_EQ(expected_super_pages_size, root.total_size_of_super_pages);
@@ -2587,7 +2605,11 @@
 
   // Allocating another size commits another slot span.
   ptr = root.Alloc(2 * small_size - kExtraAllocSize, type_name);
+#if defined(OS_WIN)
   expected_committed_size += SystemPageSize();
+#else
+  expected_committed_size += PartitionPageSize();
+#endif
   EXPECT_EQ(expected_committed_size, root.total_size_of_committed_pages);
   EXPECT_EQ(expected_super_pages_size, root.total_size_of_super_pages);
 
diff --git a/base/allocator/partition_allocator/partition_bucket.cc b/base/allocator/partition_allocator/partition_bucket.cc
index f8ef416..4d34540 100644
--- a/base/allocator/partition_allocator/partition_bucket.cc
+++ b/base/allocator/partition_allocator/partition_bucket.cc
@@ -217,6 +217,14 @@
 
   char* ret = root->next_partition_page;
   root->next_partition_page += slot_span_reserved_size;
+#if !defined(OS_WIN)
+  // System pages in the super page come in a decommited state. Commit them
+  // before vending them back.
+  // Windows uses lazy commit. Pages will be committed when provisioning slots,
+  // in ProvisionMoreSlotsAndAllocOne().
+  root->RecommitSystemPagesForData(ret, slot_span_committed_size,
+                                   PageUpdatePermissions);
+#endif
   // Double check that we had enough space in the super page for the new slot
   // span.
   PA_DCHECK(root->next_partition_page <= root->next_partition_page_end);
@@ -379,11 +387,15 @@
   // to the page start and |next_slot| doesn't, thus only the latter gets
   // rounded up.
   PA_DCHECK(commit_end > commit_start);
-  // System pages in the slot span come in an initially decommitted state.
-  // Can't use PageKeepPermissionsIfPossible, because we have no knowledge
-  // which pages have been committed before.
+#if defined(OS_WIN)
+  // Windows uses lazy commit, meaning system pages in the slot span come in an
+  // initially decommitted state. Commit them here.
+  // Note, we can't use PageKeepPermissionsIfPossible, because we have no
+  // knowledge which pages have been committed before (it doesn't matter on
+  // Windows anyway).
   root->RecommitSystemPagesForData(commit_start, commit_end - commit_start,
                                    PageUpdatePermissions);
+#endif
 
   // The slot being returned is considered allocated, and no longer
   // unprovisioned.
@@ -560,6 +572,14 @@
       PA_DCHECK(new_slot_span->bucket == this);
       PA_DCHECK(new_slot_span->is_decommitted());
       decommitted_slot_spans_head = new_slot_span->next_slot_span;
+#if !defined(OS_WIN)
+      // Windows uses lazy commit. Pages will be recommitted when provisioning
+      // slots, in ProvisionMoreSlotsAndAllocOne().
+      void* addr = SlotSpanMetadata<thread_safe>::ToPointer(new_slot_span);
+      root->RecommitSystemPagesForData(
+          addr, new_slot_span->bucket->get_bytes_per_span(),
+          PageKeepPermissionsIfPossible);
+#endif
       new_slot_span->Reset();
       *is_already_zeroed = kDecommittedPagesAreAlwaysZeroed;
     }
diff --git a/base/allocator/partition_allocator/partition_bucket.h b/base/allocator/partition_allocator/partition_bucket.h
index a4c860f..c8d6e5b 100644
--- a/base/allocator/partition_allocator/partition_bucket.h
+++ b/base/allocator/partition_allocator/partition_bucket.h
@@ -64,6 +64,21 @@
                                            bool* is_already_zeroed)
       EXCLUSIVE_LOCKS_REQUIRED(root->lock_);
 
+  ALWAYS_INLINE bool CanStoreRawSize() const {
+    // For direct-map as well as single-slot slot spans (recognized by checking
+    // against |MaxSystemPagesPerSlotSpan()|), we have some spare metadata
+    // space in subsequent PartitionPage to store the raw size. It isn't only
+    // metadata space though, slot spans that have more than one slot can't have
+    // raw size stored, because we wouldn't know which slot it applies to.
+    if (LIKELY(slot_size <= MaxSystemPagesPerSlotSpan() * SystemPageSize()))
+      return false;
+
+    PA_DCHECK((slot_size % SystemPageSize()) == 0);
+    PA_DCHECK(is_direct_mapped() || get_slots_per_span() == 1);
+
+    return true;
+  }
+
   ALWAYS_INLINE bool is_direct_mapped() const {
     return !num_system_pages_per_slot_span;
   }
diff --git a/base/allocator/partition_allocator/partition_page.cc b/base/allocator/partition_allocator/partition_page.cc
index 2f93665..5131e6f 100644
--- a/base/allocator/partition_allocator/partition_page.cc
+++ b/base/allocator/partition_allocator/partition_page.cc
@@ -169,7 +169,13 @@
   PA_DCHECK(is_empty());
   PA_DCHECK(!bucket->is_direct_mapped());
   void* addr = SlotSpanMetadata::ToPointer(this);
-  size_t size_to_decommit = bits::Align(GetProvisionedSize(), SystemPageSize());
+  size_t size_to_decommit =
+#if defined(OS_WIN)
+      // Windows uses lazy commit, thus only provisioned slots are committed.
+      bits::Align(GetProvisionedSize(), SystemPageSize());
+#else
+      bucket->get_bytes_per_span();
+#endif
   // Not decommitted slot span must've had at least 1 allocation.
   PA_DCHECK(size_to_decommit > 0);
   root->DecommitSystemPagesForData(addr, size_to_decommit,
diff --git a/base/allocator/partition_allocator/partition_page.h b/base/allocator/partition_allocator/partition_page.h
index d3a6938..1c776dd 100644
--- a/base/allocator/partition_allocator/partition_page.h
+++ b/base/allocator/partition_allocator/partition_page.h
@@ -404,19 +404,9 @@
 
 template <bool thread_safe>
 ALWAYS_INLINE bool SlotSpanMetadata<thread_safe>::CanStoreRawSize() const {
-  // For direct-map as well as single-slot slot spans (recognized by checking
-  // against |kMaxPartitionPagesPerSlotSpan|), we have some spare metadata space
-  // in subsequent PartitionPage to store the raw size. It isn't only metadata
-  // space though, slot spans that have more than one slot can't have raw size
-  // stored, because we wouldn't know which slot it applies to.
-  if (LIKELY(bucket->slot_size <=
-             MaxSystemPagesPerSlotSpan() * SystemPageSize()))
-    return false;
-
-  PA_DCHECK((bucket->slot_size % SystemPageSize()) == 0);
-  PA_DCHECK(bucket->is_direct_mapped() || bucket->get_slots_per_span() == 1);
-
-  return true;
+  // The answer is the same for all slot spans in a bucket, because it's based
+  // on the slot size.
+  return bucket->CanStoreRawSize();
 }
 
 template <bool thread_safe>
diff --git a/base/allocator/partition_allocator/partition_root.h b/base/allocator/partition_allocator/partition_root.h
index 7ff1299..f7f2552 100644
--- a/base/allocator/partition_allocator/partition_root.h
+++ b/base/allocator/partition_allocator/partition_root.h
@@ -629,16 +629,16 @@
     size_t raw_size,
     size_t* utilized_slot_size,
     bool* is_already_zeroed) {
-  *is_already_zeroed = false;
-
   SlotSpan* slot_span = bucket->active_slot_spans_head;
   // Check that this slot span is neither full nor freed.
   PA_DCHECK(slot_span);
   PA_DCHECK(slot_span->num_allocated_slots >= 0);
-  *utilized_slot_size = bucket->slot_size;
 
   void* ret = slot_span->freelist_head;
   if (LIKELY(ret)) {
+    *is_already_zeroed = false;
+    *utilized_slot_size = bucket->slot_size;
+
     // If these DCHECKs fire, you probably corrupted memory. TODO(palmer): See
     // if we can afford to make these CHECKs.
     PA_DCHECK(IsValidSlotSpan(slot_span));
@@ -646,6 +646,7 @@
     // All large allocations must go through the slow path to correctly update
     // the size metadata.
     PA_DCHECK(!slot_span->CanStoreRawSize());
+    PA_DCHECK(!slot_span->bucket->is_direct_mapped());
     internal::PartitionFreelistEntry* new_head =
         slot_span->freelist_head->GetNext();
     slot_span->SetFreelistHead(new_head);
@@ -1026,9 +1027,6 @@
       tcache = internal::ThreadCache::Create(this);
       with_thread_cache = true;
     }
-    // bucket->slot_size is 0 for direct-mapped allocations, as their bucket is
-    // the sentinel one. Since |bucket_index| is going to be kNumBuckets + 1,
-    // the thread cache allocation will return nullptr.
     ret = tcache->GetFromCache(bucket_index);
     is_already_zeroed = false;
     utilized_slot_size = bucket_at(bucket_index).slot_size;
@@ -1038,18 +1036,20 @@
     // for a non-thread cache allocation.
     if (ret) {
       SlotSpan* slot_span = SlotSpan::FromPointerNoAlignmentCheck(ret);
+      PA_DCHECK(IsValidSlotSpan(slot_span));
+      PA_DCHECK(slot_span->bucket == &bucket_at(bucket_index));
       // All large allocations must go through the RawAlloc path to correctly
       // set |utilized_slot_size|.
       PA_DCHECK(!slot_span->CanStoreRawSize());
-      PA_DCHECK(IsValidSlotSpan(slot_span));
-      PA_DCHECK(slot_span->bucket == &bucket_at(bucket_index));
+      PA_DCHECK(!slot_span->bucket->is_direct_mapped());
     }
 #endif
   }
 
-  if (!ret)
+  if (!ret) {
     ret = RawAlloc(buckets + bucket_index, flags, raw_size, &utilized_slot_size,
                    &is_already_zeroed);
+  }
 
   if (UNLIKELY(!ret))
     return nullptr;
diff --git a/base/allocator/partition_allocator/thread_cache.cc b/base/allocator/partition_allocator/thread_cache.cc
index 42b0f7e..6203471 100644
--- a/base/allocator/partition_allocator/thread_cache.cc
+++ b/base/allocator/partition_allocator/thread_cache.cc
@@ -9,6 +9,8 @@
 #include <vector>
 
 #include "base/allocator/partition_allocator/partition_alloc.h"
+#include "base/allocator/partition_allocator/partition_alloc_check.h"
+#include "base/threading/thread_task_runner_handle.h"
 
 namespace base {
 
@@ -29,6 +31,8 @@
 
 }  // namespace
 
+constexpr base::TimeDelta ThreadCacheRegistry::kPurgeInterval;
+
 // static
 ThreadCacheRegistry& ThreadCacheRegistry::Instance() {
   return g_instance;
@@ -101,6 +105,74 @@
     current_thread_tcache->Purge();
 }
 
+void ThreadCacheRegistry::StartPeriodicPurge() {
+  PostDelayedPurgeTask();
+}
+
+void ThreadCacheRegistry::PostDelayedPurgeTask() {
+  PA_DCHECK(!has_pending_purge_task_);
+  ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE,
+      base::BindOnce(&ThreadCacheRegistry::PeriodicPurge,
+                     base::Unretained(this)),
+      kPurgeInterval);
+  has_pending_purge_task_ = true;
+}
+
+void ThreadCacheRegistry::PeriodicPurge() {
+  has_pending_purge_task_ = false;
+  ThreadCache* tcache = ThreadCache::Get();
+  PA_DCHECK(tcache);
+  uint64_t allocations = tcache->stats_.alloc_count;
+  uint64_t allocations_since_last_purge =
+      allocations - allocations_at_last_purge_;
+
+  // Purge should not run when there is little activity in the process. We
+  // assume that the main thread is a reasonable proxy for the process activity,
+  // where the main thread is the current one.
+  //
+  // If we didn't see enough allocations since the last purge, don't schedule a
+  // new one, and ask the thread cache to notify us of deallocations. This makes
+  // the next |kMinMainThreadAllocationsForPurging| deallocations slightly
+  // slower.
+  //
+  // Once the threshold is reached, reschedule a purge task. We count
+  // deallocations rather than allocations because these are the ones that fill
+  // the cache, and also because we already have a check on the deallocation
+  // path, not on the allocation one that we don't want to slow down.
+  bool enough_allocations =
+      allocations_since_last_purge >= kMinMainThreadAllocationsForPurging;
+  tcache->SetNotifiesRegistry(!enough_allocations);
+  deallocations_ = 0;
+  PurgeAll();
+
+  if (enough_allocations) {
+    allocations_at_last_purge_ = allocations;
+    PostDelayedPurgeTask();
+  }
+}
+
+void ThreadCacheRegistry::OnDeallocation() {
+  deallocations_++;
+  if (deallocations_ > kMinMainThreadAllocationsForPurging) {
+    ThreadCache* tcache = ThreadCache::Get();
+    PA_DCHECK(tcache);
+
+    deallocations_ = 0;
+    tcache->SetNotifiesRegistry(false);
+
+    if (has_pending_purge_task_)
+      return;
+
+    // This is called from the thread cache, which is called from the central
+    // allocator. This means that any allocation made by task posting will make
+    // it reentrant, unless we disable the thread cache.
+    tcache->Disable();
+    PostDelayedPurgeTask();
+    tcache->Enable();
+  }
+}
+
 // static
 void ThreadCache::Init(PartitionRoot<ThreadSafe>* root) {
   PA_CHECK(root->buckets[kBucketCount - 1].slot_size == kSizeThreshold);
@@ -146,8 +218,13 @@
 }
 
 ThreadCache::ThreadCache(PartitionRoot<ThreadSafe>* root)
-    : buckets_(), stats_(), root_(root), next_(nullptr), prev_(nullptr) {
-  ThreadCacheRegistry::Instance().RegisterThreadCache(this);
+    : buckets_(),
+      stats_(),
+      root_(root),
+      registry_(&ThreadCacheRegistry::Instance()),
+      next_(nullptr),
+      prev_(nullptr) {
+  registry_->RegisterThreadCache(this);
 
   for (int index = 0; index < kBucketCount; index++) {
     const auto& root_bucket = root->buckets[index];
@@ -169,7 +246,7 @@
 }
 
 ThreadCache::~ThreadCache() {
-  ThreadCacheRegistry::Instance().UnregisterThreadCache(this);
+  registry_->UnregisterThreadCache(this);
   Purge();
 }
 
@@ -215,6 +292,9 @@
   size_t utilized_slot_size;
   bool is_already_zeroed;
 
+  PA_DCHECK(!root_->buckets[bucket_index].CanStoreRawSize());
+  PA_DCHECK(!root_->buckets[bucket_index].is_direct_mapped());
+
   // Same as calling RawAlloc() |count| times, but acquires the lock only once.
   internal::ScopedGuard<internal::ThreadSafe> guard(root_->lock_);
   for (int i = 0; i < count; i++) {
@@ -257,6 +337,22 @@
   PA_DCHECK(bucket.count == limit);
 }
 
+void ThreadCache::HandleNonNormalMode() {
+  switch (mode_.load(std::memory_order_relaxed)) {
+    case Mode::kPurge:
+      PurgeInternal();
+      mode_.store(Mode::kNormal, std::memory_order_relaxed);
+      break;
+
+    case Mode::kNotifyRegistry:
+      registry_->OnDeallocation();
+      break;
+
+    default:
+      break;
+  }
+}
+
 void ThreadCache::AccumulateStats(ThreadCacheStats* stats) const {
   stats->alloc_count += stats_.alloc_count;
   stats->alloc_hits += stats_.alloc_hits;
@@ -277,9 +373,22 @@
 }
 
 void ThreadCache::SetShouldPurge() {
+  // Purge may be triggered by an external event, in which case it should not
+  // take precedence over the notification mode, otherwise we risk disabling
+  // periodic purge entirely.
+  //
+  // Also, no other thread can set this to notification mode.
+  if (mode_.load(std::memory_order_relaxed) != Mode::kNormal)
+    return;
+
   // We don't need any synchronization, and don't really care if the purge is
   // carried out "right away", hence relaxed atomics.
-  should_purge_.store(true, std::memory_order_relaxed);
+  mode_.store(Mode::kPurge, std::memory_order_relaxed);
+}
+
+void ThreadCache::SetNotifiesRegistry(bool enabled) {
+  mode_.store(enabled ? Mode::kNotifyRegistry : Mode::kNormal,
+              std::memory_order_relaxed);
 }
 
 void ThreadCache::Purge() {
@@ -290,8 +399,14 @@
 void ThreadCache::PurgeInternal() {
   for (auto& bucket : buckets_)
     ClearBucket(bucket, 0);
+}
 
-  should_purge_.store(false, std::memory_order_relaxed);
+void ThreadCache::Disable() {
+  root_->with_thread_cache = false;
+}
+
+void ThreadCache::Enable() {
+  root_->with_thread_cache = true;
 }
 
 }  // namespace internal
diff --git a/base/allocator/partition_allocator/thread_cache.h b/base/allocator/partition_allocator/thread_cache.h
index 48cbaec..3fc29c9 100644
--- a/base/allocator/partition_allocator/thread_cache.h
+++ b/base/allocator/partition_allocator/thread_cache.h
@@ -19,6 +19,7 @@
 #include "base/macros.h"
 #include "base/no_destructor.h"
 #include "base/partition_alloc_buildflags.h"
+#include "base/sequenced_task_runner.h"
 #include "base/synchronization/lock.h"
 
 // Need TLS support.
@@ -65,13 +66,27 @@
   // a later point (during a deallocation).
   void PurgeAll();
 
+  // Starts a periodic timer on the current thread to purge all thread caches.
+  void StartPeriodicPurge();
+  void OnDeallocation();
+
   static PartitionLock& GetLock() { return Instance().lock_; }
 
+  bool has_pending_purge_task() const { return has_pending_purge_task_; }
+
+  static constexpr TimeDelta kPurgeInterval = TimeDelta::FromSeconds(1);
+  static constexpr int kMinMainThreadAllocationsForPurging = 1000;
+
  private:
+  void PeriodicPurge();
+  void PostDelayedPurgeTask();
   friend class NoDestructor<ThreadCacheRegistry>;
   // Not using base::Lock as the object's constructor must be constexpr.
   PartitionLock lock_;
   ThreadCache* list_head_ GUARDED_BY(GetLock()) = nullptr;
+  uint64_t allocations_at_last_purge_ = 0;
+  int deallocations_ = 0;
+  bool has_pending_purge_task_ = false;
 };
 
 constexpr ThreadCacheRegistry::ThreadCacheRegistry() = default;
@@ -175,12 +190,17 @@
   // Asks this cache to trigger |Purge()| at a later point. Can be called from
   // any thread.
   void SetShouldPurge();
+  void SetNotifiesRegistry(bool enabled);
   // Empties the cache.
   // The Partition lock must *not* be held when calling this.
   // Must be called from the thread this cache is for.
   void Purge();
   void AccumulateStats(ThreadCacheStats* stats) const;
 
+  // Disables the thread cache for its associated root.
+  void Disable();
+  void Enable();
+
   size_t bucket_count_for_testing(size_t index) const {
     return buckets_[index].count;
   }
@@ -194,6 +214,7 @@
     uint16_t count;
     uint16_t limit;
   };
+  enum class Mode { kNormal, kPurge, kNotifyRegistry };
 
   explicit ThreadCache(PartitionRoot<ThreadSafe>* root);
   static void Delete(void* thread_cache_ptr);
@@ -203,6 +224,7 @@
   // Empties the |bucket| until there are at most |limit| objects in it.
   void ClearBucket(Bucket& bucket, size_t limit);
   ALWAYS_INLINE void PutInBucket(Bucket& bucket, void* ptr);
+  void HandleNonNormalMode();
 
   // TODO(lizeb): Optimize the threshold.
   static constexpr size_t kSizeThreshold = 512;
@@ -214,10 +236,11 @@
       kBucketCount < kNumBuckets,
       "Cannot have more cached buckets than what the allocator supports");
 
-  std::atomic<bool> should_purge_{false};
+  std::atomic<Mode> mode_{Mode::kNormal};
   Bucket buckets_[kBucketCount];
   ThreadCacheStats stats_;
   PartitionRoot<ThreadSafe>* const root_;
+  ThreadCacheRegistry* const registry_;
 #if DCHECK_IS_ON()
   bool is_in_thread_cache_ = false;
 #endif
@@ -257,8 +280,8 @@
     ClearBucket(bucket, bucket.limit / 2);
   }
 
-  if (UNLIKELY(should_purge_.load(std::memory_order_relaxed)))
-    PurgeInternal();
+  if (UNLIKELY(mode_.load(std::memory_order_relaxed) != Mode::kNormal))
+    HandleNonNormalMode();
 
   return true;
 }
diff --git a/base/allocator/partition_allocator/thread_cache_unittest.cc b/base/allocator/partition_allocator/thread_cache_unittest.cc
index e9b541a..b942947 100644
--- a/base/allocator/partition_allocator/thread_cache_unittest.cc
+++ b/base/allocator/partition_allocator/thread_cache_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/callback.h"
 #include "base/synchronization/lock.h"
 #include "base/test/bind.h"
+#include "base/test/task_environment.h"
 #include "base/threading/platform_thread.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -24,9 +25,7 @@
 // With *SAN, PartitionAlloc is replaced in partition_alloc.h by ASAN, so we
 // cannot test the thread cache.
 //
-// Finally, the thread cache currently uses `thread_local`, which causes issues
-// on Windows 7 (at least). As long as it doesn't use something else on Windows,
-// disable the cache (and tests)
+// Finally, the thread cache is not supported on all platforms.
 #if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && \
     !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) &&  \
     defined(PA_THREAD_CACHE_SUPPORTED)
@@ -103,7 +102,14 @@
     ASSERT_TRUE(tcache);
     tcache->Purge();
   }
-  void TearDown() override {}
+
+  void TearDown() override {
+    task_env_.FastForwardUntilNoTasksRemain();
+    ASSERT_FALSE(ThreadCacheRegistry::Instance().has_pending_purge_task());
+  }
+
+  base::test::TaskEnvironment task_env_{
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
 };
 
 TEST_F(ThreadCacheTest, Simple) {
@@ -421,6 +427,103 @@
   PlatformThread::Join(thread_handle);
 }
 
+TEST_F(ThreadCacheTest, PeriodicPurge) {
+  ThreadCacheRegistry::Instance().StartPeriodicPurge();
+  EXPECT_TRUE(ThreadCacheRegistry::Instance().has_pending_purge_task());
+
+  std::atomic<bool> other_thread_started{false};
+  std::atomic<bool> purge_called{false};
+
+  size_t bucket_index = FillThreadCacheAndReturnIndex(kMediumSize);
+  ThreadCache* this_thread_tcache = g_root->thread_cache_for_testing();
+  ThreadCache* other_thread_tcache = nullptr;
+
+  LambdaThreadDelegate delegate{
+      BindLambdaForTesting([&]() NO_THREAD_SAFETY_ANALYSIS {
+        FillThreadCacheAndReturnIndex(kMediumSize);
+        other_thread_tcache = g_root->thread_cache_for_testing();
+
+        other_thread_started.store(true, std::memory_order_release);
+        while (!purge_called.load(std::memory_order_acquire)) {
+        }
+
+        // Purge() was not triggered from the other thread.
+        EXPECT_EQ(kFillCountForMediumBucket,
+                  other_thread_tcache->bucket_count_for_testing(bucket_index));
+        // Allocations do not trigger Purge().
+        void* data = g_root->Alloc(1, "");
+        EXPECT_EQ(kFillCountForMediumBucket,
+                  other_thread_tcache->bucket_count_for_testing(bucket_index));
+        // But deallocations do.
+        g_root->Free(data);
+        EXPECT_EQ(0u,
+                  other_thread_tcache->bucket_count_for_testing(bucket_index));
+      })};
+
+  PlatformThreadHandle thread_handle;
+  PlatformThread::Create(0, &delegate, &thread_handle);
+
+  while (!other_thread_started.load(std::memory_order_acquire)) {
+  }
+
+  EXPECT_EQ(kFillCountForMediumBucket,
+            this_thread_tcache->bucket_count_for_testing(bucket_index));
+  EXPECT_EQ(kFillCountForMediumBucket,
+            other_thread_tcache->bucket_count_for_testing(bucket_index));
+
+  task_env_.FastForwardBy(ThreadCacheRegistry::kPurgeInterval);
+  // Not enough allocations since last purge, don't reschedule it.
+  EXPECT_FALSE(ThreadCacheRegistry::Instance().has_pending_purge_task());
+
+  // This thread is synchronously purged.
+  EXPECT_EQ(0u, this_thread_tcache->bucket_count_for_testing(bucket_index));
+  // Not the other one.
+  EXPECT_EQ(kFillCountForMediumBucket,
+            other_thread_tcache->bucket_count_for_testing(bucket_index));
+
+  purge_called.store(true, std::memory_order_release);
+  PlatformThread::Join(thread_handle);
+}
+
+TEST_F(ThreadCacheTest, PeriodicPurgeStopsAndRestarts) {
+  const size_t kTestSize = 100;
+  ThreadCacheRegistry::Instance().StartPeriodicPurge();
+  EXPECT_TRUE(ThreadCacheRegistry::Instance().has_pending_purge_task());
+
+  size_t bucket_index = FillThreadCacheAndReturnIndex(kTestSize);
+  auto* tcache = ThreadCache::Get();
+  EXPECT_GT(tcache->bucket_count_for_testing(bucket_index), 0u);
+
+  task_env_.FastForwardBy(ThreadCacheRegistry::kPurgeInterval);
+  // Not enough allocations since last purge, don't reschedule it.
+  EXPECT_FALSE(ThreadCacheRegistry::Instance().has_pending_purge_task());
+
+  // This thread is synchronously purged.
+  EXPECT_EQ(0u, tcache->bucket_count_for_testing(bucket_index));
+
+  // 1 allocation is not enough to restart it.
+  FillThreadCacheAndReturnIndex(kTestSize);
+  EXPECT_FALSE(ThreadCacheRegistry::Instance().has_pending_purge_task());
+
+  for (int i = 0; i < ThreadCacheRegistry::kMinMainThreadAllocationsForPurging;
+       i++) {
+    FillThreadCacheAndReturnIndex(kTestSize);
+  }
+  EXPECT_TRUE(ThreadCacheRegistry::Instance().has_pending_purge_task());
+  EXPECT_GT(tcache->bucket_count_for_testing(bucket_index), 0u);
+
+  task_env_.FastForwardBy(ThreadCacheRegistry::kPurgeInterval);
+  EXPECT_EQ(0u, tcache->bucket_count_for_testing(bucket_index));
+  // Since there were enough allocations, another task is posted.
+  EXPECT_TRUE(ThreadCacheRegistry::Instance().has_pending_purge_task());
+
+  FillThreadCacheAndReturnIndex(kTestSize);
+  task_env_.FastForwardBy(ThreadCacheRegistry::kPurgeInterval);
+  EXPECT_EQ(0u, tcache->bucket_count_for_testing(bucket_index));
+  // Not enough this time.
+  EXPECT_FALSE(ThreadCacheRegistry::Instance().has_pending_purge_task());
+}
+
 }  // namespace internal
 }  // namespace base
 
diff --git a/base/mac/mac_util.h b/base/mac/mac_util.h
index f8275f3..8d1ccdd 100644
--- a/base/mac/mac_util.h
+++ b/base/mac/mac_util.h
@@ -145,8 +145,7 @@
 
 // Versions of macOS supported at runtime but whose SDK is not supported for
 // building.
-DEFINE_OLD_IS_OS_FUNCS_CR_MIN_REQUIRED(10, OLD_TEST_DEPLOYMENT_TARGET)
-DEFINE_OLD_IS_OS_FUNCS(11, OLD_TEST_DEPLOYMENT_TARGET)
+DEFINE_OLD_IS_OS_FUNCS_CR_MIN_REQUIRED(11, OLD_TEST_DEPLOYMENT_TARGET)
 DEFINE_OLD_IS_OS_FUNCS(12, OLD_TEST_DEPLOYMENT_TARGET)
 DEFINE_OLD_IS_OS_FUNCS(13, OLD_TEST_DEPLOYMENT_TARGET)
 DEFINE_OLD_IS_OS_FUNCS(14, OLD_TEST_DEPLOYMENT_TARGET)
diff --git a/base/mac/mac_util_unittest.mm b/base/mac/mac_util_unittest.mm
index 6266fda..f0a40d18 100644
--- a/base/mac/mac_util_unittest.mm
+++ b/base/mac/mac_util_unittest.mm
@@ -174,23 +174,10 @@
   EXPECT_FALSE(IsAtLeastOS##V());
 
   if (major == 10) {
-    if (minor == 10) {
-      EXPECT_TRUE(IsOS10_10());
-      EXPECT_TRUE(IsAtMostOS10_10());
+    if (minor == 11) {
+      EXPECT_TRUE(IsOS10_11());
+      EXPECT_TRUE(IsAtMostOS10_11());
 
-      TEST_FOR_FUTURE_10_OS(11);
-      TEST_FOR_FUTURE_10_OS(12);
-      TEST_FOR_FUTURE_10_OS(13);
-      TEST_FOR_FUTURE_10_OS(14);
-      TEST_FOR_FUTURE_10_OS(15);
-      TEST_FOR_FUTURE_OS(11);
-
-      EXPECT_FALSE(IsOSLaterThan11_DontCallThis());
-    } else if (minor == 11) {
-      EXPECT_FALSE(IsOS10_10());
-      EXPECT_FALSE(IsAtMostOS10_10());
-
-      TEST_FOR_SAME_10_OS(11);
       TEST_FOR_FUTURE_10_OS(12);
       TEST_FOR_FUTURE_10_OS(13);
       TEST_FOR_FUTURE_10_OS(14);
@@ -199,10 +186,9 @@
 
       EXPECT_FALSE(IsOSLaterThan11_DontCallThis());
     } else if (minor == 12) {
-      EXPECT_FALSE(IsOS10_10());
-      EXPECT_FALSE(IsAtMostOS10_10());
+      EXPECT_FALSE(IsOS10_11());
+      EXPECT_FALSE(IsAtMostOS10_11());
 
-      TEST_FOR_PAST_10_OS(11);
       TEST_FOR_SAME_10_OS(12);
       TEST_FOR_FUTURE_10_OS(13);
       TEST_FOR_FUTURE_10_OS(14);
@@ -211,10 +197,9 @@
 
       EXPECT_FALSE(IsOSLaterThan11_DontCallThis());
     } else if (minor == 13) {
-      EXPECT_FALSE(IsOS10_10());
-      EXPECT_FALSE(IsAtMostOS10_10());
+      EXPECT_FALSE(IsOS10_11());
+      EXPECT_FALSE(IsAtMostOS10_11());
 
-      TEST_FOR_PAST_10_OS(11);
       TEST_FOR_PAST_10_OS(12);
       TEST_FOR_SAME_10_OS(13);
       TEST_FOR_FUTURE_10_OS(14);
@@ -223,10 +208,9 @@
 
       EXPECT_FALSE(IsOSLaterThan11_DontCallThis());
     } else if (minor == 14) {
-      EXPECT_FALSE(IsOS10_10());
-      EXPECT_FALSE(IsAtMostOS10_10());
+      EXPECT_FALSE(IsOS10_11());
+      EXPECT_FALSE(IsAtMostOS10_11());
 
-      TEST_FOR_PAST_10_OS(11);
       TEST_FOR_PAST_10_OS(12);
       TEST_FOR_PAST_10_OS(13);
       TEST_FOR_SAME_10_OS(14);
@@ -235,10 +219,9 @@
 
       EXPECT_FALSE(IsOSLaterThan11_DontCallThis());
     } else if (minor == 15) {
-      EXPECT_FALSE(IsOS10_10());
-      EXPECT_FALSE(IsAtMostOS10_10());
+      EXPECT_FALSE(IsOS10_11());
+      EXPECT_FALSE(IsAtMostOS10_11());
 
-      TEST_FOR_PAST_10_OS(11);
       TEST_FOR_PAST_10_OS(12);
       TEST_FOR_PAST_10_OS(13);
       TEST_FOR_PAST_10_OS(14);
@@ -251,10 +234,9 @@
       EXPECT_TRUE(false);
     }
   } else if (major == 11) {
-    EXPECT_FALSE(IsOS10_10());
-    EXPECT_FALSE(IsAtMostOS10_10());
+    EXPECT_FALSE(IsOS10_11());
+    EXPECT_FALSE(IsAtMostOS10_11());
 
-    TEST_FOR_PAST_10_OS(11);
     TEST_FOR_PAST_10_OS(12);
     TEST_FOR_PAST_10_OS(13);
     TEST_FOR_PAST_10_OS(14);
diff --git a/base/power_monitor/power_monitor_device_source_mac.mm b/base/power_monitor/power_monitor_device_source_mac.mm
index 54a2215..7ab0b5c9 100644
--- a/base/power_monitor/power_monitor_device_source_mac.mm
+++ b/base/power_monitor/power_monitor_device_source_mac.mm
@@ -69,10 +69,7 @@
 
 PowerObserver::DeviceThermalState
 PowerMonitorDeviceSource::GetCurrentThermalState() {
-  if (@available(macOS 10.10.3, *)) {
-    return thermal_state_observer_->GetCurrentThermalState();
-  };
-  return PowerObserver::DeviceThermalState::kUnknown;
+  return thermal_state_observer_->GetCurrentThermalState();
 }
 
 namespace {
@@ -107,10 +104,8 @@
   CFRunLoopAddSource(CFRunLoopGetCurrent(), power_source_run_loop_source_,
                      kCFRunLoopDefaultMode);
 
-  if (@available(macOS 10.10.3, *)) {
-    thermal_state_observer_ = std::make_unique<ThermalStateObserverMac>(
-        BindRepeating(&PowerMonitorSource::ProcessThermalEvent));
-  };
+  thermal_state_observer_ = std::make_unique<ThermalStateObserverMac>(
+      BindRepeating(&PowerMonitorSource::ProcessThermalEvent));
 }
 
 void PowerMonitorDeviceSource::PlatformDestroy() {
diff --git a/build/android/adb_gdb b/build/android/adb_gdb
index bd0f1f3..6de4273 100755
--- a/build/android/adb_gdb
+++ b/build/android/adb_gdb
@@ -821,7 +821,7 @@
   # Remove the fingerprint file in case pulling one of the libs fails.
   rm -f "$PULL_LIBS_DIR/build.fingerprint"
   SYSTEM_LIBS=$(echo "$MAPPINGS" | \
-      awk '$6 ~ /\/system\/.*\.so$/ { print $6; }' | sort -u)
+      awk '$6 ~ /\/(system|apex|vendor)\/.*\.so$/ { print $6; }' | sort -u)
   for SYSLIB in /system/bin/linker$SUFFIX_64_BIT $SYSTEM_LIBS; do
     echo "Pulling from device: $SYSLIB"
     DST_FILE=$PULL_LIBS_DIR$SYSLIB
diff --git a/build/config/compiler/compiler.gni b/build/config/compiler/compiler.gni
index 09175ac8..9e472bef 100644
--- a/build/config/compiler/compiler.gni
+++ b/build/config/compiler/compiler.gni
@@ -233,9 +233,8 @@
     use_debug_fission == "default" || use_debug_fission || !use_debug_fission,
     "Invalid use_debug_fission.")
 if (use_debug_fission == "default") {
-  use_debug_fission = (is_android && is_official_build) ||
-                      (is_debug && !is_android && !is_fuchsia && !is_apple &&
-                       !is_win && (use_gold || use_lld) && cc_wrapper == "")
+  use_debug_fission = is_debug && !is_android && !is_fuchsia && !is_apple &&
+                      !is_win && (use_gold || use_lld) && cc_wrapper == ""
 }
 
 # If it wasn't manually set, set to an appropriate default.
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index b206e09..1a9a5740 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-0.20201203.3.1
+0.20201204.1.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index d1d50ac..1a9a5740 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-0.20201203.4.1
+0.20201204.1.1
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java
index cb2bbc7..5211c43 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java
@@ -30,6 +30,7 @@
 import org.chromium.chrome.browser.autofill_assistant.header.AssistantHeaderCoordinator;
 import org.chromium.chrome.browser.autofill_assistant.header.AssistantHeaderModel;
 import org.chromium.chrome.browser.autofill_assistant.infobox.AssistantInfoBoxCoordinator;
+import org.chromium.chrome.browser.autofill_assistant.overlay.AssistantOverlayCoordinator;
 import org.chromium.chrome.browser.autofill_assistant.user_data.AssistantCollectUserDataCoordinator;
 import org.chromium.chrome.browser.autofill_assistant.user_data.AssistantCollectUserDataModel;
 import org.chromium.chrome.browser.ui.TabObscuringHandler;
@@ -54,6 +55,7 @@
     private static final int CHANGE_BOUNDS_TRANSITION_TIME_MS = 250;
 
     private final AssistantModel mModel;
+    private final AssistantOverlayCoordinator mOverlayCoordinator;
     private final BottomSheetController mBottomSheetController;
     private final TabObscuringHandler mTabObscuringHandler;
     private final AssistantBottomSheetContent mContent;
@@ -100,10 +102,11 @@
     private int mShadowHeight;
 
     AssistantBottomBarCoordinator(Activity activity, AssistantModel model,
-            BottomSheetController controller,
+            AssistantOverlayCoordinator overlayCoordinator, BottomSheetController controller,
             ApplicationViewportInsetSupplier applicationViewportInsetSupplier,
             TabObscuringHandler tabObscuringHandler) {
         mModel = model;
+        mOverlayCoordinator = overlayCoordinator;
         mBottomSheetController = controller;
         mTabObscuringHandler = tabObscuringHandler;
 
@@ -206,6 +209,14 @@
                 if (newState != BottomSheetController.SheetState.SCROLLING) {
                     maybeShowHeaderChips();
                 }
+
+                if (newState == SheetState.HIDDEN) {
+                    mOverlayCoordinator.suppress();
+                }
+                if (newState == SheetState.PEEK || newState == SheetState.HALF
+                        || newState == SheetState.FULL) {
+                    mOverlayCoordinator.restore();
+                }
             }
 
             @Override
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantCoordinator.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantCoordinator.java
index 1939a19..0f8bdb32 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantCoordinator.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantCoordinator.java
@@ -45,9 +45,10 @@
                     controller.getScrimCoordinator(), mModel.getOverlayModel());
         }
 
-        mBottomBarCoordinator = new AssistantBottomBarCoordinator(activity, mModel, controller,
-                activity.getWindowAndroid().getApplicationBottomInsetProvider(),
-                tabObscuringHandler);
+        mBottomBarCoordinator =
+                new AssistantBottomBarCoordinator(activity, mModel, mOverlayCoordinator, controller,
+                        activity.getWindowAndroid().getApplicationBottomInsetProvider(),
+                        tabObscuringHandler);
         mKeyboardCoordinator = new AssistantKeyboardCoordinator(activity,
                 activity.getWindowAndroid().getKeyboardDelegate(),
                 activity.getCompositorViewHolder(), mModel, keyboardCoordinatorDelegate,
@@ -57,9 +58,9 @@
     /** Detaches and destroys the view. */
     public void destroy() {
         mModel.setVisible(false);
-        mOverlayCoordinator.destroy();
         mBottomBarCoordinator.destroy();
         mBottomBarCoordinator = null;
+        mOverlayCoordinator.destroy();
     }
 
     /**
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantOnboardingCoordinator.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantOnboardingCoordinator.java
index 2c1149d..0e359f67 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantOnboardingCoordinator.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantOnboardingCoordinator.java
@@ -156,12 +156,16 @@
         mBottomSheetObserver = new EmptyBottomSheetObserver() {
             @Override
             public void onSheetStateChanged(int newState) {
+                if (mOverlayCoordinator == null) {
+                    return;
+                }
+
                 if (newState == SheetState.HIDDEN) {
-                    overlayModel.set(AssistantOverlayModel.STATE, AssistantOverlayState.HIDDEN);
+                    mOverlayCoordinator.suppress();
                 }
                 if (newState == SheetState.PEEK || newState == SheetState.HALF
                         || newState == SheetState.FULL) {
-                    overlayModel.set(AssistantOverlayModel.STATE, AssistantOverlayState.FULL);
+                    mOverlayCoordinator.restore();
                 }
             }
         };
@@ -210,6 +214,8 @@
 
     /** Hides the UI, if one is shown. */
     void hide() {
+        mController.removeObserver(mBottomSheetObserver);
+
         if (mOverlayCoordinator != null) {
             mOverlayCoordinator.destroy();
             mOverlayCoordinator = null;
@@ -224,8 +230,6 @@
             mWebContentsObserver.destroy();
             mWebContentsObserver = null;
         }
-
-        mController.removeObserver(mBottomSheetObserver);
     }
 
     /**
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/overlay/AssistantOverlayCoordinator.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/overlay/AssistantOverlayCoordinator.java
index 4124fb6..f83fc61 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/overlay/AssistantOverlayCoordinator.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/overlay/AssistantOverlayCoordinator.java
@@ -7,12 +7,8 @@
 import android.content.Context;
 import android.graphics.RectF;
 
-import org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiController;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
 import org.chromium.chrome.browser.compositor.CompositorViewHolder;
-import org.chromium.chrome.browser.image_fetcher.ImageFetcher;
-import org.chromium.chrome.browser.image_fetcher.ImageFetcherConfig;
-import org.chromium.chrome.browser.image_fetcher.ImageFetcherFactory;
 import org.chromium.chrome.browser.util.ChromeAccessibilityUtil;
 import org.chromium.components.browser_ui.widget.scrim.ScrimCoordinator;
 import org.chromium.components.browser_ui.widget.scrim.ScrimProperties;
@@ -30,22 +26,13 @@
     private final AssistantOverlayDrawable mDrawable;
     private final CompositorViewHolder mCompositorViewHolder;
     private final ScrimCoordinator mScrim;
-    private final ImageFetcher mImageFetcher;
     private boolean mScrimEnabled;
+    private boolean mScrimSuppressed;
 
     public AssistantOverlayCoordinator(Context context,
             BrowserControlsStateProvider browserControls, CompositorViewHolder compositorViewHolder,
             ScrimCoordinator scrim, AssistantOverlayModel model) {
-        this(context, browserControls, compositorViewHolder, scrim, model,
-                ImageFetcherFactory.createImageFetcher(ImageFetcherConfig.DISK_CACHE_ONLY,
-                        AutofillAssistantUiController.getProfile()));
-    }
-
-    public AssistantOverlayCoordinator(Context context,
-            BrowserControlsStateProvider browserControls, CompositorViewHolder compositorViewHolder,
-            ScrimCoordinator scrim, AssistantOverlayModel model, ImageFetcher imageFetcher) {
         mModel = model;
-        mImageFetcher = imageFetcher;
         mCompositorViewHolder = compositorViewHolder;
         mScrim = scrim;
         mEventFilter =
@@ -103,9 +90,29 @@
     }
 
     /**
+     * Suppress the Scrim.
+     */
+    public void suppress() {
+        mScrimSuppressed = true;
+        setScrimEnabled(false);
+    }
+
+    /**
+     * Restore the Scrim to the current state.
+     */
+    public void restore() {
+        mScrimSuppressed = false;
+        setState(mModel.get(AssistantOverlayModel.STATE));
+    }
+
+    /**
      * Set the overlay state.
      */
     private void setState(@AssistantOverlayState int state) {
+        if (mScrimSuppressed) {
+            return;
+        }
+
         if (state == AssistantOverlayState.PARTIAL
                 && ChromeAccessibilityUtil.get().isAccessibilityEnabled()) {
             // Touch exploration is fully disabled if there's an overlay in front. In this case, the
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantChromeTabIntegrationTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantChromeTabIntegrationTest.java
index c989b511..d12bf9ac 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantChromeTabIntegrationTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantChromeTabIntegrationTest.java
@@ -46,6 +46,7 @@
 import org.chromium.chrome.autofill_assistant.R;
 import org.chromium.chrome.browser.autofill_assistant.proto.ActionProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.ChipProto;
+import org.chromium.chrome.browser.autofill_assistant.proto.ChipType;
 import org.chromium.chrome.browser.autofill_assistant.proto.ConfigureBottomSheetProto.PeekMode;
 import org.chromium.chrome.browser.autofill_assistant.proto.PromptProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.StopProto;
@@ -489,7 +490,6 @@
 
     @Test
     @MediumTest
-    @DisabledTest(message = "https://crbug.com/1131835")
     public void interactingWithLocationBarHidesAutofillAssistant() {
         ArrayList<ActionProto> list = new ArrayList<>();
         list.add((ActionProto) ActionProto.newBuilder()
@@ -508,6 +508,8 @@
         startAutofillAssistantOnTab(TEST_PAGE_A);
 
         waitUntilViewMatchesCondition(withText("Prompt"), isCompletelyDisplayed());
+        waitUntilViewMatchesCondition(is(mScrimCoordinator.getViewForTesting()),
+                withEffectiveVisibility(Visibility.VISIBLE));
 
         // Clicking location bar hides UI and shows the keyboard.
         onView(withId(org.chromium.chrome.R.id.url_bar)).perform(click());
@@ -517,6 +519,8 @@
         // Closing keyboard brings it back.
         Espresso.pressBack();
         waitUntilViewMatchesCondition(withText("Prompt"), isCompletelyDisplayed());
+        waitUntilViewMatchesCondition(is(mScrimCoordinator.getViewForTesting()),
+                withEffectiveVisibility(Visibility.VISIBLE));
 
         // Committing URL shows error.
         onView(withId(org.chromium.chrome.R.id.url_bar))
@@ -526,6 +530,56 @@
 
     @Test
     @MediumTest
+    public void interactingWithLocationBarDoesNotShowHiddenScrim() {
+        ArrayList<ActionProto> list = new ArrayList<>();
+        list.add((ActionProto) ActionProto.newBuilder()
+                         .setPrompt(PromptProto.newBuilder()
+                                            .setMessage("Browse")
+                                            .setBrowseMode(true)
+                                            .addChoices(PromptProto.Choice.newBuilder().setChip(
+                                                    ChipProto.newBuilder()
+                                                            .setType(ChipType.HIGHLIGHTED_ACTION)
+                                                            .setText("Continue"))))
+                         .build());
+        list.add((ActionProto) ActionProto.newBuilder()
+                         .setPrompt(PromptProto.newBuilder().setMessage("Prompt").addChoices(
+                                 PromptProto.Choice.newBuilder()))
+                         .build());
+
+        AutofillAssistantTestScript script = new AutofillAssistantTestScript(
+                (SupportedScriptProto) SupportedScriptProto.newBuilder()
+                        .setPath(TEST_PAGE_A)
+                        .setPresentation(PresentationProto.newBuilder().setAutostart(true).setChip(
+                                ChipProto.newBuilder().setText("Done")))
+                        .build(),
+                list);
+        setupScripts(script);
+        startAutofillAssistantOnTab(TEST_PAGE_A);
+
+        // Browse mode hides the Scrim.
+        waitUntilViewMatchesCondition(withText("Browse"), isCompletelyDisplayed());
+        waitUntilViewMatchesCondition(is(mScrimCoordinator.getViewForTesting()),
+                not(withEffectiveVisibility(Visibility.VISIBLE)));
+
+        // Clicking location bar hides UI and shows the keyboard.
+        onView(withId(org.chromium.chrome.R.id.url_bar)).perform(click());
+        waitUntilViewMatchesCondition(withText("Browse"), not(isDisplayed()));
+        waitUntilKeyboardMatchesCondition(mTestRule, /* isShowing= */ true);
+
+        // Closing keyboard brings back the UI but does not restore the Scrim.
+        Espresso.pressBack();
+        waitUntilViewMatchesCondition(withText("Browse"), isCompletelyDisplayed());
+        waitUntil(() -> mScrimCoordinator.getViewForTesting() == null);
+
+        // Running the next action brings back the Scrim.
+        onView(withText("Continue")).perform(click());
+        waitUntilViewMatchesCondition(withText("Prompt"), isCompletelyDisplayed());
+        waitUntilViewMatchesCondition(is(mScrimCoordinator.getViewForTesting()),
+                withEffectiveVisibility(Visibility.VISIBLE));
+    }
+
+    @Test
+    @MediumTest
     public void switchingBackToTabWithStoppedAutofillAssistantShowsErrorMessage() {
         ArrayList<ActionProto> list = new ArrayList<>();
         list.add((ActionProto) ActionProto.newBuilder()
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantOverlayUiTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantOverlayUiTest.java
index f49d12e0..07c8e1e 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantOverlayUiTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantOverlayUiTest.java
@@ -93,17 +93,14 @@
     private AssistantOverlayCoordinator createCoordinator(
             AssistantOverlayModel model, @Nullable Bitmap overlayImage) throws ExecutionException {
         ChromeActivity activity = mTestRule.getActivity();
-        return runOnUiThreadBlocking(
-                ()
-                        -> new AssistantOverlayCoordinator(activity,
-                                activity.getBrowserControlsManager(),
-                                activity.getCompositorViewHolder(),
-                                mTestRule.getActivity()
-                                        .getRootUiCoordinatorForTesting()
-                                        .getScrimCoordinator(),
-                                model,
-                                new AutofillAssistantUiTestUtil.MockImageFetcher(
-                                        overlayImage, null)));
+        return runOnUiThreadBlocking(()
+                                             -> new AssistantOverlayCoordinator(activity,
+                                                     activity.getBrowserControlsManager(),
+                                                     activity.getCompositorViewHolder(),
+                                                     mTestRule.getActivity()
+                                                             .getRootUiCoordinatorForTesting()
+                                                             .getScrimCoordinator(),
+                                                     model));
     }
 
     /** Tests assumptions about the initial state of the infobox. */
diff --git a/chrome/android/features/keyboard_accessory/BUILD.gn b/chrome/android/features/keyboard_accessory/BUILD.gn
index ce94f00..180261d 100644
--- a/chrome/android/features/keyboard_accessory/BUILD.gn
+++ b/chrome/android/features/keyboard_accessory/BUILD.gn
@@ -80,6 +80,7 @@
     "//content/public/test/android:content_java_test_support",
     "//net/android:net_java_test_support",
     "//third_party/android_deps:androidx_annotation_annotation_java",
+    "//third_party/android_deps:androidx_appcompat_appcompat_java",
     "//third_party/android_deps:androidx_recyclerview_recyclerview_java",
     "//third_party/android_deps:androidx_test_runner_java",
     "//third_party/android_deps:espresso_java",
diff --git a/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_option_toggle.xml b/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_option_toggle.xml
index 6e3d304..1d3df1d 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_option_toggle.xml
+++ b/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_option_toggle.xml
@@ -37,7 +37,7 @@
             android:textAppearance="@style/TextAppearance.TextMedium.Secondary" />
     </LinearLayout>
 
-    <android.widget.Switch
+    <androidx.appcompat.widget.SwitchCompat
         android:id="@+id/option_toggle_switch"
         android:layout_marginStart="16dp"
         android:layout_width="48dp"
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AccessorySheetTabViewBinder.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AccessorySheetTabViewBinder.java
index 6c60169..561abdb9 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AccessorySheetTabViewBinder.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AccessorySheetTabViewBinder.java
@@ -8,11 +8,11 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.LinearLayout;
-import android.widget.Switch;
 import android.widget.TextView;
 
 import androidx.annotation.LayoutRes;
 import androidx.annotation.Nullable;
+import androidx.appcompat.widget.SwitchCompat;
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
 
@@ -119,7 +119,7 @@
             TextView subtitleText = view.findViewById(R.id.option_toggle_subtitle);
             subtitleText.setText(optionToggle.isEnabled() ? R.string.text_on : R.string.text_off);
 
-            Switch switchView = view.findViewById(R.id.option_toggle_switch);
+            SwitchCompat switchView = view.findViewById(R.id.option_toggle_switch);
             switchView.setChecked(optionToggle.isEnabled());
             switchView.setBackground(null);
         }
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetModernViewTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetModernViewTest.java
index 5fcd9ee..07630d7 100644
--- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetModernViewTest.java
+++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetModernViewTest.java
@@ -19,9 +19,9 @@
 import android.text.method.PasswordTransformationMethod;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.Switch;
 import android.widget.TextView;
 
+import androidx.appcompat.widget.SwitchCompat;
 import androidx.recyclerview.widget.RecyclerView;
 import androidx.test.filters.MediumTest;
 
@@ -198,8 +198,8 @@
 
         View switchView = mView.get().findViewById(R.id.option_toggle_switch);
         assertThat(switchView, is(not(nullValue())));
-        assertThat(switchView, instanceOf(Switch.class));
-        assertFalse(((Switch) switchView).isChecked());
+        assertThat(switchView, instanceOf(SwitchCompat.class));
+        assertFalse(((SwitchCompat) switchView).isChecked());
     }
 
     @Test
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceViewBinder.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceViewBinder.java
index 97c97c2..bbbd842 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceViewBinder.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceViewBinder.java
@@ -9,12 +9,15 @@
 import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.IS_BOTTOM_BAR_VISIBLE;
 import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.IS_EXPLORE_SURFACE_VISIBLE;
 import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.IS_SHOWING_OVERVIEW;
+import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.RESET_FEED_SURFACE_SCROLL_POSITION;
 import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.TOP_MARGIN;
 
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
+import androidx.recyclerview.widget.RecyclerView;
+
 import org.chromium.ui.UiUtils;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
@@ -30,6 +33,8 @@
                     model.get(IS_EXPLORE_SURFACE_VISIBLE) && model.get(IS_SHOWING_OVERVIEW));
         } else if (propertyKey == TOP_MARGIN) {
             setTopMargin(model);
+        } else if (propertyKey == RESET_FEED_SURFACE_SCROLL_POSITION) {
+            resetScrollPosition(model);
         }
     }
 
@@ -76,4 +81,14 @@
         layoutParams.topMargin = model.get(TOP_MARGIN);
         feedSurfaceView.setLayoutParams(layoutParams);
     }
+
+    private static void resetScrollPosition(PropertyModel model) {
+        if (model.get(FEED_SURFACE_COORDINATOR) == null) return;
+
+        RecyclerView feedStreamView =
+                (RecyclerView) model.get(FEED_SURFACE_COORDINATOR).getStream().getView();
+        if (feedStreamView != null) {
+            feedStreamView.scrollToPosition(0);
+        }
+    }
 }
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
index f0214c50..23acb3db 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
@@ -14,6 +14,7 @@
 import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.MORE_TABS_CLICK_LISTENER;
 import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.MV_TILES_CONTAINER_TOP_MARGIN;
 import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.MV_TILES_VISIBLE;
+import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.RESET_TASK_SURFACE_HEADER_SCROLL_POSITION;
 import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.TAB_SWITCHER_TITLE_TOP_MARGIN;
 import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.TASKS_SURFACE_BODY_TOP_MARGIN;
 import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.TRENDY_TERMS_VISIBLE;
@@ -26,6 +27,7 @@
 import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.IS_SECONDARY_SURFACE_VISIBLE;
 import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.IS_SHOWING_OVERVIEW;
 import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.IS_SHOWING_STACK_TAB_SWITCHER;
+import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.RESET_FEED_SURFACE_SCROLL_POSITION;
 import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.TOP_MARGIN;
 
 import android.content.Context;
@@ -422,6 +424,13 @@
 
         if (mPropertyModel == null || state == mStartSurfaceState) return;
 
+        // When entering the Start surface by tapping home button or new tab page, we need to reset
+        // the scrolling position.
+        if (state == StartSurfaceState.SHOWING_HOMEPAGE) {
+            mPropertyModel.set(RESET_TASK_SURFACE_HEADER_SCROLL_POSITION, true);
+            mPropertyModel.set(RESET_FEED_SURFACE_SCROLL_POSITION, true);
+        }
+
         // Cache previous state.
         if (mStartSurfaceState != StartSurfaceState.NOT_SHOWN) {
             mPreviousStartSurfaceState = mStartSurfaceState;
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceProperties.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceProperties.java
index 913e0e7..89670c98 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceProperties.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceProperties.java
@@ -43,8 +43,11 @@
             new PropertyModel.WritableObjectPropertyKey<FeedSurfaceCoordinator>();
     public static final PropertyModel.WritableIntPropertyKey TOP_MARGIN =
             new PropertyModel.WritableIntPropertyKey();
+    public static final PropertyModel.WritableObjectPropertyKey RESET_FEED_SURFACE_SCROLL_POSITION =
+            new PropertyModel.WritableObjectPropertyKey<>(true /* skipEquality */);
     public static final PropertyKey[] ALL_KEYS = new PropertyKey[] {BOTTOM_BAR_CLICKLISTENER,
             BOTTOM_BAR_HEIGHT, BOTTOM_BAR_SELECTED_TAB_POSITION, IS_BOTTOM_BAR_VISIBLE,
             IS_EXPLORE_SURFACE_VISIBLE, IS_SECONDARY_SURFACE_VISIBLE, IS_SHOWING_OVERVIEW,
-            IS_SHOWING_STACK_TAB_SWITCHER, FEED_SURFACE_COORDINATOR, TOP_MARGIN};
+            IS_SHOWING_STACK_TAB_SWITCHER, FEED_SURFACE_COORDINATOR, TOP_MARGIN,
+            RESET_FEED_SURFACE_SCROLL_POSITION};
 }
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
index a623bde..18c1086 100644
--- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
+++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
@@ -64,6 +64,8 @@
 import androidx.test.espresso.matcher.ViewMatchers;
 import androidx.test.filters.MediumTest;
 
+import com.google.android.material.appbar.AppBarLayout;
+
 import org.hamcrest.Description;
 import org.hamcrest.Matcher;
 import org.hamcrest.Matchers;
@@ -1499,6 +1501,49 @@
         assertTrue(bottomSheetTestSupport.hasSuppressionTokens());
     }
 
+    @Test
+    @MediumTest
+    @Feature({"StartSurface"})
+    // clang-format off
+    @CommandLineFlags.Add({BASE_PARAMS + "/single"})
+    public void testShow_SingleAsHomepage_ResetScrollPosition() {
+        // clang-format on
+        if (!mImmediateReturn) {
+            onView(withId(org.chromium.chrome.tab_ui.R.id.home_button)).perform(click());
+        }
+
+        ChromeTabbedActivity cta = mActivityTestRule.getActivity();
+        CriteriaHelper.pollUiThread(
+                () -> cta.getLayoutManager() != null && cta.getLayoutManager().overviewVisible());
+        waitForTabModel();
+        TabUiTestHelper.verifyTabModelTabCount(cta, 1, 0);
+
+        // Scroll the toolbar.
+        scrollToolbar();
+        AppBarLayout taskSurfaceHeader =
+                cta.findViewById(org.chromium.chrome.tab_ui.R.id.task_surface_header);
+        assertNotEquals(taskSurfaceHeader.getBottom(), taskSurfaceHeader.getHeight());
+
+        // Verifies the case of scrolling Start surface ->  tab switcher -> tap "+1" button ->
+        // Start surface. The Start surface should reset its scroll position.
+        try {
+            TestThreadUtils.runOnUiThreadBlocking(
+                    ()
+                            -> mActivityTestRule.getActivity()
+                                       .findViewById(org.chromium.chrome.tab_ui.R.id.more_tabs)
+                                       .performClick());
+        } catch (ExecutionException e) {
+            fail("Failed to tap 'more tabs' " + e.toString());
+        }
+
+        onViewWaiting(withId(R.id.secondary_tasks_surface_view));
+        TestThreadUtils.runOnUiThreadBlocking(() -> cta.getTabCreator(false).launchNTP());
+        onViewWaiting(
+                allOf(withId(org.chromium.chrome.tab_ui.R.id.mv_tiles_container), isDisplayed()));
+
+        assertEquals(taskSurfaceHeader.getBottom(), taskSurfaceHeader.getHeight());
+    }
+
     private static Matcher<View> isView(final View targetView) {
         return new TypeSafeMatcher<View>() {
             @Override
@@ -1527,6 +1572,16 @@
         // requires mImmediateReturn to be true.
         assumeTrue(mImmediateReturn);
 
+        scrollToolbar();
+
+        // Check the toolbar's background color.
+        ToolbarPhone toolbar =
+                mActivityTestRule.getActivity().findViewById(org.chromium.chrome.R.id.toolbar);
+        Assert.assertEquals(toolbar.getToolbarDataProvider().getPrimaryColor(),
+                toolbar.getBackgroundDrawable().getColor());
+    }
+
+    private void scrollToolbar() {
         onViewWaiting(allOf(withId(R.id.feed_stream_recycler_view), isDisplayed()));
 
         // Default scrollTo() cannot be used for RecyclerView. Add a customized scrollTo for
@@ -1570,12 +1625,6 @@
 
         // Toolbar container view should show.
         onView(withId(R.id.toolbar_container)).check(matches(isDisplayed()));
-
-        // Check the toolbar's background color.
-        ToolbarPhone toolbar =
-                mActivityTestRule.getActivity().findViewById(org.chromium.chrome.R.id.toolbar);
-        Assert.assertEquals(toolbar.getToolbarDataProvider().getPrimaryColor(),
-                toolbar.getBackgroundDrawable().getColor());
     }
 }
 
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksSurfaceProperties.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksSurfaceProperties.java
index 85af37f..5a034a9 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksSurfaceProperties.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksSurfaceProperties.java
@@ -75,6 +75,9 @@
             new PropertyModel.WritableIntPropertyKey();
     public static final PropertyModel.WritableBooleanPropertyKey TRENDY_TERMS_VISIBLE =
             new PropertyModel.WritableBooleanPropertyKey();
+    public static final PropertyModel
+            .WritableObjectPropertyKey RESET_TASK_SURFACE_HEADER_SCROLL_POSITION =
+            new PropertyModel.WritableObjectPropertyKey<>(true /* skipEquality */);
     public static final PropertyKey[] ALL_KEYS = new PropertyKey[] {IS_FAKE_SEARCH_BOX_VISIBLE,
             IS_INCOGNITO, IS_INCOGNITO_DESCRIPTION_INITIALIZED, IS_INCOGNITO_DESCRIPTION_VISIBLE,
             IS_SURFACE_BODY_VISIBLE, IS_TAB_CAROUSEL_VISIBLE, IS_VOICE_RECOGNITION_BUTTON_VISIBLE,
@@ -85,5 +88,6 @@
             INCOGNITO_LEARN_MORE_CLICK_LISTENER, FAKE_SEARCH_BOX_CLICK_LISTENER,
             FAKE_SEARCH_BOX_TEXT_WATCHER, MORE_TABS_CLICK_LISTENER, MV_TILES_VISIBLE,
             VOICE_SEARCH_BUTTON_CLICK_LISTENER, TASKS_SURFACE_BODY_TOP_MARGIN,
-            MV_TILES_CONTAINER_TOP_MARGIN, TAB_SWITCHER_TITLE_TOP_MARGIN, TRENDY_TERMS_VISIBLE};
+            MV_TILES_CONTAINER_TOP_MARGIN, TAB_SWITCHER_TITLE_TOP_MARGIN, TRENDY_TERMS_VISIBLE,
+            RESET_TASK_SURFACE_HEADER_SCROLL_POSITION};
 }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksView.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksView.java
index 1a594c7..eb21254 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksView.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksView.java
@@ -342,6 +342,14 @@
     }
 
     /**
+     * Reset the scrolling position by expanding the {@link #mHeaderView}.
+     */
+    void resetScrollPosition() {
+        if (mHeaderView != null && mHeaderView.getHeight() != mHeaderView.getBottom()) {
+            mHeaderView.setExpanded(true);
+        }
+    }
+    /**
      * Add a header offset change listener.
      * @param onOffsetChangedListener The given header offset change listener.
      */
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksViewBinder.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksViewBinder.java
index c6835ea..971be0d 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksViewBinder.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksViewBinder.java
@@ -23,6 +23,7 @@
 import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.MORE_TABS_CLICK_LISTENER;
 import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.MV_TILES_CONTAINER_TOP_MARGIN;
 import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.MV_TILES_VISIBLE;
+import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.RESET_TASK_SURFACE_HEADER_SCROLL_POSITION;
 import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.TAB_SWITCHER_TITLE_TOP_MARGIN;
 import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.TASKS_SURFACE_BODY_TOP_MARGIN;
 import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.TRENDY_TERMS_VISIBLE;
@@ -98,6 +99,8 @@
             view.setTabSwitcherTitleTopMargin(model.get(TAB_SWITCHER_TITLE_TOP_MARGIN));
         } else if (propertyKey == TRENDY_TERMS_VISIBLE) {
             view.setTrendyTermsVisibility(model.get(TRENDY_TERMS_VISIBLE));
+        } else if (propertyKey == RESET_TASK_SURFACE_HEADER_SCROLL_POSITION) {
+            view.resetScrollPosition();
         }
     }
 }
diff --git a/chrome/android/java/res/layout/start_top_toolbar.xml b/chrome/android/java/res/layout/start_top_toolbar.xml
index 479e87a..1d3343ad 100644
--- a/chrome/android/java/res/layout/start_top_toolbar.xml
+++ b/chrome/android/java/res/layout/start_top_toolbar.xml
@@ -14,6 +14,7 @@
     android:visibility="gone">
 
     <Switch
+        tools:ignore="UseSwitchCompatOrMaterialXml"
         android:id="@+id/incognito_switch"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
diff --git a/chrome/android/java/res/layout/tab_switcher_toolbar.xml b/chrome/android/java/res/layout/tab_switcher_toolbar.xml
index b7404b6..7248a68b 100644
--- a/chrome/android/java/res/layout/tab_switcher_toolbar.xml
+++ b/chrome/android/java/res/layout/tab_switcher_toolbar.xml
@@ -6,6 +6,7 @@
 <org.chromium.chrome.browser.toolbar.top.TabSwitcherModeTTPhone
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/tab_switcher_toolbar"
     android:layout_width="match_parent"
     android:layout_height="@dimen/toolbar_height_no_shadow"
@@ -89,7 +90,8 @@
             android:paddingEnd="16dp"
             android:thumb="@drawable/incognito_switch"
             android:track="@drawable/incognito_switch_track"
-            android:visibility="gone"/>
+            android:visibility="gone"
+            tools:ignore="UseSwitchCompatOrMaterialXml"/>
 
         <include layout="@layout/menu_button" />
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHelper.java
index 02ed7d5b..213afa588 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHelper.java
@@ -184,7 +184,7 @@
                 mCurrentPopulator.onMenuClosed();
                 mCurrentPopulator = null;
             }
-            if (LensUtils.enableImageChip(mIsIncognito)) {
+            if (mChipDelegate != null) {
                 // If the image was being classified terminate the classification
                 // Has no effect if the classification already succeeded.
                 mChipDelegate.onMenuClosed();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetView.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetView.java
index e373938..67da2910 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetView.java
@@ -86,8 +86,8 @@
                                        .findViewById(R.id.account_picker_selected_account);
         mDismissButton = mViewFlipper.getChildAt(ViewState.COLLAPSED_ACCOUNT_LIST)
                                  .findViewById(R.id.account_picker_dismiss_button);
-        if (AccountPickerFeatureUtils.shouldShowNoThanksOnDismissButton()) {
-            mDismissButton.setText(R.string.no_thanks);
+        if (AccountPickerFeatureUtils.shouldHideDismissButton()) {
+            mDismissButton.setVisibility(View.GONE);
         }
 
         // TODO(https://crbug.com/1146990): Use different continue buttons for different view
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerFeatureUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerFeatureUtils.java
index 2f6dc9c..a06e7c7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerFeatureUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerFeatureUtils.java
@@ -10,12 +10,12 @@
  * This class is used to handle state of feature flags in the project
  * MobileIdentityConsistency.
  */
-public class AccountPickerFeatureUtils {
+class AccountPickerFeatureUtils {
     private static final String DISMISS_BUTTON_PARAM = "dismiss_button";
-    private static final String DISMISS_BUTTON_NO_THANKS = "no_thanks";
+    private static final String HIDE_DISMISS_BUTTON = "hide";
 
-    static boolean shouldShowNoThanksOnDismissButton() {
-        return DISMISS_BUTTON_NO_THANKS.equals(ChromeFeatureList.getFieldTrialParamByFeature(
+    static boolean shouldHideDismissButton() {
+        return HIDE_DISMISS_BUTTON.equals(ChromeFeatureList.getFieldTrialParamByFeature(
                 ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY_VAR, DISMISS_BUTTON_PARAM));
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/IncognitoSwitchCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/IncognitoSwitchCoordinator.java
index c58657f..ef77422 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/IncognitoSwitchCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/IncognitoSwitchCoordinator.java
@@ -31,6 +31,7 @@
     private TabModelSelector mTabModelSelector;
     private TabModelSelectorObserver mTabModelSelectorObserver;
 
+    @SuppressWarnings({"UseSwitchCompatOrMaterialCode"})
     public IncognitoSwitchCoordinator(ViewGroup root, TabModelSelector tabModelSelector) {
         assert tabModelSelector != null;
         mTabModelSelector = tabModelSelector;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/IncognitoSwitchViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/IncognitoSwitchViewBinder.java
index 8f1d8e2..a00820a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/IncognitoSwitchViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/IncognitoSwitchViewBinder.java
@@ -24,6 +24,7 @@
      * Build a binder that handles interaction between the model and the view that make up the
      * incognito switch.
      */
+    @SuppressWarnings({"UseSwitchCompatOrMaterialCode"})
     public static void bind(PropertyModel model, Switch incognitoSwitch, PropertyKey propertyKey) {
         if (IncognitoSwitchProperties.ON_CHECKED_CHANGE_LISTENER == propertyKey) {
             incognitoSwitch.setOnCheckedChangeListener(
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index 7c642d5..be98975 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-89.0.4342.0_rc-r1-merged.afdo.bz2
+chromeos-chrome-amd64-89.0.4343.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index dd01b838..c135928 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -5467,6 +5467,9 @@
   <message name="IDS_ACCOUNT_MANAGER_WELCOME_BUTTON" desc="Label for the button to view accounts on the Chrome OS Account Manager Welcome screen.">
     View accounts
   </message>
+  <message name="IDS_ACCOUNT_MANAGER_DIALOG_WELCOME_TITLE" desc="Title for the Welcome screen in Chrome OS 'Add account' dialog.">
+    Add a secondary Google Account for <ph name="USER_NAME">$1<ex>John</ex></ph>
+  </message>
   <message name="IDS_ACCOUNT_MANAGER_ERROR_NO_INTERNET_TITLE" desc="Title for the network error screen.">
     No Internet
   </message>
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ACCOUNT_MANAGER_DIALOG_WELCOME_BODY.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_ACCOUNT_MANAGER_DIALOG_WELCOME_BODY.png.sha1
new file mode 100644
index 0000000..c56808f
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_ACCOUNT_MANAGER_DIALOG_WELCOME_BODY.png.sha1
@@ -0,0 +1 @@
+1bd4e289cc5474bbdd1909fad5d723269a25a306
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ACCOUNT_MANAGER_DIALOG_WELCOME_TITLE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_ACCOUNT_MANAGER_DIALOG_WELCOME_TITLE.png.sha1
new file mode 100644
index 0000000..91679cc5
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_ACCOUNT_MANAGER_DIALOG_WELCOME_TITLE.png.sha1
@@ -0,0 +1 @@
+c4dd21a1e21ef55bd5ef3c9d17df911348efa325
\ No newline at end of file
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index c20506d..858376d51 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -1091,6 +1091,14 @@
         </message>
       </if>
 
+      <!-- Chrome OS in-session 'Add account' flow -->
+      <if expr="chromeos">
+        <message name="IDS_ACCOUNT_MANAGER_DIALOG_WELCOME_BODY" desc="Text body for the Welcome screen in Chrome OS 'Add account' dialog.">
+          You can manage this and other Google Accounts you've added for <ph name="USER_NAME">$1<ex>John</ex></ph> from one place in <ph name="LINK_BEGIN">&lt;a id="osSettingsLink" href="$2<ex>https://google.com/</ex>"&gt;</ph>Settings<ph name="LINK_END">&lt;/a&gt;</ph>.
+          Permissions you have granted to websites in the Chromium browser and apps from Google Play may apply to all accounts.
+        </message>
+      </if>
+
       <!-- Native notifications for Windows 10 -->
       <if expr="is_win">
         <message name="IDS_WIN_NOTIFICATION_SETTINGS_CONTEXT_MENU_ITEM_NAME" desc="The name of the button in Windows Notification Center which leads to Chrome notification settings.">
diff --git a/chrome/app/chromium_strings_grd/IDS_ACCOUNT_MANAGER_DIALOG_WELCOME_BODY.png.sha1 b/chrome/app/chromium_strings_grd/IDS_ACCOUNT_MANAGER_DIALOG_WELCOME_BODY.png.sha1
new file mode 100644
index 0000000..1b1a6f71
--- /dev/null
+++ b/chrome/app/chromium_strings_grd/IDS_ACCOUNT_MANAGER_DIALOG_WELCOME_BODY.png.sha1
@@ -0,0 +1 @@
+57468ecef9c8f19c1554aa0ce7a63f2411de021c
\ No newline at end of file
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index acb86d9..10f678e 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -4927,6 +4927,12 @@
       <message name="IDS_UPDATE_PASSWORD_DIFFERENT_DOMAINS_TITLE" desc="The title of the update password bubble when the submitted form origin isn't equal to saved credentials origin.">
         Update password for <ph name="ORIGIN">$1<ex>example.com</ex></ph>?
       </message>
+      <message name="IDS_SAVE_PASSWORD_TO_GOOGLE" desc="The title of the save password bubble when the user syncs passswors to thir Google account.">
+        Save password to your Google Account?
+      </message>
+      <message name="IDS_SAVE_ACCOUNT_TO_GOOGLE" desc="The title of the save password bubble when a federated credential can be saved to the user's Google account.">
+        Save username to your Google Account?
+      </message>
       <message name="IDS_SAVE_PASSWORD_FOOTER" desc="The footer text of the bubble that offers user to save a password to Chrome.">
         Passwords are saved in your Google Account so you can use them on any device
       </message>
diff --git a/chrome/app/generated_resources_grd/IDS_SAVE_ACCOUNT_TO_GOOGLE.png.sha1 b/chrome/app/generated_resources_grd/IDS_SAVE_ACCOUNT_TO_GOOGLE.png.sha1
new file mode 100644
index 0000000..69a804d
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_SAVE_ACCOUNT_TO_GOOGLE.png.sha1
@@ -0,0 +1 @@
+d82dbe45f91b7573060266d89e8d5d7a91923458
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_SAVE_PASSWORD_TO_GOOGLE.png.sha1 b/chrome/app/generated_resources_grd/IDS_SAVE_PASSWORD_TO_GOOGLE.png.sha1
new file mode 100644
index 0000000..fe695bb
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_SAVE_PASSWORD_TO_GOOGLE.png.sha1
@@ -0,0 +1 @@
+b53a8f296fc56d2e618e646ced5095d95857fefc
\ No newline at end of file
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd
index dde3d1a..2f8fc8d8 100644
--- a/chrome/app/google_chrome_strings.grd
+++ b/chrome/app/google_chrome_strings.grd
@@ -1105,6 +1105,14 @@
         </message>
       </if>
 
+      <!-- Chrome OS in-session 'Add account' flow -->
+      <if expr="chromeos">
+        <message name="IDS_ACCOUNT_MANAGER_DIALOG_WELCOME_BODY" desc="Text body for the Welcome screen in Chrome OS 'Add account' dialog.">
+          You can manage this and other Google Accounts you've added for <ph name="USER_NAME">$1<ex>John</ex></ph> from one place in <ph name="LINK_BEGIN">&lt;a id="osSettingsLink" href="$2<ex>https://google.com/</ex>"&gt;</ph>Settings<ph name="LINK_END">&lt;/a&gt;</ph>.
+          Permissions you have granted to websites in the Chrome browser and apps from Google Play may apply to all accounts.
+        </message>
+      </if>
+
       <!-- Native notifications for Windows 10 -->
       <if expr="is_win">
         <message name="IDS_WIN_NOTIFICATION_SETTINGS_CONTEXT_MENU_ITEM_NAME" desc="The name of the button in Windows Notification Center which leads to Chrome notification settings.">
diff --git a/chrome/app/google_chrome_strings_grd/IDS_ACCOUNT_MANAGER_DIALOG_WELCOME_BODY.png.sha1 b/chrome/app/google_chrome_strings_grd/IDS_ACCOUNT_MANAGER_DIALOG_WELCOME_BODY.png.sha1
new file mode 100644
index 0000000..91679cc5
--- /dev/null
+++ b/chrome/app/google_chrome_strings_grd/IDS_ACCOUNT_MANAGER_DIALOG_WELCOME_BODY.png.sha1
@@ -0,0 +1 @@
+c4dd21a1e21ef55bd5ef3c9d17df911348efa325
\ No newline at end of file
diff --git a/chrome/app/vector_icons/BUILD.gn b/chrome/app/vector_icons/BUILD.gn
index 50fec4d..d109f38 100644
--- a/chrome/app/vector_icons/BUILD.gn
+++ b/chrome/app/vector_icons/BUILD.gn
@@ -64,7 +64,6 @@
     "keyboard_arrow_right.icon",
     "keyboard_arrow_up.icon",
     "laptop.icon",
-    "live_caption.icon",
     "media_toolbar_button.icon",
     "media_toolbar_button_touch.icon",
     "mixed_content.icon",
diff --git a/chrome/app/vector_icons/live_caption.icon b/chrome/app/vector_icons/live_caption.icon
deleted file mode 100644
index 5962632..0000000
--- a/chrome/app/vector_icons/live_caption.icon
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-CANVAS_DIMENSIONS, 20,
-MOVE_TO, 2, 5.5f,
-CUBIC_TO, 2, 4.67f, 2.67f, 4, 3.5f, 4,
-H_LINE_TO, 16.5f,
-CUBIC_TO, 17.33f, 4, 18, 4.67f, 18, 5.5f,
-V_LINE_TO, 14.5f,
-CUBIC_TO, 18, 15.33f, 17.33f, 16, 16.5f, 16,
-H_LINE_TO, 3.5f,
-CUBIC_TO, 2.67f, 16, 2, 15.33f, 2, 14.5f,
-V_LINE_TO, 5.5f,
-CLOSE,
-MOVE_TO, 4, 6,
-H_LINE_TO, 16,
-V_LINE_TO, 14,
-H_LINE_TO, 4,
-V_LINE_TO, 6,
-CLOSE,
-MOVE_TO, 5, 8,
-H_LINE_TO, 9,
-V_LINE_TO, 10,
-H_LINE_TO, 5,
-V_LINE_TO, 8,
-CLOSE,
-MOVE_TO, 5, 11,
-H_LINE_TO, 12,
-V_LINE_TO, 13,
-H_LINE_TO, 5,
-V_LINE_TO, 11,
-CLOSE,
-MOVE_TO, 15, 11,
-H_LINE_TO, 13,
-V_LINE_TO, 13,
-H_LINE_TO, 15,
-V_LINE_TO, 11,
-CLOSE,
-MOVE_TO, 10, 8,
-H_LINE_TO, 15,
-V_LINE_TO, 10,
-H_LINE_TO, 10,
-V_LINE_TO, 8,
-CLOSE
diff --git a/chrome/browser/OWNERS b/chrome/browser/OWNERS
index 010e6b7..d8d7143 100644
--- a/chrome/browser/OWNERS
+++ b/chrome/browser/OWNERS
@@ -87,9 +87,8 @@
 per-file chrome_back_forward_cache_browsertest.cc=altimin@chromium.org
 per-file chrome_back_forward_cache_browsertest.cc=file://content/OWNERS
 
-# Cross-Origin-Opener-Policy:
-per-file chrome_cross_origin_opener_policy_browsertest.cc=file://content/OWNERS
-per-file chrome_cross_origin_opener_policy_browsertest.cc=arthursonzogni@chromium.org
+# Web Platform security metrics tests:
+per-file chrome_web_platform_security_metrics_browsertest.cc=file://content/OWNERS
 
 # COMPONENT: UI>Browser
 # TEAM: chromium-reviews@chromium.org
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index b2a53ed..ded9b6e 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -461,12 +461,12 @@
 #endif  // OS_ANDROID
 
 #if defined(OS_ANDROID)
-const FeatureEntry::FeatureParam kDismissButtonWithNoThanks[] = {
-    {"dismiss_button", "no_thanks"}};
+const FeatureEntry::FeatureParam kHideDismissButton[] = {
+    {"dismiss_button", "hide"}};
 
 const FeatureEntry::FeatureVariation kMobileIdentityConsistencyVariations[] = {
-    {"Dismiss No Thanks", kDismissButtonWithNoThanks,
-     base::size(kDismissButtonWithNoThanks), nullptr}};
+    {"Hide Dismiss Button", kHideDismissButton, base::size(kHideDismissButton),
+     nullptr}};
 #endif  // OS_ANDROID
 
 #if !defined(OS_CHROMEOS)
@@ -2919,7 +2919,7 @@
         flag_descriptions::kAcceleratedVideoDecodeName,
         flag_descriptions::kAcceleratedVideoDecodeDescription,
         kOsLinux,
-        SINGLE_VALUE_TYPE(switches::kEnableAcceleratedVideoDecode),
+        FEATURE_VALUE_TYPE(media::kVaapiVideoDecodeLinux),
     },
 #else
     {
diff --git a/chrome/browser/autofill/android/personal_data_manager_android.cc b/chrome/browser/autofill/android/personal_data_manager_android.cc
index e9e209d..9d1b0c8 100644
--- a/chrome/browser/autofill/android/personal_data_manager_android.cc
+++ b/chrome/browser/autofill/android/personal_data_manager_android.cc
@@ -61,6 +61,7 @@
 using ::base::android::JavaRef;
 using ::base::android::ScopedJavaGlobalRef;
 using ::base::android::ScopedJavaLocalRef;
+using payments::FullCardRequest;
 
 Profile* GetProfile() {
   return ProfileManager::GetActiveUserProfile()->GetOriginalProfile();
@@ -79,7 +80,7 @@
 
 // Self-deleting requester of full card details, including full PAN and the CVC
 // number.
-class FullCardRequester : public payments::FullCardRequest::ResultDelegate,
+class FullCardRequester : public FullCardRequest::ResultDelegate,
                           public base::SupportsWeakPtr<FullCardRequester> {
  public:
   FullCardRequester() {}
@@ -93,28 +94,28 @@
     jdelegate_.Reset(env, jdelegate);
 
     if (!card_) {
-      OnFullCardRequestFailed();
+      OnFullCardRequestFailed(FullCardRequest::FailureType::GENERIC_FAILURE);
       return;
     }
 
     content::WebContents* contents =
         content::WebContents::FromJavaWebContents(jweb_contents);
     if (!contents) {
-      OnFullCardRequestFailed();
+      OnFullCardRequestFailed(FullCardRequest::FailureType::GENERIC_FAILURE);
       return;
     }
 
     ContentAutofillDriverFactory* factory =
         ContentAutofillDriverFactory::FromWebContents(contents);
     if (!factory) {
-      OnFullCardRequestFailed();
+      OnFullCardRequestFailed(FullCardRequest::FailureType::GENERIC_FAILURE);
       return;
     }
 
     ContentAutofillDriver* driver =
         factory->DriverForFrame(contents->GetMainFrame());
     if (!driver) {
-      OnFullCardRequestFailed();
+      OnFullCardRequestFailed(FullCardRequest::FailureType::GENERIC_FAILURE);
       return;
     }
 
@@ -140,7 +141,8 @@
   }
 
   // payments::FullCardRequest::ResultDelegate:
-  void OnFullCardRequestFailed() override {
+  void OnFullCardRequestFailed(
+      FullCardRequest::FailureType failure_type) override {
     JNIEnv* env = base::android::AttachCurrentThread();
     Java_FullCardRequestDelegate_onFullCardError(env, jdelegate_);
     delete this;
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index f238c3b..9ed123b 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -158,6 +158,7 @@
       <if expr="not is_android">
         <!-- Page not available for guest. -->
         <include name="IDR_PAGE_NOT_AVAILABLE_FOR_GUEST_APP_HTML" file="resources\page_not_available_for_guest\app.html" type="BINDATA" />
+        <!-- In-session login flow -->
         <include name="IDR_INLINE_LOGIN_HTML" file="resources\inline_login\inline_login.html" type="BINDATA" />
         <include name="IDR_INLINE_LOGIN_APP_JS" file="${root_gen_dir}\chrome\browser\resources\inline_login\inline_login_app.js" use_base_dir="false" type ="BINDATA" preprocess="true" />
         <include name="IDR_INLINE_LOGIN_BROWSER_PROXY_JS" file="resources\inline_login\inline_login_browser_proxy.js" type ="BINDATA"/>
@@ -165,6 +166,8 @@
 
       <if expr="chromeos">
         <include name="IDR_CHROME_URLS_DISABLED_PAGE_HTML" file="resources\chromeos\chrome_urls_disabled_page\app.html" type="BINDATA" />
+        <!-- In-session login flow -->
+        <include name="IDR_INLINE_LOGIN_WELCOME_PAGE_APP_JS" file="${root_gen_dir}\chrome\browser\resources\inline_login\welcome_page_app.js" use_base_dir="false" type ="BINDATA" preprocess="true" />
       </if>
 
       <include name="IDR_IDENTITY_API_SCOPE_APPROVAL_MANIFEST" file="resources\identity_scope_approval_dialog\manifest.json" type="BINDATA" />
diff --git a/chrome/browser/chrome_cross_origin_opener_policy_browsertest.cc b/chrome/browser/chrome_cross_origin_opener_policy_browsertest.cc
deleted file mode 100644
index 8ec9cb5..0000000
--- a/chrome/browser/chrome_cross_origin_opener_policy_browsertest.cc
+++ /dev/null
@@ -1,185 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/command_line.h"
-#include "base/test/scoped_feature_list.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "components/network_session_configurator/common/network_switches.h"
-#include "content/public/test/browser_test.h"
-#include "content/public/test/browser_test_utils.h"
-#include "content/public/test/content_browser_test_utils.h"
-#include "net/dns/mock_host_resolver.h"
-#include "net/test/embedded_test_server/embedded_test_server.h"
-#include "services/network/public/cpp/features.h"
-#include "services/network/public/mojom/cross_origin_opener_policy.mojom.h"
-
-#include "content/public/browser/web_contents.h"
-// Cross-Origin-Opener-Policy is a web platform feature implemented by content/.
-// However, since ContentBrowserClientImpl::LogWebFeatureForCurrentPage() is
-// currently left blank in content/, it can't be tested from content/. So it is
-// tested from chrome/ instead.
-class ChromeCrossOriginOpenerPolicyBrowserTest : public InProcessBrowserTest {
- public:
-  ChromeCrossOriginOpenerPolicyBrowserTest() {
-    features_.InitWithFeatures(
-        {
-            // Enabled:
-            network::features::kCrossOriginOpenerPolicy,
-            network::features::kCrossOriginEmbedderPolicy,
-            network::features::kCrossOriginOpenerPolicyReporting,
-        },
-        {});
-  }
-
-  content::WebContents* web_contents() const {
-    return browser()->tab_strip_model()->GetActiveWebContents();
-  }
-
- private:
-  void SetUpOnMainThread() final { host_resolver()->AddRule("*", "127.0.0.1"); }
-
-  void SetUpCommandLine(base::CommandLine* command_line) final {
-    InProcessBrowserTest::SetUpCommandLine(command_line);
-    command_line->AppendSwitch(switches::kIgnoreCertificateErrors);
-  }
-
-  base::test::ScopedFeatureList features_;
-};
-
-// Check the kCrossOriginOpenerPolicyReporting feature usage.
-IN_PROC_BROWSER_TEST_F(ChromeCrossOriginOpenerPolicyBrowserTest,
-                       ReportingUsage) {
-  net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
-  net::EmbeddedTestServer http_server(net::EmbeddedTestServer::TYPE_HTTP);
-  https_server.AddDefaultHandlers(GetChromeTestDataDir());
-  http_server.AddDefaultHandlers(GetChromeTestDataDir());
-  https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_OK);
-  ASSERT_TRUE(https_server.Start());
-  ASSERT_TRUE(http_server.Start());
-
-  int expected_count = 0;
-  base::HistogramTester histogram;
-
-  auto expect_histogram_increased_by = [&](int count) {
-    expected_count += count;
-    histogram.ExpectBucketCount(
-        "Blink.UseCounter.Features",
-        blink::mojom::WebFeature::kCrossOriginOpenerPolicyReporting,
-        expected_count);
-  };
-
-  // No header => 0 count.
-  {
-    GURL url = https_server.GetURL("a.com", "/title1.html");
-    EXPECT_TRUE(content::NavigateToURL(web_contents(), url));
-    expect_histogram_increased_by(0);
-  }
-
-  // COOP-Report-Only + HTTP => 0 count.
-  {
-    GURL url = http_server.GetURL("a.com",
-                                  "/set-header?"
-                                  "Cross-Origin-Opener-Policy-Report-Only: "
-                                  "same-origin; report-to%3d\"a\"");
-    EXPECT_TRUE(content::NavigateToURL(web_contents(), url));
-    expect_histogram_increased_by(0);
-  }
-
-  // COOP-Report-Only + HTTPS => 1 count.
-  {
-    GURL url = https_server.GetURL("a.com",
-                                   "/set-header?"
-                                   "Cross-Origin-Opener-Policy-Report-Only: "
-                                   "same-origin; report-to%3d\"a\"");
-    EXPECT_TRUE(content::NavigateToURL(web_contents(), url));
-    expect_histogram_increased_by(1);
-  }
-
-  // COOP + HTPS => 1 count.
-  {
-    GURL url = https_server.GetURL("a.com",
-                                   "/set-header?"
-                                   "Cross-Origin-Opener-Policy: "
-                                   "same-origin; report-to%3d\"a\"");
-    EXPECT_TRUE(content::NavigateToURL(web_contents(), url));
-    expect_histogram_increased_by(1);
-  }
-
-  // COOP + COOP-RO  + HTTPS => 1 count.
-  {
-    GURL url = https_server.GetURL("a.com",
-                                   "/set-header?"
-                                   "Cross-Origin-Opener-Policy: "
-                                   "same-origin; report-to%3d\"a\"&"
-                                   "Cross-Origin-Opener-Policy-Report-Only: "
-                                   "same-origin; report-to%3d\"a\"");
-    EXPECT_TRUE(content::NavigateToURL(web_contents(), url));
-    expect_histogram_increased_by(1);
-  }
-  // No report endpoints defined => 0 count.
-  {
-    GURL url = https_server.GetURL(
-        "a.com",
-        "/set-header?"
-        "Cross-Origin-Opener-Policy: same-origin&"
-        "Cross-Origin-Opener-Policy-Report-Only: same-origin");
-    EXPECT_TRUE(content::NavigateToURL(web_contents(), url));
-    expect_histogram_increased_by(0);
-  }
-
-  // Main frame (COOP-RO), subframe (COOP-RO) => 1 count.
-  {
-    GURL url = https_server.GetURL("a.com",
-                                   "/set-header?"
-                                   "Cross-Origin-Opener-Policy-Report-Only: "
-                                   "same-origin; report-to%3d\"a\"");
-    EXPECT_TRUE(content::NavigateToURL(web_contents(), url));
-    EXPECT_TRUE(content::ExecJs(web_contents(), content::JsReplace(R"(
-      new Promise(resolve => {
-        let iframe = document.createElement("iframe");
-        iframe.src = $1;
-        iframe.onload = resolve;
-        document.body.appendChild(iframe);
-      });
-    )",
-                                                                   url)));
-    expect_histogram_increased_by(1);
-  }
-
-  // Main frame (no-headers), subframe (COOP-RO) => 0 count.
-  {
-    GURL main_document_url = https_server.GetURL("a.com", "/title1.html");
-    GURL sub_document_url =
-        https_server.GetURL("a.com",
-                            "/set-header?"
-                            "Cross-Origin-Opener-Policy-Report-Only: "
-                            "same-origin; report-to%3d\"a\"");
-    EXPECT_TRUE(content::NavigateToURL(web_contents(), main_document_url));
-    EXPECT_TRUE(
-        content::ExecJs(web_contents(), content::JsReplace(R"(
-      new Promise(resolve => {
-        let iframe = document.createElement("iframe");
-        iframe.src = $1;
-        iframe.onload = resolve;
-        document.body.appendChild(iframe);
-      });
-    )",
-                                                           sub_document_url)));
-    expect_histogram_increased_by(0);
-  }
-}
-
-// TODO(arthursonzogni): Add basic test(s) for the WebFeatures:
-// - CrossOriginOpenerPolicySameOrigin
-// - CrossOriginOpenerPolicySameOriginAllowPopups
-// - CrossOriginEmbedderPolicyRequireCorp
-// - CoopAndCoepIsolated
-//
-// Added by:
-// https://chromium-review.googlesource.com/c/chromium/src/+/2122140
-//
-// In particular, it would be interesting knowing what happens with iframes?
-// Are CoopCoepOriginIsolated nested document counted as CoopAndCoepIsolated?
-// Not doing it would underestimate the usage metric.
diff --git a/chrome/browser/chrome_web_platform_security_metrics_browsertest.cc b/chrome/browser/chrome_web_platform_security_metrics_browsertest.cc
new file mode 100644
index 0000000..09d05d0
--- /dev/null
+++ b/chrome/browser/chrome_web_platform_security_metrics_browsertest.cc
@@ -0,0 +1,294 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/command_line.h"
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "components/network_session_configurator/common/network_switches.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "services/network/public/cpp/features.h"
+#include "services/network/public/mojom/cross_origin_opener_policy.mojom.h"
+
+// Web platform security features are implemented by content/ and blink/.
+// However, since ContentBrowserClientImpl::LogWebFeatureForCurrentPage() is
+// currently left blank in content/, metrics logging can't be tested from
+// content/. So it is tested from chrome/ instead.
+class ChromeWebPlatformSecurityMetricsBrowserTest
+    : public InProcessBrowserTest {
+ public:
+  ChromeWebPlatformSecurityMetricsBrowserTest()
+      : https_server_(net::EmbeddedTestServer::TYPE_HTTPS),
+        http_server_(net::EmbeddedTestServer::TYPE_HTTP) {
+    features_.InitWithFeatures(
+        {
+            // Enabled:
+            network::features::kCrossOriginOpenerPolicy,
+            network::features::kCrossOriginEmbedderPolicy,
+            network::features::kCrossOriginOpenerPolicyReporting,
+        },
+        {});
+  }
+
+  content::WebContents* web_contents() const {
+    return browser()->tab_strip_model()->GetActiveWebContents();
+  }
+
+  void set_monitored_feature(blink::mojom::WebFeature feature) {
+    monitored_feature_ = feature;
+  }
+
+  void LoadIFrame(const GURL& url) {
+    EXPECT_TRUE(content::ExecJs(web_contents(), content::JsReplace(R"(
+      new Promise(resolve => {
+        let iframe = document.createElement("iframe");
+        iframe.src = $1;
+        iframe.onload = resolve;
+        document.body.appendChild(iframe);
+      });
+    )",
+                                                                   url)));
+  }
+
+  void ExpectHistogramIncreasedBy(int count) {
+    expected_count_ += count;
+    EXPECT_TRUE(content::NavigateToURL(web_contents(), GURL("about:blank")));
+    histogram_.ExpectBucketCount("Blink.UseCounter.Features",
+                                 monitored_feature_, expected_count_);
+  }
+
+  net::EmbeddedTestServer& https_server() { return https_server_; }
+  net::EmbeddedTestServer& http_server() { return http_server_; }
+
+ private:
+  void SetUpOnMainThread() final {
+    host_resolver()->AddRule("*", "127.0.0.1");
+    https_server_.AddDefaultHandlers(GetChromeTestDataDir());
+    http_server_.AddDefaultHandlers(GetChromeTestDataDir());
+    https_server_.SetSSLConfig(net::EmbeddedTestServer::CERT_OK);
+    ASSERT_TRUE(https_server_.Start());
+    ASSERT_TRUE(http_server_.Start());
+    EXPECT_TRUE(content::NavigateToURL(web_contents(), GURL("about:blank")));
+  }
+
+  void SetUpCommandLine(base::CommandLine* command_line) final {
+    InProcessBrowserTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitch(switches::kIgnoreCertificateErrors);
+  }
+
+  net::EmbeddedTestServer https_server_;
+  net::EmbeddedTestServer http_server_;
+  int expected_count_ = 0;
+  base::HistogramTester histogram_;
+  blink::mojom::WebFeature monitored_feature_;
+  base::test::ScopedFeatureList features_;
+};
+
+// Check the kCrossOriginOpenerPolicyReporting feature usage. No header => 0
+// count.
+IN_PROC_BROWSER_TEST_F(ChromeWebPlatformSecurityMetricsBrowserTest,
+                       CrossOriginOpenerPolicyReportingNoHeader) {
+  set_monitored_feature(
+      blink::mojom::WebFeature::kCrossOriginOpenerPolicyReporting);
+  GURL url = https_server().GetURL("a.com", "/title1.html");
+  EXPECT_TRUE(content::NavigateToURL(web_contents(), url));
+  ExpectHistogramIncreasedBy(0);
+}
+
+// Check the kCrossOriginOpenerPolicyReporting feature usage. COOP-Report-Only +
+// HTTP => 0 count.
+IN_PROC_BROWSER_TEST_F(ChromeWebPlatformSecurityMetricsBrowserTest,
+                       CrossOriginOpenerPolicyReportingReportOnlyHTTP) {
+  set_monitored_feature(
+      blink::mojom::WebFeature::kCrossOriginOpenerPolicyReporting);
+  GURL url = http_server().GetURL("a.com",
+                                  "/set-header?"
+                                  "Cross-Origin-Opener-Policy-Report-Only: "
+                                  "same-origin; report-to%3d\"a\"");
+  EXPECT_TRUE(content::NavigateToURL(web_contents(), url));
+  ExpectHistogramIncreasedBy(0);
+}
+
+// Check the kCrossOriginOpenerPolicyReporting feature usage. COOP-Report-Only +
+// HTTPS => 1 count.
+IN_PROC_BROWSER_TEST_F(ChromeWebPlatformSecurityMetricsBrowserTest,
+                       CrossOriginOpenerPolicyReportingReportOnlyHTTPS) {
+  set_monitored_feature(
+      blink::mojom::WebFeature::kCrossOriginOpenerPolicyReporting);
+  GURL url = https_server().GetURL("a.com",
+                                   "/set-header?"
+                                   "Cross-Origin-Opener-Policy-Report-Only: "
+                                   "same-origin; report-to%3d\"a\"");
+  EXPECT_TRUE(content::NavigateToURL(web_contents(), url));
+  ExpectHistogramIncreasedBy(1);
+}
+
+// Check the kCrossOriginOpenerPolicyReporting feature usage. COOP + HTPS => 1
+// count.
+IN_PROC_BROWSER_TEST_F(ChromeWebPlatformSecurityMetricsBrowserTest,
+                       CrossOriginOpenerPolicyReportingCOOPHTTPS) {
+  set_monitored_feature(
+      blink::mojom::WebFeature::kCrossOriginOpenerPolicyReporting);
+  GURL url = https_server().GetURL("a.com",
+                                   "/set-header?"
+                                   "Cross-Origin-Opener-Policy: "
+                                   "same-origin; report-to%3d\"a\"");
+  EXPECT_TRUE(content::NavigateToURL(web_contents(), url));
+  ExpectHistogramIncreasedBy(1);
+}
+
+// Check the kCrossOriginOpenerPolicyReporting feature usage. COOP + COOP-RO  +
+// HTTPS => 1 count.
+IN_PROC_BROWSER_TEST_F(ChromeWebPlatformSecurityMetricsBrowserTest,
+                       CrossOriginOpenerPolicyReportingCOOPAndReportOnly) {
+  set_monitored_feature(
+      blink::mojom::WebFeature::kCrossOriginOpenerPolicyReporting);
+  GURL url = https_server().GetURL("a.com",
+                                   "/set-header?"
+                                   "Cross-Origin-Opener-Policy: "
+                                   "same-origin; report-to%3d\"a\"&"
+                                   "Cross-Origin-Opener-Policy-Report-Only: "
+                                   "same-origin; report-to%3d\"a\"");
+  EXPECT_TRUE(content::NavigateToURL(web_contents(), url));
+  ExpectHistogramIncreasedBy(1);
+}
+
+// Check the kCrossOriginOpenerPolicyReporting feature usage. No report
+// endpoints defined => 0 count.
+IN_PROC_BROWSER_TEST_F(ChromeWebPlatformSecurityMetricsBrowserTest,
+                       CrossOriginOpenerPolicyReportingNoEndpoint) {
+  set_monitored_feature(
+      blink::mojom::WebFeature::kCrossOriginOpenerPolicyReporting);
+  GURL url = https_server().GetURL(
+      "a.com",
+      "/set-header?"
+      "Cross-Origin-Opener-Policy: same-origin&"
+      "Cross-Origin-Opener-Policy-Report-Only: same-origin");
+  EXPECT_TRUE(content::NavigateToURL(web_contents(), url));
+  ExpectHistogramIncreasedBy(0);
+}
+
+// Check the kCrossOriginOpenerPolicyReporting feature usage. Main frame
+// (COOP-RO), subframe (COOP-RO) => 1 count.
+IN_PROC_BROWSER_TEST_F(ChromeWebPlatformSecurityMetricsBrowserTest,
+                       CrossOriginOpenerPolicyReportingMainFrameAndSubframe) {
+  set_monitored_feature(
+      blink::mojom::WebFeature::kCrossOriginOpenerPolicyReporting);
+  GURL url = https_server().GetURL("a.com",
+                                   "/set-header?"
+                                   "Cross-Origin-Opener-Policy-Report-Only: "
+                                   "same-origin; report-to%3d\"a\"");
+  EXPECT_TRUE(content::NavigateToURL(web_contents(), url));
+  LoadIFrame(url);
+  ExpectHistogramIncreasedBy(1);
+}
+
+// Check the kCrossOriginOpenerPolicyReporting feature usage. Main frame
+// (no-headers), subframe (COOP-RO) => 0 count.
+IN_PROC_BROWSER_TEST_F(ChromeWebPlatformSecurityMetricsBrowserTest,
+                       CrossOriginOpenerPolicyReportingUsageSubframeOnly) {
+  set_monitored_feature(
+      blink::mojom::WebFeature::kCrossOriginOpenerPolicyReporting);
+  GURL main_document_url = https_server().GetURL("a.com", "/title1.html");
+  GURL sub_document_url =
+      https_server().GetURL("a.com",
+                            "/set-header?"
+                            "Cross-Origin-Opener-Policy-Report-Only: "
+                            "same-origin; report-to%3d\"a\"");
+  EXPECT_TRUE(content::NavigateToURL(web_contents(), main_document_url));
+  LoadIFrame(sub_document_url);
+  ExpectHistogramIncreasedBy(0);
+}
+
+// Check kCrossOriginSubframeWithoutEmbeddingControl reporting. Same-origin
+// iframe (no headers) => 0 count.
+IN_PROC_BROWSER_TEST_F(ChromeWebPlatformSecurityMetricsBrowserTest,
+                       CrossOriginSubframeWithoutEmbeddingControlSameOrigin) {
+  set_monitored_feature(
+      blink::mojom::WebFeature::kCrossOriginSubframeWithoutEmbeddingControl);
+  GURL url = https_server().GetURL("a.com", "/title1.html");
+  EXPECT_TRUE(content::NavigateToURL(web_contents(), url));
+  LoadIFrame(url);
+  ExpectHistogramIncreasedBy(0);
+}
+
+// Check kCrossOriginSubframeWithoutEmbeddingControl reporting. Cross-origin
+// iframe (no headers) => 0 count.
+IN_PROC_BROWSER_TEST_F(ChromeWebPlatformSecurityMetricsBrowserTest,
+                       CrossOriginSubframeWithoutEmbeddingControlNoHeaders) {
+  set_monitored_feature(
+      blink::mojom::WebFeature::kCrossOriginSubframeWithoutEmbeddingControl);
+  GURL main_document_url = https_server().GetURL("a.com", "/title1.html");
+  GURL sub_document_url = https_server().GetURL("b.com", "/title1.html");
+  EXPECT_TRUE(content::NavigateToURL(web_contents(), main_document_url));
+  LoadIFrame(sub_document_url);
+  ExpectHistogramIncreasedBy(1);
+}
+
+// Check kCrossOriginSubframeWithoutEmbeddingControl reporting. Cross-origin
+// iframe (CSP frame-ancestors) => 0 count.
+IN_PROC_BROWSER_TEST_F(
+    ChromeWebPlatformSecurityMetricsBrowserTest,
+    CrossOriginSubframeWithoutEmbeddingControlFrameAncestors) {
+  set_monitored_feature(
+      blink::mojom::WebFeature::kCrossOriginSubframeWithoutEmbeddingControl);
+  GURL main_document_url = https_server().GetURL("a.com", "/title1.html");
+  url::Origin main_document_origin = url::Origin::Create(main_document_url);
+  std::string csp_header = "Content-Security-Policy: frame-ancestors 'self' *;";
+  GURL sub_document_url =
+      https_server().GetURL("b.com", "/set-header?" + csp_header);
+  EXPECT_TRUE(content::NavigateToURL(web_contents(), main_document_url));
+  LoadIFrame(sub_document_url);
+  ExpectHistogramIncreasedBy(0);
+}
+
+// Check kCrossOriginSubframeWithoutEmbeddingControl reporting. Cross-origin
+// iframe (blocked by CSP header) => 0 count.
+IN_PROC_BROWSER_TEST_F(ChromeWebPlatformSecurityMetricsBrowserTest,
+                       CrossOriginSubframeWithoutEmbeddingControlNoEmbedding) {
+  set_monitored_feature(
+      blink::mojom::WebFeature::kCrossOriginSubframeWithoutEmbeddingControl);
+  GURL main_document_url = https_server().GetURL("a.com", "/title1.html");
+  GURL sub_document_url =
+      https_server().GetURL("b.com",
+                            "/set-header?"
+                            "Content-Security-Policy: frame-ancestors 'self';");
+  EXPECT_TRUE(content::NavigateToURL(web_contents(), main_document_url));
+  LoadIFrame(sub_document_url);
+  ExpectHistogramIncreasedBy(0);
+}
+
+// Check kCrossOriginSubframeWithoutEmbeddingControl reporting. Cross-origin
+// iframe (other CSP header) => 1 count.
+IN_PROC_BROWSER_TEST_F(ChromeWebPlatformSecurityMetricsBrowserTest,
+                       CrossOriginSubframeWithoutEmbeddingControlOtherCSP) {
+  set_monitored_feature(
+      blink::mojom::WebFeature::kCrossOriginSubframeWithoutEmbeddingControl);
+  GURL main_document_url = https_server().GetURL("a.com", "/title1.html");
+  GURL sub_document_url =
+      https_server().GetURL("b.com",
+                            "/set-header?"
+                            "Content-Security-Policy: script-src 'self';");
+  EXPECT_TRUE(content::NavigateToURL(web_contents(), main_document_url));
+  LoadIFrame(sub_document_url);
+  ExpectHistogramIncreasedBy(1);
+}
+
+// TODO(arthursonzogni): Add basic test(s) for the WebFeatures:
+// - CrossOriginOpenerPolicySameOrigin
+// - CrossOriginOpenerPolicySameOriginAllowPopups
+// - CrossOriginEmbedderPolicyRequireCorp
+// - CoopAndCoepIsolated
+//
+// Added by:
+// https://chromium-review.googlesource.com/c/chromium/src/+/2122140
+//
+// In particular, it would be interesting knowing what happens with iframes?
+// Are CoopCoepOriginIsolated nested document counted as CoopAndCoepIsolated?
+// Not doing it would underestimate the usage metric.
diff --git a/chrome/browser/chromeos/arc/arc_optin_uma.cc b/chrome/browser/chromeos/arc/arc_optin_uma.cc
index 68d75f0..0f82375 100644
--- a/chrome/browser/chromeos/arc/arc_optin_uma.cc
+++ b/chrome/browser/chromeos/arc/arc_optin_uma.cc
@@ -75,11 +75,11 @@
   base::UmaHistogramEnumeration("Arc.OptInResult", result);
 }
 
-void UpdateProvisioningResultUMA(ProvisioningResultUMA result,
+void UpdateProvisioningStatusUMA(ProvisioningStatus status,
                                  const Profile* profile) {
-  DCHECK_NE(result, ProvisioningResultUMA::CHROME_SERVER_COMMUNICATION_ERROR);
+  DCHECK_NE(status, ProvisioningStatus::CHROME_SERVER_COMMUNICATION_ERROR);
   base::UmaHistogramEnumeration(
-      GetHistogramNameByUserType("Arc.Provisioning.Result", profile), result);
+      GetHistogramNameByUserType("Arc.Provisioning.Status", profile), status);
 }
 
 void UpdateCloudProvisionFlowErrorUMA(mojom::CloudProvisionFlowError error,
@@ -89,8 +89,22 @@
       error);
 }
 
-void UpdateSecondarySigninResultUMA(ProvisioningResultUMA result) {
-  base::UmaHistogramEnumeration("Arc.Secondary.Signin.Result", result);
+void UpdateGMSSignInErrorUMA(mojom::GMSSignInError error,
+                             const Profile* profile) {
+  base::UmaHistogramEnumeration(
+      GetHistogramNameByUserType("Arc.Provisioning.SignInError", profile),
+      error);
+}
+
+void UpdateGMSCheckInErrorUMA(mojom::GMSCheckInError error,
+                              const Profile* profile) {
+  base::UmaHistogramEnumeration(
+      GetHistogramNameByUserType("Arc.Provisioning.CheckInError", profile),
+      error);
+}
+
+void UpdateSecondarySigninResultUMA(ProvisioningStatus status) {
+  base::UmaHistogramEnumeration("Arc.Secondary.Signin.Result", status);
 }
 
 void UpdateProvisioningTiming(const base::TimeDelta& elapsed_time,
@@ -106,11 +120,11 @@
       base::TimeDelta::FromSeconds(1), base::TimeDelta::FromMinutes(6), 50);
 }
 
-void UpdateReauthorizationResultUMA(ProvisioningResultUMA result,
+void UpdateReauthorizationResultUMA(ProvisioningStatus status,
                                     const Profile* profile) {
   base::UmaHistogramEnumeration(
       GetHistogramNameByUserType("Arc.Reauthorization.Result", profile),
-      result);
+      status);
 }
 
 void UpdatePlayAutoInstallRequestState(mojom::PaiFlowState state,
@@ -206,29 +220,31 @@
                            static_cast<int>(state));
 }
 
-ProvisioningResultUMA GetProvisioningResultUMA(
+ProvisioningStatus GetProvisioningStatus(
     const ArcProvisioningResult& provisioning_result) {
   if (provisioning_result.is_stopped())
-    return ProvisioningResultUMA::ARC_STOPPED;
+    return ProvisioningStatus::ARC_STOPPED;
 
   if (provisioning_result.is_timedout())
-    return ProvisioningResultUMA::OVERALL_SIGN_IN_TIMEOUT;
+    return ProvisioningStatus::CHROME_PROVISIONING_TIMEOUT;
 
   const mojom::ArcSignInResult* result = provisioning_result.sign_in_result();
-  if (result->is_success()) {
-    if (result->get_success() == mojom::ArcSignInSuccess::SUCCESS)
-      return ProvisioningResultUMA::SUCCESS;
-    else
-      return ProvisioningResultUMA::SUCCESS_ALREADY_PROVISIONED;
-  }
+  if (result->is_success())
+    return ProvisioningStatus::SUCCESS;
 
   if (result->get_error()->is_cloud_provision_flow_error())
-    return ProvisioningResultUMA::CLOUD_PROVISION_FLOW_ERROR;
+    return ProvisioningStatus::CLOUD_PROVISION_FLOW_ERROR;
+
+  if (result->get_error()->is_check_in_error())
+    return ProvisioningStatus::GMS_CHECK_IN_ERROR;
+
+  if (result->get_error()->is_sign_in_error())
+    return ProvisioningStatus::GMS_SIGN_IN_ERROR;
 
   if (result->get_error()->is_general_error()) {
 #define MAP_GENERAL_ERROR(name)         \
   case mojom::GeneralSignInError::name: \
-    return ProvisioningResultUMA::name
+    return ProvisioningStatus::name
 
     switch (result->get_error()->get_general_error()) {
       MAP_GENERAL_ERROR(UNKNOWN_ERROR);
@@ -243,75 +259,37 @@
 #undef MAP_GENERAL_ERROR
   }
 
-  if (result->get_error()->is_check_in_error()) {
-#define MAP_CHECKIN_ERROR(name)      \
-  case mojom::GMSCheckInError::name: \
-    return ProvisioningResultUMA::name
-
-    switch (result->get_error()->get_check_in_error()) {
-      MAP_CHECKIN_ERROR(GMS_CHECK_IN_FAILED);
-      MAP_CHECKIN_ERROR(GMS_CHECK_IN_TIMEOUT);
-      MAP_CHECKIN_ERROR(GMS_CHECK_IN_INTERNAL_ERROR);
-    }
-#undef MAP_CHECKIN_ERROR
-  }
-
-  if (result->get_error()->is_sign_in_error()) {
-#define MAP_GMS_ERROR(name)         \
-  case mojom::GMSSignInError::name: \
-    return ProvisioningResultUMA::name
-
-    switch (result->get_error()->get_sign_in_error()) {
-      MAP_GMS_ERROR(GMS_SIGN_IN_NETWORK_ERROR);
-      MAP_GMS_ERROR(GMS_SIGN_IN_SERVICE_UNAVAILABLE);
-      MAP_GMS_ERROR(GMS_SIGN_IN_BAD_AUTHENTICATION);
-      MAP_GMS_ERROR(GMS_SIGN_IN_FAILED);
-      MAP_GMS_ERROR(GMS_SIGN_IN_TIMEOUT);
-      MAP_GMS_ERROR(GMS_SIGN_IN_INTERNAL_ERROR);
-    }
-#undef MAP_GMS_ERROR
-  }
-
-  NOTREACHED() << "unknown sign result";
-  return ProvisioningResultUMA::UNKNOWN_ERROR;
+  NOTREACHED() << "unexpected provisioning result";
+  return ProvisioningStatus::UNKNOWN_ERROR;
 }
 
-std::ostream& operator<<(std::ostream& os,
-                         const ProvisioningResultUMA& result) {
+std::ostream& operator<<(std::ostream& os, const ProvisioningStatus& status) {
 #define MAP_PROVISIONING_RESULT(name) \
-  case ProvisioningResultUMA::name:   \
+  case ProvisioningStatus::name:      \
     return os << #name
 
-  switch (result) {
+  switch (status) {
     MAP_PROVISIONING_RESULT(SUCCESS);
     MAP_PROVISIONING_RESULT(UNKNOWN_ERROR);
-    MAP_PROVISIONING_RESULT(GMS_SIGN_IN_NETWORK_ERROR);
-    MAP_PROVISIONING_RESULT(GMS_SIGN_IN_SERVICE_UNAVAILABLE);
-    MAP_PROVISIONING_RESULT(GMS_SIGN_IN_BAD_AUTHENTICATION);
-    MAP_PROVISIONING_RESULT(GMS_CHECK_IN_FAILED);
+    MAP_PROVISIONING_RESULT(GMS_SIGN_IN_ERROR);
+    MAP_PROVISIONING_RESULT(GMS_CHECK_IN_ERROR);
+    MAP_PROVISIONING_RESULT(CLOUD_PROVISION_FLOW_ERROR);
     MAP_PROVISIONING_RESULT(MOJO_VERSION_MISMATCH);
     MAP_PROVISIONING_RESULT(GENERIC_PROVISIONING_TIMEOUT);
-    MAP_PROVISIONING_RESULT(GMS_CHECK_IN_TIMEOUT);
-    MAP_PROVISIONING_RESULT(GMS_CHECK_IN_INTERNAL_ERROR);
-    MAP_PROVISIONING_RESULT(GMS_SIGN_IN_FAILED);
-    MAP_PROVISIONING_RESULT(GMS_SIGN_IN_TIMEOUT);
-    MAP_PROVISIONING_RESULT(GMS_SIGN_IN_INTERNAL_ERROR);
+    MAP_PROVISIONING_RESULT(CHROME_PROVISIONING_TIMEOUT);
     MAP_PROVISIONING_RESULT(ARC_STOPPED);
-    MAP_PROVISIONING_RESULT(OVERALL_SIGN_IN_TIMEOUT);
+    MAP_PROVISIONING_RESULT(ARC_DISABLED);
     MAP_PROVISIONING_RESULT(CHROME_SERVER_COMMUNICATION_ERROR);
     MAP_PROVISIONING_RESULT(NO_NETWORK_CONNECTION);
-    MAP_PROVISIONING_RESULT(ARC_DISABLED);
-    MAP_PROVISIONING_RESULT(SUCCESS_ALREADY_PROVISIONED);
     MAP_PROVISIONING_RESULT(UNSUPPORTED_ACCOUNT_TYPE);
     MAP_PROVISIONING_RESULT(CHROME_ACCOUNT_NOT_FOUND);
-    MAP_PROVISIONING_RESULT(CLOUD_PROVISION_FLOW_ERROR);
   }
 
 #undef MAP_PROVISIONING_RESULT
 
   // Some compilers report an error even if all values of an enum-class are
   // covered exhaustively in a switch statement.
-  NOTREACHED() << "Invalid value " << static_cast<int>(result);
+  NOTREACHED() << "Invalid value " << static_cast<int>(status);
   return os;
 }
 
diff --git a/chrome/browser/chromeos/arc/arc_optin_uma.h b/chrome/browser/chromeos/arc/arc_optin_uma.h
index 17aa45e..724a5f0 100644
--- a/chrome/browser/chromeos/arc/arc_optin_uma.h
+++ b/chrome/browser/chromeos/arc/arc_optin_uma.h
@@ -103,70 +103,54 @@
 };
 
 // The values should be listed in ascending order. They are also persisted to
-// logs, and their values should therefore never be renumbered nor reused. For
-// detailed meaning, please consult auth.mojom.
-enum class ProvisioningResultUMA : int {
-  // Provisioning was successful. Note, SUCCESS_ALREADY_PROVISIONED is also
-  // successful state.
+// logs, and their values should therefore never be renumbered nor reused.
+enum class ProvisioningStatus {
+  // Provisioning was successful.
   SUCCESS = 0,
 
   // Unclassified failure.
   UNKNOWN_ERROR = 1,
 
-  // GMS errors. More errors defined below.
-  GMS_SIGN_IN_NETWORK_ERROR = 2,
-  GMS_SIGN_IN_SERVICE_UNAVAILABLE = 3,
-  GMS_SIGN_IN_BAD_AUTHENTICATION = 4,
-
-  // Check in error. More errors defined below.
-  GMS_CHECK_IN_FAILED = 5,
-
-  // Mojo errors.
-  MOJO_VERSION_MISMATCH = 7,
-
-  // ARC did not finish provisioning within a reasonable amount of time.
-  GENERIC_PROVISIONING_TIMEOUT = 8,
+  // Unmanaged sign-in error.
+  GMS_SIGN_IN_ERROR = 2,
 
   // Check in error.
-  GMS_CHECK_IN_TIMEOUT = 9,
-  GMS_CHECK_IN_INTERNAL_ERROR = 10,
+  GMS_CHECK_IN_ERROR = 3,
 
-  // GMS errors:
-  GMS_SIGN_IN_FAILED = 11,
-  GMS_SIGN_IN_TIMEOUT = 12,
-  GMS_SIGN_IN_INTERNAL_ERROR = 13,
+  // Managed sign-in error.
+  CLOUD_PROVISION_FLOW_ERROR = 4,
+
+  // Mojo errors.
+  MOJO_VERSION_MISMATCH = 5,
+
+  // ARC did not finish provisioning within a reasonable amount of time.
+  GENERIC_PROVISIONING_TIMEOUT = 6,
+
+  // ARC instance did not report provisioning status within a reasonable amount
+  // of time.
+  CHROME_PROVISIONING_TIMEOUT = 7,
 
   // ARC instance is stopped during the sign in procedure.
-  ARC_STOPPED = 16,
+  ARC_STOPPED = 8,
 
-  // ARC instance did not report sign in status within a reasonable amount of
-  // time.
-  OVERALL_SIGN_IN_TIMEOUT = 17,
+  // ARC is not enabled.
+  ARC_DISABLED = 9,
 
   // In Chrome, server communication error occurs.
   // For backward compatibility, the UMA is handled differently. Please see
   // ArcSessionManager::OnProvisioningFinished for details.
-  CHROME_SERVER_COMMUNICATION_ERROR = 18,
+  CHROME_SERVER_COMMUNICATION_ERROR = 10,
 
   // Network connection is unavailable in ARC.
-  NO_NETWORK_CONNECTION = 19,
-
-  // ARC is not enabled.
-  ARC_DISABLED = 20,
-
-  // Device was already provisioned.
-  SUCCESS_ALREADY_PROVISIONED = 21,
+  NO_NETWORK_CONNECTION = 11,
 
   // Account type is not supported for authorization.
-  UNSUPPORTED_ACCOUNT_TYPE = 22,
+  UNSUPPORTED_ACCOUNT_TYPE = 12,
 
   // Account is not present in Chrome OS Account Manager.
-  CHROME_ACCOUNT_NOT_FOUND = 23,
+  CHROME_ACCOUNT_NOT_FOUND = 13,
 
-  // Top level error for cloud DPC failure.
-  CLOUD_PROVISION_FLOW_ERROR = 24,
-
-  kMaxValue = CLOUD_PROVISION_FLOW_ERROR,
+  kMaxValue = CHROME_ACCOUNT_NOT_FOUND,
 };
 
 enum class OptInFlowResult : int {
@@ -226,15 +210,19 @@
 void UpdateOptInActionUMA(OptInActionType type);
 void UpdateOptInCancelUMA(OptInCancelReason reason);
 void UpdateOptInFlowResultUMA(OptInFlowResult result);
-void UpdateProvisioningResultUMA(ProvisioningResultUMA result,
+void UpdateProvisioningStatusUMA(ProvisioningStatus status,
                                  const Profile* profile);
 void UpdateCloudProvisionFlowErrorUMA(mojom::CloudProvisionFlowError error,
                                       const Profile* profile);
-void UpdateSecondarySigninResultUMA(ProvisioningResultUMA result);
+void UpdateGMSSignInErrorUMA(mojom::GMSSignInError error,
+                             const Profile* profile);
+void UpdateGMSCheckInErrorUMA(mojom::GMSCheckInError error,
+                              const Profile* profile);
+void UpdateSecondarySigninResultUMA(ProvisioningStatus status);
 void UpdateProvisioningTiming(const base::TimeDelta& elapsed_time,
                               bool success,
                               const Profile* profile);
-void UpdateReauthorizationResultUMA(ProvisioningResultUMA result,
+void UpdateReauthorizationResultUMA(ProvisioningStatus status,
                                     const Profile* profile);
 void UpdatePlayAutoInstallRequestState(mojom::PaiFlowState state,
                                        const Profile* profile);
@@ -266,11 +254,11 @@
 // Returns the enum for use in UMA stat and displaying error code on the UI.
 // This enum should not be used anywhere else. Please work with the object
 // instead.
-ProvisioningResultUMA GetProvisioningResultUMA(
+ProvisioningStatus GetProvisioningStatus(
     const ArcProvisioningResult& provisioning_result);
 
 // Outputs the stringified |result| to |os|. This is only for logging purposes.
-std::ostream& operator<<(std::ostream& os, const ProvisioningResultUMA& result);
+std::ostream& operator<<(std::ostream& os, const ProvisioningStatus& status);
 
 }  // namespace arc
 
diff --git a/chrome/browser/chromeos/arc/auth/arc_auth_service.cc b/chrome/browser/chromeos/arc/auth/arc_auth_service.cc
index b2e693c..c3999d98 100644
--- a/chrome/browser/chromeos/arc/auth/arc_auth_service.cc
+++ b/chrome/browser/chromeos/arc/auth/arc_auth_service.cc
@@ -326,8 +326,7 @@
     return;
   }
 
-  ProvisioningResultUMA provisioning_result_enum =
-      GetProvisioningResultUMA(provisioning_result);
+  const ProvisioningStatus status = GetProvisioningStatus(provisioning_result);
 
   if (!account->is_account_name() || !account->get_account_name() ||
       account->get_account_name().value().empty() ||
@@ -337,11 +336,9 @@
     // The check for |!account_name.has_value()| is for backwards compatibility
     // with older ARC versions, for which Mojo will set |account_name| to
     // empty/null.
-    DCHECK_NE(ProvisioningResultUMA::SUCCESS_ALREADY_PROVISIONED,
-              provisioning_result_enum);
-    UpdateReauthorizationResultUMA(provisioning_result_enum, profile_);
+    UpdateReauthorizationResultUMA(status, profile_);
   } else {
-    UpdateSecondarySigninResultUMA(provisioning_result_enum);
+    UpdateSecondarySigninResultUMA(status);
   }
 }
 
diff --git a/chrome/browser/chromeos/arc/session/arc_provisioning_result.cc b/chrome/browser/chromeos/arc/session/arc_provisioning_result.cc
index 309120e..74e21c9 100644
--- a/chrome/browser/chromeos/arc/session/arc_provisioning_result.cc
+++ b/chrome/browser/chromeos/arc/session/arc_provisioning_result.cc
@@ -62,7 +62,7 @@
 
 std::ostream& operator<<(std::ostream& os,
                          const ArcProvisioningResult& result) {
-  return os << GetProvisioningResultUMA(result);
+  return os << GetProvisioningStatus(result);
 }
 
 }  // namespace arc
diff --git a/chrome/browser/chromeos/arc/session/arc_provisioning_result.h b/chrome/browser/chromeos/arc/session/arc_provisioning_result.h
index 3fc6931..2a1d02a4 100644
--- a/chrome/browser/chromeos/arc/session/arc_provisioning_result.h
+++ b/chrome/browser/chromeos/arc/session/arc_provisioning_result.h
@@ -11,7 +11,7 @@
 #include "components/arc/session/arc_stop_reason.h"
 #include "third_party/abseil-cpp/absl/types/variant.h"
 
-enum class ProvisioningResultUMA : int;
+enum class ProvisioningStatus;
 
 namespace arc {
 
diff --git a/chrome/browser/chromeos/arc/session/arc_session_manager.cc b/chrome/browser/chromeos/arc/session/arc_session_manager.cc
index b61980e..14d013e 100644
--- a/chrome/browser/chromeos/arc/session/arc_session_manager.cc
+++ b/chrome/browser/chromeos/arc/session/arc_session_manager.cc
@@ -624,10 +624,17 @@
 
     UpdateProvisioningTiming(base::TimeTicks::Now() - sign_in_start_time_,
                              provisioning_successful, profile_);
-    UpdateProvisioningResultUMA(GetProvisioningResultUMA(result), profile_);
-    if (sign_in_error && sign_in_error->is_cloud_provision_flow_error()) {
-      UpdateCloudProvisionFlowErrorUMA(
-          sign_in_error->get_cloud_provision_flow_error(), profile_);
+    UpdateProvisioningStatusUMA(GetProvisioningStatus(result), profile_);
+
+    if (sign_in_error) {
+      if (sign_in_error->is_cloud_provision_flow_error()) {
+        UpdateCloudProvisionFlowErrorUMA(
+            sign_in_error->get_cloud_provision_flow_error(), profile_);
+      } else if (sign_in_error->is_sign_in_error()) {
+        UpdateGMSSignInErrorUMA(sign_in_error->get_sign_in_error(), profile_);
+      } else if (sign_in_error->is_check_in_error()) {
+        UpdateGMSCheckInErrorUMA(sign_in_error->get_check_in_error(), profile_);
+      }
     }
 
     if (!provisioning_successful)
@@ -727,8 +734,8 @@
 
   base::Optional<int> error_code;
   if (support_error == ArcSupportHost::Error::SIGN_IN_UNKNOWN_ERROR) {
-    error_code = static_cast<std::underlying_type_t<ProvisioningResultUMA>>(
-        GetProvisioningResultUMA(result));
+    error_code = static_cast<std::underlying_type_t<ProvisioningStatus>>(
+        GetProvisioningStatus(result));
   } else if (sign_in_error) {
     error_code = GetSignInErrorCode(sign_in_error);
   }
@@ -1250,8 +1257,8 @@
 
   // State::STOPPED appears here in following scenario.
   // Initial provisioning finished with state
-  // ProvisioningResultUMA::ArcStop or
-  // ProvisioningResultUMA::CHROME_SERVER_COMMUNICATION_ERROR.
+  // ProvisioningStatus::ArcStop or
+  // ProvisioningStatus::CHROME_SERVER_COMMUNICATION_ERROR.
   // At this moment |prefs::kArcTermsAccepted| is set to true, once user
   // confirmed ToS prior to provisioning flow. Once user presses "Try Again"
   // button, OnRetryClicked calls this immediately.
@@ -1536,8 +1543,8 @@
   } else {
     // Otherwise, we start ARC once it is stopped now. Usually ARC container is
     // left active after provisioning failure but in case
-    // ProvisioningResultUMA::ARC_STOPPED and
-    // ProvisioningResultUMA::CHROME_SERVER_COMMUNICATION_ERROR failures
+    // ProvisioningStatus::ARC_STOPPED and
+    // ProvisioningStatus::CHROME_SERVER_COMMUNICATION_ERROR failures
     // container is stopped. At this point ToS is already accepted and
     // IsArcTermsOfServiceNegotiationNeeded returns true or ToS needs not to be
     // shown at all. However there is an exception when this does not happen in
diff --git a/chrome/browser/chromeos/arc/session/arc_session_manager.h b/chrome/browser/chromeos/arc/session/arc_session_manager.h
index 78eeb26..5a64db6 100644
--- a/chrome/browser/chromeos/arc/session/arc_session_manager.h
+++ b/chrome/browser/chromeos/arc/session/arc_session_manager.h
@@ -45,7 +45,7 @@
 class ArcTermsOfServiceNegotiator;
 class ArcUiAvailabilityReporter;
 
-enum class ProvisioningResultUMA : int;
+enum class ProvisioningStatus;
 enum class ArcStopReason;
 
 // This class is responsible for handing stages of ARC life-cycle.
diff --git a/chrome/browser/chromeos/arc/session/arc_session_manager_unittest.cc b/chrome/browser/chromeos/arc/session/arc_session_manager_unittest.cc
index c476016..88cb811 100644
--- a/chrome/browser/chromeos/arc/session/arc_session_manager_unittest.cc
+++ b/chrome/browser/chromeos/arc/session/arc_session_manager_unittest.cc
@@ -1155,12 +1155,12 @@
 constexpr ProvisioningErrorDisplayTestParam
     kProvisioningErrorDisplayTestCases[] = {
         {ArcStopReason::GENERIC_BOOT_FAILURE,
-         ArcSupportHost::Error::SIGN_IN_UNKNOWN_ERROR, 16 /*ARC_STOPPED*/},
+         ArcSupportHost::Error::SIGN_IN_UNKNOWN_ERROR, 8 /*ARC_STOPPED*/},
         {ArcStopReason::LOW_DISK_SPACE,
          ArcSupportHost::Error::LOW_DISK_SPACE_ERROR,
          {}},
         {ArcStopReason::CRASH, ArcSupportHost::Error::SIGN_IN_UNKNOWN_ERROR,
-         16 /*ARC_STOPPED*/}};
+         8 /*ARC_STOPPED*/}};
 
 class ProvisioningErrorDisplayTest
     : public ArcSessionManagerTest,
diff --git a/chrome/browser/chromeos/file_manager/file_manager_string_util.cc b/chrome/browser/chromeos/file_manager/file_manager_string_util.cc
index dc959d1..f8787b3 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_string_util.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_string_util.cc
@@ -831,6 +831,12 @@
              IDS_FILE_BROWSER_REPARTITION_DIALOG_MESSAGE);
   SET_STRING("RESTORE_FROM_TRASH_BUTTON_LABEL",
              IDS_FILE_BROWSER_RESTORE_FROM_TRASH_BUTTON_LABEL);
+  SET_STRING("RESTORE_FROM_TRASH_ERROR",
+             IDS_FILE_BROWSER_RESTORE_FROM_TRASH_ERROR);
+  SET_STRING("RESTORE_FROM_TRASH_FILE_NAME",
+             IDS_FILE_BROWSER_RESTORE_FROM_TRASH_FILE_NAME);
+  SET_STRING("RESTORE_FROM_TRASH_ITEMS_REMAINING",
+             IDS_FILE_BROWSER_RESTORE_FROM_TRASH_ITEMS_REMAINING);
   SET_STRING("UNPIN_FOLDER_BUTTON_LABEL",
              IDS_FILE_BROWSER_UNPIN_FOLDER_BUTTON_LABEL);
   SET_STRING("RENAME_BUTTON_LABEL", IDS_FILE_BROWSER_RENAME_BUTTON_LABEL);
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc
index 6130bdad..e2536bc 100644
--- a/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc
+++ b/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc
@@ -152,7 +152,8 @@
                                               "fr",
                                               "se",
                                               "jp",
-                                              "hu"};
+                                              "hu",
+                                              "de"};
 
     auto mock_delegate =
         std::make_unique<MockComponentExtensionIMEManagerDelegate>();
@@ -306,6 +307,13 @@
     ext_xkb_engine_hu.layouts.emplace_back("hu");
     ext_xkb.engines.push_back(ext_xkb_engine_hu);
 
+    ComponentExtensionEngine ext_xkb_engine_de;
+    ext_xkb_engine_de.engine_id = "xkb:de::ger";
+    ext_xkb_engine_de.display_name = "xkb:de::ger";
+    ext_xkb_engine_de.language_codes.emplace_back("de");
+    ext_xkb_engine_de.layouts.emplace_back("de");
+    ext_xkb.engines.push_back(ext_xkb_engine_de);
+
     ime_list.push_back(ext_xkb);
 
     ComponentExtensionIME ext1;
diff --git a/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc b/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc
index 90f90cf..6508733 100644
--- a/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc
+++ b/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc
@@ -255,6 +255,8 @@
   VLOG(1) << "AutoEnrollmentCheckScreen::SignalCompletion()";
 
   network_portal_detector::GetInstance()->RemoveObserver(this);
+  error_screen_->SetHideCallback(base::OnceClosure());
+  error_screen_->SetParentScreen(OobeScreen::SCREEN_UNKNOWN);
   auto_enrollment_progress_subscription_ = {};
   connect_request_subscription_ = {};
 
diff --git a/chrome/browser/chromeos/login/enrollment/enrollment_local_policy_server_browsertest.cc b/chrome/browser/chromeos/login/enrollment/enrollment_local_policy_server_browsertest.cc
index 181523ef..f323486 100644
--- a/chrome/browser/chromeos/login/enrollment/enrollment_local_policy_server_browsertest.cc
+++ b/chrome/browser/chromeos/login/enrollment/enrollment_local_policy_server_browsertest.cc
@@ -23,6 +23,7 @@
 #include "chrome/browser/chromeos/login/test/js_checker.h"
 #include "chrome/browser/chromeos/login/test/kiosk_test_helpers.h"
 #include "chrome/browser/chromeos/login/test/local_policy_test_server_mixin.h"
+#include "chrome/browser/chromeos/login/test/network_portal_detector_mixin.h"
 #include "chrome/browser/chromeos/login/test/oobe_base_test.h"
 #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
 #include "chrome/browser/chromeos/login/test/oobe_screens_utils.h"
@@ -196,6 +197,9 @@
         ->GetStateKeysBroker();
   }
 
+ protected:
+  NetworkPortalDetectorMixin network_portal_detector_{&mixin_host_};
+
  private:
   DISALLOW_COPY_AND_ASSIGN(AutoEnrollmentLocalPolicyServer);
 };
@@ -618,6 +622,18 @@
   EXPECT_TRUE(InstallAttributes::Get()->IsCloudManaged());
 }
 
+// Verify able to advance to login screen when error screen is shown.
+IN_PROC_BROWSER_TEST_F(AutoEnrollmentLocalPolicyServer, TestCaptivePortal) {
+  network_portal_detector_.SimulateDefaultNetworkState(
+      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL);
+  host()->StartWizard(AutoEnrollmentCheckScreenView::kScreenId);
+  OobeScreenWaiter(ErrorScreenView::kScreenId).Wait();
+
+  network_portal_detector_.SimulateDefaultNetworkState(
+      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE);
+  OobeScreenWaiter(GetFirstSigninScreen()).Wait();
+}
+
 // FRE explicitly required in VPD, but the state keys are missing.
 IN_PROC_BROWSER_TEST_F(AutoEnrollmentNoStateKeys, FREExplicitlyRequired) {
   SetFRERequiredKey("1");
diff --git a/chrome/browser/chromeos/policy/dlp/data_transfer_dlp_controller_browsertest.cc b/chrome/browser/chromeos/policy/dlp/data_transfer_dlp_controller_browsertest.cc
index 032450f..9419e00 100644
--- a/chrome/browser/chromeos/policy/dlp/data_transfer_dlp_controller_browsertest.cc
+++ b/chrome/browser/chromeos/policy/dlp/data_transfer_dlp_controller_browsertest.cc
@@ -7,6 +7,9 @@
 #include "base/json/json_writer.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/chromeos/crostini/crostini_manager.h"
+#include "chrome/browser/chromeos/crostini/crostini_util.h"
+#include "chrome/browser/chromeos/crostini/fake_crostini_features.h"
 #include "chrome/browser/chromeos/policy/dlp/data_transfer_dlp_controller.h"
 #include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager.h"
 #include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager_test_utils.h"
@@ -44,6 +47,23 @@
         policy, /*recommended=*/base::DictionaryValue(),
         ProfileManager::GetActiveUserProfile());
   }
+
+  void SetupCrostini() {
+    crostini::FakeCrostiniFeatures crostini_features;
+    crostini_features.set_is_allowed_now(true);
+    crostini_features.set_enabled(true);
+
+    // Setup CrostiniManager for testing.
+    crostini::CrostiniManager* crostini_manager =
+        crostini::CrostiniManager::GetForProfile(GetProfileForActiveUser());
+    crostini_manager->set_skip_restart_for_testing();
+    crostini_manager->AddRunningVmForTesting(crostini::kCrostiniDefaultVmName);
+    crostini_manager->AddRunningContainerForTesting(
+        crostini::kCrostiniDefaultVmName,
+        crostini::ContainerInfo(crostini::kCrostiniDefaultContainerName,
+                                "testuser", "/home/testuser",
+                                "PLACEHOLDER_IP"));
+  }
 };
 
 IN_PROC_BROWSER_TEST_F(DataTransferDlpBrowserTest, EmptyPolicy) {
@@ -140,6 +160,8 @@
   SkipToLoginScreen();
   LogIn(kAccountId, kAccountPassword, kEmptyServices);
 
+  SetupCrostini();
+
   const std::string kUrl1 = "https://mail.google.com";
 
   base::Value rules(base::Value::Type::LIST);
@@ -171,19 +193,13 @@
       ui::ClipboardBuffer::kCopyPaste, &data_dst1, &result1);
   EXPECT_EQ(base::UTF8ToUTF16(kClipboardText), result1);
 
-  // `notify_if_restricted` should be set false, otherwise the test would fail,
-  // because no guest os is actually running.
-  ui::DataTransferEndpoint data_dst2(ui::EndpointType::kArc,
-                                     /*notify_if_restricted=*/false);
+  ui::DataTransferEndpoint data_dst2(ui::EndpointType::kArc);
   base::string16 result2;
   ui::Clipboard::GetForCurrentThread()->ReadText(
       ui::ClipboardBuffer::kCopyPaste, &data_dst2, &result2);
   EXPECT_EQ(base::string16(), result2);
 
-  // `notify_if_restricted` should be set false, otherwise the test would fail,
-  // because no guest os is actually running.
-  ui::DataTransferEndpoint data_dst3(ui::EndpointType::kGuestOs,
-                                     /*notify_if_restricted=*/false);
+  ui::DataTransferEndpoint data_dst3(ui::EndpointType::kGuestOs);
   base::string16 result3;
   ui::Clipboard::GetForCurrentThread()->ReadText(
       ui::ClipboardBuffer::kCopyPaste, &data_dst3, &result3);
diff --git a/chrome/browser/chromeos/policy/extension_install_event_log_collector.cc b/chrome/browser/chromeos/policy/extension_install_event_log_collector.cc
index 7b6e398..1c137442 100644
--- a/chrome/browser/chromeos/policy/extension_install_event_log_collector.cc
+++ b/chrome/browser/chromeos/policy/extension_install_event_log_collector.cc
@@ -473,12 +473,10 @@
 void AddErrorCodesToFailureEvent(
     const extensions::InstallStageTracker::InstallationData& data,
     em::ExtensionInstallReportLogEvent* event) {
-  if (data.response_code) {
+  if (data.response_code)
     event->set_fetch_error_code(data.response_code.value());
-  } else {
-    DCHECK(data.network_error_code);
+  else if (data.network_error_code)
     event->set_fetch_error_code(data.network_error_code.value());
-  }
 
   DCHECK(data.fetch_tries);
   event->set_fetch_tries(data.fetch_tries.value_or(0));
diff --git a/chrome/browser/chromeos/usb/cros_usb_detector.cc b/chrome/browser/chromeos/usb/cros_usb_detector.cc
index 5493ef0..d4ff953 100644
--- a/chrome/browser/chromeos/usb/cros_usb_detector.cc
+++ b/chrome/browser/chromeos/usb/cros_usb_detector.cc
@@ -293,7 +293,7 @@
 
 class FilesystemUnmounter : public base::RefCounted<FilesystemUnmounter> {
  public:
-  static void UnmountPaths(const std::vector<std::string>& paths,
+  static void UnmountPaths(const std::set<std::string>& paths,
                            base::OnceCallback<void(bool success)> callback);
 
  private:
@@ -310,7 +310,7 @@
 };
 
 void FilesystemUnmounter::UnmountPaths(
-    const std::vector<std::string>& paths,
+    const std::set<std::string>& paths,
     base::OnceCallback<void(bool success)> callback) {
   scoped_refptr<FilesystemUnmounter> unmounter =
       new FilesystemUnmounter(std::move(callback));
@@ -388,10 +388,12 @@
   chromeos::DBusThreadManager::Get()
       ->GetVmPluginDispatcherClient()
       ->AddObserver(this);
+  disks::DiskMountManager::GetInstance()->AddObserver(this);
 }
 
 CrosUsbDetector::~CrosUsbDetector() {
   DCHECK_EQ(this, g_cros_usb_detector);
+  disks::DiskMountManager::GetInstance()->RemoveObserver(this);
   chromeos::DBusThreadManager::Get()->GetConciergeClient()->RemoveVmObserver(
       this);
   chromeos::DBusThreadManager::Get()
@@ -434,6 +436,12 @@
   return devices;
 }
 
+bool CrosUsbDetector::SharingRequiresReassignPrompt(
+    const CrosUsbDeviceInfo& device_info) const {
+  return device_info.shared_vm_name.has_value() ||
+         !device_info.mount_points.empty();
+}
+
 void CrosUsbDetector::ConnectToDeviceManager() {
   // Tests may set a fake manager.
   if (!device_manager_) {
@@ -493,6 +501,41 @@
   }
 }
 
+void CrosUsbDetector::OnMountEvent(
+    disks::DiskMountManager::MountEvent event,
+    MountError error_code,
+    const disks::DiskMountManager::MountPointInfo& mount_info) {
+  if (mount_info.mount_type != MOUNT_TYPE_DEVICE) {
+    return;
+  }
+
+  const chromeos::disks::Disk* disk =
+      disks::DiskMountManager::GetInstance()->FindDiskBySourcePath(
+          mount_info.source_path);
+
+  // This can be null if a drive is physically removed.
+  if (!disk) {
+    return;
+  }
+
+  for (auto& device : usb_devices_) {
+    if (device.bus_number == disk->bus_number() &&
+        device.port_number == disk->device_number()) {
+      bool was_empty = device.mount_points.empty();
+      if (event == disks::DiskMountManager::MOUNTING) {
+        device.mount_points.insert(mount_info.mount_path);
+      } else {
+        device.mount_points.erase(mount_info.mount_path);
+      }
+
+      if (!device.is_unmounting && was_empty != device.mount_points.empty()) {
+        SignalUsbDeviceObservers();
+      }
+      return;
+    }
+  }
+}
+
 void CrosUsbDetector::OnDeviceChecked(
     device::mojom::UsbDeviceInfoPtr device_info,
     bool hide_notification,
@@ -648,6 +691,7 @@
       // with an in progress attach.
       RelinquishDeviceClaim(guid);
       device.shared_vm_name = base::nullopt;
+      SignalUsbDeviceObservers();
       std::move(callback).Run(/*success=*/true);
       return;
     }
@@ -678,8 +722,8 @@
     const std::string& vm_name,
     const std::string& guid,
     base::OnceCallback<void(bool success)> callback) {
-  const CrosUsbDeviceInfo* cur_device = nullptr;
-  for (const auto& device : usb_devices_) {
+  CrosUsbDeviceInfo* cur_device = nullptr;
+  for (auto& device : usb_devices_) {
     if (device.guid == guid) {
       cur_device = &device;
       break;
@@ -691,19 +735,12 @@
     return;
   }
 
-  std::vector<std::string> paths_to_unmount;
-  for (const auto& iter : disks::DiskMountManager::GetInstance()->disks()) {
-    if (iter.second->bus_number() == cur_device->bus_number &&
-        iter.second->device_number() == cur_device->port_number &&
-        iter.second->is_mounted()) {
-      paths_to_unmount.push_back(iter.second->mount_path());
-    }
-  }
-
+  cur_device->is_unmounting = true;
   FilesystemUnmounter::UnmountPaths(
-      paths_to_unmount, base::BindOnce(&CrosUsbDetector::OnUnmountFilesystems,
-                                       weak_ptr_factory_.GetWeakPtr(), vm_name,
-                                       guid, std::move(callback)));
+      cur_device->mount_points,
+      base::BindOnce(&CrosUsbDetector::OnUnmountFilesystems,
+                     weak_ptr_factory_.GetWeakPtr(), vm_name, guid,
+                     std::move(callback)));
 }
 
 void CrosUsbDetector::OnUnmountFilesystems(
@@ -711,40 +748,45 @@
     const std::string& guid,
     base::OnceCallback<void(bool success)> callback,
     bool unmount_success) {
-  if (!unmount_success) {
-    // FilesystemUnmounter already logged the error.
-    std::move(callback).Run(false);
+  for (auto& device : usb_devices_) {
+    if (device.guid != guid) {
+      continue;
+    }
+
+    device.is_unmounting = false;
+
+    if (!unmount_success) {
+      // FilesystemUnmounter already logged the error.
+      std::move(callback).Run(false);
+      return;
+    }
+
+    // Detach first if device is attached elsewhere
+    if (device.shared_vm_name && device.shared_vm_name != vm_name) {
+      DetachUsbDeviceFromVm(
+          *device.shared_vm_name, guid,
+          base::BindOnce(&CrosUsbDetector::AttachAfterDetach,
+                         weak_ptr_factory_.GetWeakPtr(), vm_name, guid,
+                         device.allowed_interfaces_mask, std::move(callback)));
+    } else {
+      // Mark the USB device shared so that we know to reattach it on VM
+      // restart. Setting this flag early also allows the UI not to flicker
+      // because of the notification resulting from the default VM detach below.
+      device.shared_vm_name = vm_name;
+      // The guest port will be set on completion.
+
+      // The device isn't attached.
+      AttachAfterDetach(vm_name, guid, device.allowed_interfaces_mask,
+                        std::move(callback),
+                        /*detach_success=*/true);
+    }
+
     return;
   }
 
-  uint32_t allowed_interfaces_mask = 0;
-  for (auto& device : usb_devices_) {
-    if (device.guid == guid) {
-      // Detach first if device is attached elsewhere
-      if (device.shared_vm_name && device.shared_vm_name != vm_name) {
-        DetachUsbDeviceFromVm(
-            *device.shared_vm_name, guid,
-            base::BindOnce(&CrosUsbDetector::AttachAfterDetach,
-                           weak_ptr_factory_.GetWeakPtr(), vm_name, guid,
-                           device.allowed_interfaces_mask,
-                           std::move(callback)));
-        return;
-      }
-
-      // Mark the USB device shared so that we know to reattach it on VM
-      // restart.
-      // Setting this flag early also allows the UI not to flicker because of
-      // the notification resulting from the default VM detach below.
-      device.shared_vm_name = vm_name;
-      allowed_interfaces_mask = device.allowed_interfaces_mask;
-      // The guest port will be set on completion.
-      break;
-    }
-  }
-
-  // The device isn't attached.
-  AttachAfterDetach(vm_name, guid, allowed_interfaces_mask, std::move(callback),
-                    /*detach_success=*/true);
+  LOG(ERROR) << "Couldn't find device " << guid;
+  std::move(callback).Run(false);
+  return;
 }
 
 void CrosUsbDetector::AttachAfterDetach(
diff --git a/chrome/browser/chromeos/usb/cros_usb_detector.h b/chrome/browser/chromeos/usb/cros_usb_detector.h
index e08b9e7..410f828 100644
--- a/chrome/browser/chromeos/usb/cros_usb_detector.h
+++ b/chrome/browser/chromeos/usb/cros_usb_detector.h
@@ -17,6 +17,7 @@
 #include "chrome/browser/chromeos/crostini/crostini_manager.h"
 #include "chromeos/dbus/concierge_client.h"
 #include "chromeos/dbus/vm_plugin_dispatcher_client.h"
+#include "chromeos/disks/disk_mount_manager.h"
 #include "mojo/public/cpp/bindings/associated_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/remote.h"
@@ -64,6 +65,10 @@
   base::Optional<uint8_t> guest_port;
   // Interfaces shareable with guest OSes
   uint32_t allowed_interfaces_mask = 0;
+  // For a mass storage device, the mount points for active mounts.
+  std::set<std::string> mount_points;
+  // An internal flag to suppress observer events as mount_points empties.
+  bool is_unmounting = false;
   // TODO(nverne): Add current state and errors etc.
 };
 
@@ -77,7 +82,8 @@
 // with CrOS, Web or GuestOSs.
 class CrosUsbDetector : public device::mojom::UsbDeviceManagerClient,
                         public chromeos::ConciergeClient::VmObserver,
-                        public chromeos::VmPluginDispatcherClient::Observer {
+                        public chromeos::VmPluginDispatcherClient::Observer,
+                        public disks::DiskMountManager::Observer {
  public:
   // Used to namespace USB notifications to avoid clashes with WebUsbDetector.
   static std::string MakeNotificationId(const std::string& guid);
@@ -132,6 +138,10 @@
   // include all connected devices.
   std::vector<CrosUsbDeviceInfo> GetDevicesSharableWithCrostini() const;
 
+  // Returns whether we should prompt the user before sharing the device.
+  bool SharingRequiresReassignPrompt(
+      const CrosUsbDeviceInfo& device_info) const;
+
  private:
   // chromeos::ConciergeClient::VmObserver:
   void OnVmStarted(const vm_tools::concierge::VmStartedSignal& signal) override;
@@ -144,6 +154,12 @@
   void OnVmStateChanged(
       const vm_tools::plugin_dispatcher::VmStateChangedSignal& signal) override;
 
+  // disks::DiskMountManager::Observer:
+  void OnMountEvent(
+      disks::DiskMountManager::MountEvent event,
+      MountError error_code,
+      const disks::DiskMountManager::MountPointInfo& mount_info) override;
+
   // Called after USB device access has been checked.
   void OnDeviceChecked(device::mojom::UsbDeviceInfoPtr device,
                        bool hide_notification,
diff --git a/chrome/browser/chromeos/usb/cros_usb_detector_unittest.cc b/chrome/browser/chromeos/usb/cros_usb_detector_unittest.cc
index 89bf813..a0fc9a1 100644
--- a/chrome/browser/chromeos/usb/cros_usb_detector_unittest.cc
+++ b/chrome/browser/chromeos/usb/cros_usb_detector_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/macros.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/gmock_move_support.h"
 #include "chrome/browser/chromeos/crostini/crostini_manager.h"
 #include "chrome/browser/chromeos/crostini/crostini_pref_names.h"
 #include "chrome/browser/chromeos/crostini/crostini_test_helper.h"
@@ -123,11 +124,6 @@
   int notify_count_ = 0;
 };
 
-// testing::SaveArg doesn't work with move-only types
-auto SaveMountCallback(MountCallback* out) {
-  return [out](std::string, MountCallback in) { *out = std::move(in); };
-}
-
 }  // namespace
 
 class CrosUsbDetectorTest : public BrowserWithTestWindowTest {
@@ -144,8 +140,6 @@
 
     mock_disk_mount_manager_ =
         new testing::NiceMock<chromeos::disks::MockDiskMountManager>;
-    ON_CALL(*mock_disk_mount_manager_, disks())
-        .WillByDefault(ReturnRef(disks_));
     chromeos::disks::DiskMountManager::InitializeForTesting(
         mock_disk_mount_manager_);
   }
@@ -236,16 +230,29 @@
     return devices.front();
   }
 
-  void AddDisk(std::string name,
+  void AddDisk(const std::string& name,
                int bus_number,
                int device_number,
                bool mounted) {
-    disks_[name] = chromeos::disks::Disk::Builder()
-                       .SetBusNumber(bus_number)
-                       .SetDeviceNumber(device_number)
-                       .SetMountPath("/mount/" + name)
-                       .SetIsMounted(mounted)
-                       .Build();
+    mock_disk_mount_manager_->CreateDiskEntryForMountDevice(
+        chromeos::disks::Disk::Builder()
+            .SetBusNumber(bus_number)
+            .SetDeviceNumber(device_number)
+            .SetDevicePath("/dev/" + name)
+            .SetMountPath("/mount/" + name)
+            .SetIsMounted(mounted)
+            .Build());
+    if (mounted)
+      NotifyMountEvent(name, chromeos::disks::DiskMountManager::MOUNTING);
+  }
+
+  void NotifyMountEvent(const std::string& name,
+                        chromeos::disks::DiskMountManager::MountEvent event) {
+    chromeos::disks::DiskMountManager::MountPointInfo info(
+        "/dev/" + name, "/mount/" + name, chromeos::MOUNT_TYPE_DEVICE,
+        chromeos::disks::MOUNT_CONDITION_NONE);
+    mock_disk_mount_manager_->NotifyMountEvent(
+        event, chromeos::MOUNT_ERROR_NONE, info);
   }
 
  protected:
@@ -985,10 +992,9 @@
   ConnectToDeviceManager();
   base::RunLoop().RunUntilIdle();
 
-  auto device = base::MakeRefCounted<device::FakeUsbDeviceInfo>(
+  device_manager_.CreateAndAddDevice(
       0x0200, 0xff, 0xff, 0xff, 0x0100, 1, 2, /*bus_number=*/3,
       /*port_number=*/4, kManufacturerName, kProductName_1, "5");
-  device_manager_.AddDevice(device);
   base::RunLoop().RunUntilIdle();
 
   AddDisk("disk1", 3, 4, true);
@@ -999,19 +1005,22 @@
   MountCallback callback1;
   MountCallback callback4;
   EXPECT_CALL(*mock_disk_mount_manager_, UnmountPath("/mount/disk1", _))
-      .WillOnce(SaveMountCallback(&callback1));
+      .WillOnce(MoveArg<1>(&callback1));
   EXPECT_CALL(*mock_disk_mount_manager_, UnmountPath("/mount/disk4", _))
-      .WillOnce(SaveMountCallback(&callback4));
+      .WillOnce(MoveArg<1>(&callback4));
 
   AttachDeviceToVm("VM1", GetSingleDeviceInfo().guid);
   EXPECT_FALSE(fake_concierge_client_->attach_usb_device_called());
 
+  // Unmount events would normally be fired by the DiskMountManager.
+  NotifyMountEvent("disk1", chromeos::disks::DiskMountManager::UNMOUNTING);
   std::move(callback1).Run(chromeos::MOUNT_ERROR_NONE);
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(GetSingleDeviceInfo().shared_vm_name.has_value());
   EXPECT_FALSE(fake_concierge_client_->attach_usb_device_called());
 
   // All unmounts must complete before sharing succeeds.
+  NotifyMountEvent("disk4", chromeos::disks::DiskMountManager::UNMOUNTING);
   std::move(callback4).Run(chromeos::MOUNT_ERROR_NONE);
   base::RunLoop().RunUntilIdle();
 
@@ -1023,10 +1032,9 @@
   ConnectToDeviceManager();
   base::RunLoop().RunUntilIdle();
 
-  auto device = base::MakeRefCounted<device::FakeUsbDeviceInfo>(
+  device_manager_.CreateAndAddDevice(
       0x0200, 0xff, 0xff, 0xff, 0x0100, 1, 2, /*bus_number=*/1,
       /*port_number=*/5, kManufacturerName, kProductName_1, "5");
-  device_manager_.AddDevice(device);
   base::RunLoop().RunUntilIdle();
 
   AddDisk("disk1", 1, 5, true);
@@ -1036,15 +1044,18 @@
   MountCallback callback2;
   MountCallback callback3;
   EXPECT_CALL(*mock_disk_mount_manager_, UnmountPath("/mount/disk1", _))
-      .WillOnce(SaveMountCallback(&callback1));
+      .WillOnce(MoveArg<1>(&callback1));
   EXPECT_CALL(*mock_disk_mount_manager_, UnmountPath("/mount/disk2", _))
-      .WillOnce(SaveMountCallback(&callback2));
+      .WillOnce(MoveArg<1>(&callback2));
   EXPECT_CALL(*mock_disk_mount_manager_, UnmountPath("/mount/disk3", _))
-      .WillOnce(SaveMountCallback(&callback3));
+      .WillOnce(MoveArg<1>(&callback3));
 
+  // Unmount events would normally be fired by the DiskMountManager.
   AttachDeviceToVm("VM1", GetSingleDeviceInfo().guid, /*success=*/false);
+  NotifyMountEvent("disk1", chromeos::disks::DiskMountManager::UNMOUNTING);
   std::move(callback1).Run(chromeos::MOUNT_ERROR_NONE);
   std::move(callback2).Run(chromeos::MOUNT_ERROR_UNKNOWN);
+  NotifyMountEvent("disk3", chromeos::disks::DiskMountManager::UNMOUNTING);
   std::move(callback3).Run(chromeos::MOUNT_ERROR_NONE);
   base::RunLoop().RunUntilIdle();
 
@@ -1052,3 +1063,43 @@
   // callback, so there's not much to check here.
   EXPECT_FALSE(fake_concierge_client_->attach_usb_device_called());
 }
+
+TEST_F(CrosUsbDetectorTest, ReassignPromptForSharedDevice) {
+  ConnectToDeviceManager();
+  base::RunLoop().RunUntilIdle();
+
+  device_manager_.CreateAndAddDevice(0x1234, 0x5678);
+  base::RunLoop().RunUntilIdle();
+
+  auto device_info = GetSingleDeviceInfo();
+  EXPECT_FALSE(cros_usb_detector_->SharingRequiresReassignPrompt(device_info));
+
+  AttachDeviceToVm("VM1", device_info.guid);
+  device_info = GetSingleDeviceInfo();
+  EXPECT_TRUE(cros_usb_detector_->SharingRequiresReassignPrompt(device_info));
+
+  DetachDeviceFromVm("VM1", device_info.guid, /*expected_success=*/true);
+  device_info = GetSingleDeviceInfo();
+  EXPECT_FALSE(cros_usb_detector_->SharingRequiresReassignPrompt(device_info));
+}
+
+TEST_F(CrosUsbDetectorTest, ReassignPromptForStorageDevice) {
+  ConnectToDeviceManager();
+  base::RunLoop().RunUntilIdle();
+
+  device_manager_.CreateAndAddDevice(
+      0x0200, 0xff, 0xff, 0xff, 0x0100, 1, 2, /*bus_number=*/1,
+      /*port_number=*/5, kManufacturerName, kProductName_1, "5");
+  base::RunLoop().RunUntilIdle();
+
+  auto device_info = GetSingleDeviceInfo();
+  EXPECT_FALSE(cros_usb_detector_->SharingRequiresReassignPrompt(device_info));
+
+  AddDisk("disk1", 1, 5, true);
+  device_info = GetSingleDeviceInfo();
+  EXPECT_TRUE(cros_usb_detector_->SharingRequiresReassignPrompt(device_info));
+
+  NotifyMountEvent("disk1", chromeos::disks::DiskMountManager::UNMOUNTING);
+  device_info = GetSingleDeviceInfo();
+  EXPECT_FALSE(cros_usb_detector_->SharingRequiresReassignPrompt(device_info));
+}
diff --git a/chrome/browser/continuous_search/android/javatests/org/chromium/chrome/browser/continuous_search/ContinuousSearchTabHelperTest.java b/chrome/browser/continuous_search/android/javatests/org/chromium/chrome/browser/continuous_search/ContinuousSearchTabHelperTest.java
index de98cb9..8c8edbf6 100644
--- a/chrome/browser/continuous_search/android/javatests/org/chromium/chrome/browser/continuous_search/ContinuousSearchTabHelperTest.java
+++ b/chrome/browser/continuous_search/android/javatests/org/chromium/chrome/browser/continuous_search/ContinuousSearchTabHelperTest.java
@@ -154,12 +154,9 @@
             SearchResultUserData searchResultUserData =
                     tab.getUserDataHost().getUserData(SearchResultUserData.USER_DATA_KEY);
             Assert.assertTrue(searchResultUserData.isValid());
-            Assert.assertEquals(
-                    mServer.getURLWithHostName("www.google.com", TEST_URL + "?q=cat+dog&cs=0"),
-                    observer.mMetadata.getResultUrl().getSpec());
-            Assert.assertEquals(
-                    mServer.getURLWithHostName("www.google.com", TEST_URL + "?q=cat+dog&cs=0"),
-                    observer.mUrl.getSpec());
+            String url = mServer.getURLWithHostName("www.google.com", TEST_URL + "?q=cat+dog");
+            Assert.assertTrue(observer.mMetadata.getResultUrl().getSpec().startsWith(url));
+            Assert.assertTrue(observer.mUrl.getSpec().startsWith(url));
             tab.loadUrl(new LoadUrlParams(UrlConstants.ABOUT_URL));
         });
 
diff --git a/chrome/browser/enterprise/reporting/report_request_queue_generator_unittest.cc b/chrome/browser/enterprise/reporting/report_request_queue_generator_unittest.cc
index 01a549bf..0e4c554 100644
--- a/chrome/browser/enterprise/reporting/report_request_queue_generator_unittest.cc
+++ b/chrome/browser/enterprise/reporting/report_request_queue_generator_unittest.cc
@@ -255,7 +255,8 @@
                                        0);
 }
 
-TEST_P(ReportRequestQueueGeneratorTest, ReportSeparation) {
+// TODO(1153593): Test is very flaky on all bots. Disabling until zmin@ is back.
+TEST_P(ReportRequestQueueGeneratorTest, DISABLED_ReportSeparation) {
   CreateActiveProfilesWithContent();
   auto basic_request = GenerateBasicRequest();
   auto requests = GenerateRequests(*basic_request);
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc b/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc
index 3d6059a..638eda69 100644
--- a/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc
+++ b/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc
@@ -10,16 +10,16 @@
 
 #include "base/bind.h"
 #include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/files/scoped_temp_dir.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
 #include "base/task/post_task.h"
+#include "base/values.h"
 #include "chrome/browser/extensions/api/platform_keys/platform_keys_test_base.h"
-#include "chrome/browser/extensions/policy_test_utils.h"
 #include "chrome/browser/net/nss_context.h"
+#include "chrome/browser/policy/extension_force_install_mixin.h"
 #include "chrome/common/chrome_paths.h"
+#include "components/policy/core/common/mock_configuration_policy_provider.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/content_switches.h"
@@ -27,11 +27,14 @@
 #include "crypto/nss_util_internal.h"
 #include "crypto/scoped_nss_types.h"
 #include "crypto/scoped_test_system_nss_key_slot.h"
+#include "extensions/browser/event_router.h"
+#include "extensions/browser/extension_event_histogram_value.h"
 #include "extensions/browser/extension_registry.h"
+#include "extensions/common/api/test.h"
+#include "extensions/common/extension_id.h"
 #include "extensions/test/extension_test_message_listener.h"
 #include "extensions/test/result_catcher.h"
 #include "net/cert/nss_cert_database.h"
-#include "net/test/embedded_test_server/embedded_test_server.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -39,16 +42,16 @@
 
 namespace {
 
-// The test extension will query for the state of the system token.
-constexpr char kWaitingForSystemTokenStateMessage[] =
-    "Waiting for system token state message";
-
-// The message sent from a browsertest to the background script in case the
-// system token is enabled.
-constexpr char kSystemTokenEnabledMessage[] = "System token enabled.";
-// The message sent from a browsertest to the background script in case the
-// system token is disabled.
-constexpr char kSystemTokenDisabledMessage[] = "System token disabled.";
+// This message sent from a browsertest to the background script to test the API
+// behavior for an extension running in a user session with system token
+// enabled.
+constexpr char kUserSessionWithSystemTokenEnabledMode[] =
+    "User session with system token enabled mode.";
+// This message sent from a browsertest to the background script to test the API
+// behavior for an extension running in a user session with system token
+// disabled.
+constexpr char kUserSessionWithSystemTokenDisabledMode[] =
+    "User session with system token disabled mode.";
 
 // The test extension has a certificate referencing this private key which will
 // be stored in the user's token in the test setup.
@@ -121,6 +124,18 @@
     0xd8, 0x71, 0x69, 0x5e, 0x8d, 0xb4, 0x48, 0x1c, 0xa4, 0x01, 0xce, 0xc1,
     0xb5, 0x6f, 0xe9, 0x1b, 0x32, 0x91, 0x34, 0x38};
 
+base::FilePath GetExtensionDirName() {
+  return base::PathService::CheckedGet(chrome::DIR_TEST_DATA)
+      .Append(
+          FILE_PATH_LITERAL("extensions/api_test/enterprise_platform_keys/"));
+}
+
+base::FilePath GetExtensionPemFileName() {
+  return base::PathService::CheckedGet(chrome::DIR_TEST_DATA)
+      .Append(FILE_PATH_LITERAL(
+          "extensions/api_test/enterprise_platform_keys.pem"));
+}
+
 void ImportPrivateKeyPKCS8ToSlot(const unsigned char* pkcs8_der,
                                  size_t pkcs8_der_size,
                                  PK11SlotInfo* slot) {
@@ -142,18 +157,6 @@
   crypto::ScopedSECKEYPrivateKey seckey(seckey_raw);
 }
 
-// The managed_storage extension has a key defined in its manifest, so that
-// its extension ID is well-known and the policy system can push policies for
-// the extension.
-const char kTestExtensionID[] = "aecpbnckhoppanpmefllkdkohionpmig";
-const char kTestExtensionUpdateManifest[] =
-    R"(<?xml version='1.0' encoding='UTF-8'?>
-       <gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
-         <app appid='$1'>
-           <updatecheck codebase='$2' version='0.1' />
-         </app>
-       </gupdate>)";
-
 struct Params {
   Params(PlatformKeysTestBase::SystemTokenStatus system_token_status,
          PlatformKeysTestBase::EnrollmentStatus enrollment_status,
@@ -185,24 +188,10 @@
   }
 
   void SetUpOnMainThread() override {
-    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-
-    embedded_test_server()->ServeFilesFromDirectory(temp_dir_.GetPath());
-
-    crx_path_ = temp_dir_.GetPath().Append(kCrxFileName);
-    update_manifest_path_ = temp_dir_.GetPath().Append(kUpdateManifestFileName);
-
-    extension_path_ = test_data_dir_.Append(kExtensionDirName);
-    pem_path_ = test_data_dir_.Append(kPemFileName);
-
-    base::FilePath created_crx_path =
-        PackExtensionWithOptions(extension_path_, crx_path_, pem_path_,
-                                 /*pem_out_path=*/base::FilePath());
-    ASSERT_EQ(created_crx_path, crx_path_);
-
-    GenerateUpdateManifestFile();
-
     PlatformKeysTestBase::SetUpOnMainThread();
+
+    extension_force_install_mixin_.InitWithMockPolicyProvider(
+        profile(), mock_policy_provider());
   }
 
   void DidGetCertDatabase(const base::Closure& done_callback,
@@ -216,18 +205,20 @@
   }
 
  protected:
-  const std::string kUpdateManifestFileName =
-      "enterprise_platform_keys_update_manifest.xml";
+  std::string GetTestMode() {
+    // Only if the system token exists, and the current user is of the same
+    // domain as the device is enrolled to, the system token is available to the
+    // extension.
+    if (system_token_status() == SystemTokenStatus::EXISTS &&
+        enrollment_status() == EnrollmentStatus::ENROLLED &&
+        user_status() == UserStatus::MANAGED_AFFILIATED_DOMAIN) {
+      return kUserSessionWithSystemTokenEnabledMode;
+    }
 
-  void SetUpTestListeners() {
-    catcher_ = std::make_unique<extensions::ResultCatcher>();
-    listener_ = std::make_unique<ExtensionTestMessageListener>(
-        kWaitingForSystemTokenStateMessage,
-        /*will_reply=*/true);
+    return kUserSessionWithSystemTokenDisabledMode;
   }
 
-  std::unique_ptr<extensions::ResultCatcher> catcher_;
-  std::unique_ptr<ExtensionTestMessageListener> listener_;
+  ExtensionForceInstallMixin extension_force_install_mixin_{&mixin_host_};
 
  private:
   void PrepareTestSystemSlotOnIO(
@@ -239,29 +230,6 @@
                                 system_slot->slot());
   }
 
-  void GenerateUpdateManifestFile() {
-    const std::string kContent = base::ReplaceStringPlaceholders(
-        kTestExtensionUpdateManifest,
-        {kTestExtensionID,
-         embedded_test_server()->GetURL("/" + kCrxFileName).spec().c_str()},
-        /*offsets=*/nullptr);
-
-    int written_bytes = base::WriteFile(update_manifest_path_, kContent.data(),
-                                        kContent.size());
-    ASSERT_EQ(written_bytes, static_cast<int>(kContent.length()));
-  }
-
-  const std::string kCrxFileName = "enterprise_platform_keys.crx";
-  const std::string kExtensionDirName = "enterprise_platform_keys";
-  const std::string kPemFileName = "enterprise_platform_keys.pem";
-
-  base::FilePath crx_path_;
-  base::FilePath extension_path_;
-  base::FilePath pem_path_;
-  base::FilePath update_manifest_path_;
-
-  base::ScopedTempDir temp_dir_;
-
   DISALLOW_COPY_AND_ASSIGN(EnterprisePlatformKeysTest);
 };
 
@@ -280,26 +248,25 @@
                        base::Unretained(this), loop.QuitClosure()));
     loop.Run();
   }
-  policy_test_utils::SetExtensionInstallForcelistPolicy(
-      kTestExtensionID,
-      embedded_test_server()->GetURL("/" + kUpdateManifestFileName), profile(),
-      mock_policy_provider());
 
-  SetUpTestListeners();
-  ASSERT_TRUE(listener_->WaitUntilSatisfied());
+  extensions::ExtensionId extension_id;
+  ASSERT_TRUE(extension_force_install_mixin_.ForceInstallFromSourceDir(
+      GetExtensionDirName(), GetExtensionPemFileName(),
+      ExtensionForceInstallMixin::WaitMode::kBackgroundPageFirstLoad,
+      &extension_id));
 
-  // Only if the system token exists, and the current user is of the same domain
-  // as the device is enrolled to, the system token is available to the
-  // extension.
-  if (system_token_status() == SystemTokenStatus::EXISTS &&
-      enrollment_status() == EnrollmentStatus::ENROLLED &&
-      user_status() == UserStatus::MANAGED_AFFILIATED_DOMAIN) {
-    listener_->Reply(kSystemTokenEnabledMessage);
-  } else {
-    listener_->Reply(kSystemTokenDisabledMessage);
-  }
+  api::test::OnMessage::Info info;
+  info.data = GetTestMode();
 
-  ASSERT_TRUE(catcher_->GetNextResult());
+  auto event = std::make_unique<extensions::Event>(
+      extensions::events::FOR_TEST,
+      extensions::api::test::OnMessage::kEventName,
+      api::test::OnMessage::Create(info), profile());
+  extensions::EventRouter::Get(profile())->DispatchEventToExtension(
+      extension_id, std::move(event));
+
+  extensions::ResultCatcher catcher;
+  ASSERT_TRUE(catcher.GetNextResult());
 }
 
 INSTANTIATE_TEST_SUITE_P(
diff --git a/chrome/browser/extensions/api/image_writer_private/operation.cc b/chrome/browser/extensions/api/image_writer_private/operation.cc
index 374eae9..eae57092 100644
--- a/chrome/browser/extensions/api/image_writer_private/operation.cc
+++ b/chrome/browser/extensions/api/image_writer_private/operation.cc
@@ -115,7 +115,7 @@
   SetStage(image_writer_api::STAGE_UNZIP);
 
   auto unzip_helper = base::MakeRefCounted<UnzipHelper>(
-      task_runner(), base::Bind(&Operation::OnUnzipOpenComplete, this),
+      base::Bind(&Operation::OnUnzipOpenComplete, this),
       base::Bind(&Operation::CompleteAndContinue, this, continuation),
       base::Bind(&Operation::OnUnzipFailure, this),
       base::Bind(&Operation::OnUnzipProgress, this));
diff --git a/chrome/browser/extensions/api/image_writer_private/unzip_helper.cc b/chrome/browser/extensions/api/image_writer_private/unzip_helper.cc
index 54e7d2d..a2a1ea4 100644
--- a/chrome/browser/extensions/api/image_writer_private/unzip_helper.cc
+++ b/chrome/browser/extensions/api/image_writer_private/unzip_helper.cc
@@ -8,7 +8,6 @@
 
 #include "base/bind.h"
 #include "base/files/file_util.h"
-#include "base/single_thread_task_runner.h"
 #include "base/task/post_task.h"
 #include "base/task/thread_pool.h"
 #include "chrome/browser/extensions/api/image_writer_private/error_messages.h"
@@ -18,13 +17,11 @@
 namespace image_writer {
 
 UnzipHelper::UnzipHelper(
-    scoped_refptr<base::SequencedTaskRunner> owner_task_runner,
     const base::Callback<void(const base::FilePath&)>& open_callback,
     const base::Closure& complete_callback,
     const base::Callback<void(const std::string&)>& failure_callback,
     const base::Callback<void(int64_t, int64_t)>& progress_callback)
-    : owner_task_runner_(owner_task_runner),
-      open_callback_(open_callback),
+    : open_callback_(open_callback),
       complete_callback_(complete_callback),
       failure_callback_(failure_callback),
       progress_callback_(progress_callback),
@@ -34,15 +31,6 @@
 
 void UnzipHelper::Unzip(const base::FilePath& image_path,
                         const base::FilePath& temp_dir_path) {
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner =
-      base::ThreadPool::CreateSingleThreadTaskRunner(
-          {base::MayBlock(), base::TaskPriority::USER_VISIBLE});
-  task_runner->PostTask(FROM_HERE, base::BindOnce(&UnzipHelper::UnzipImpl, this,
-                                                  image_path, temp_dir_path));
-}
-
-void UnzipHelper::UnzipImpl(const base::FilePath& image_path,
-                            const base::FilePath& temp_dir_path) {
   if (!zip_reader_->Open(image_path) || !zip_reader_->AdvanceToNextEntry() ||
       !zip_reader_->OpenCurrentEntryInZip()) {
     OnError(error::kUnzipGenericError);
@@ -74,22 +62,19 @@
 }
 
 void UnzipHelper::OnError(const std::string& error) {
-  owner_task_runner_->PostTask(FROM_HERE,
-                               base::BindOnce(failure_callback_, error));
+  failure_callback_.Run(error);
 }
 
 void UnzipHelper::OnOpenSuccess(const base::FilePath& image_path) {
-  owner_task_runner_->PostTask(FROM_HERE,
-                               base::BindOnce(open_callback_, image_path));
+  open_callback_.Run(image_path);
 }
 
 void UnzipHelper::OnComplete() {
-  owner_task_runner_->PostTask(FROM_HERE, complete_callback_);
+  complete_callback_.Run();
 }
 
 void UnzipHelper::OnProgress(int64_t total_bytes, int64_t curr_bytes) {
-  owner_task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(progress_callback_, total_bytes, curr_bytes));
+  progress_callback_.Run(total_bytes, curr_bytes);
 }
 
 }  // namespace image_writer
diff --git a/chrome/browser/extensions/api/image_writer_private/unzip_helper.h b/chrome/browser/extensions/api/image_writer_private/unzip_helper.h
index 984b037..35ae85b 100644
--- a/chrome/browser/extensions/api/image_writer_private/unzip_helper.h
+++ b/chrome/browser/extensions/api/image_writer_private/unzip_helper.h
@@ -5,8 +5,8 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_IMAGE_WRITER_PRIVATE_UNZIP_HELPER_H_
 #define CHROME_BROWSER_EXTENSIONS_API_IMAGE_WRITER_PRIVATE_UNZIP_HELPER_H_
 
+#include "base/callback.h"
 #include "base/memory/ref_counted_memory.h"
-#include "base/sequenced_task_runner.h"
 #include "build/build_config.h"
 
 namespace base {
@@ -21,16 +21,9 @@
 namespace image_writer {
 
 // A helper to provide Unzip operation.
-// Currently ZipReader requires SingleThreadTaskRunner, this class is
-// responsible for running ZipReader on a SingleThreadTaskRunner. Unzip
-// should be called from sequences (|owner_task_runner_|) and all the
-// callbacks of this class is called on that task runner.
-// TODO(satorux/lazyboy): Make ZipReader Sequence friendly and remove
-// SingleThreadTaskRunner from this class. https://crbug.com/752702.
 class UnzipHelper : public base::RefCountedThreadSafe<UnzipHelper> {
  public:
   explicit UnzipHelper(
-      scoped_refptr<base::SequencedTaskRunner> owner_task_runner,
       const base::Callback<void(const base::FilePath&)>& open_callback,
       const base::Closure& complete_callback,
       const base::Callback<void(const std::string&)>& failure_callback,
@@ -43,15 +36,11 @@
   friend class base::RefCountedThreadSafe<UnzipHelper>;
   ~UnzipHelper();
 
-  void UnzipImpl(const base::FilePath& image_path,
-                 const base::FilePath& temp_dir);
   void OnError(const std::string& error);
   void OnOpenSuccess(const base::FilePath& image_path);
   void OnComplete();
   void OnProgress(int64_t total_bytes, int64_t curr_bytes);
 
-  scoped_refptr<base::SequencedTaskRunner> owner_task_runner_;
-
   base::Callback<void(const base::FilePath&)> open_callback_;
   base::Closure complete_callback_;
   base::Callback<void(const std::string&)> failure_callback_;
diff --git a/chrome/browser/media/history/media_history_browsertest.cc b/chrome/browser/media/history/media_history_browsertest.cc
index a636b62e..85a6e7d 100644
--- a/chrome/browser/media/history/media_history_browsertest.cc
+++ b/chrome/browser/media/history/media_history_browsertest.cc
@@ -112,6 +112,14 @@
     return played;
   }
 
+  static bool EnterPictureInPicture(Browser* browser) {
+    bool success = false;
+    return content::ExecuteScriptAndExtractBool(
+               browser->tab_strip_model()->GetActiveWebContents(),
+               "enterPictureInPicture();", &success) &&
+           success;
+  }
+
   static bool SetMediaMetadata(Browser* browser) {
     return content::ExecuteScript(
         browser->tab_strip_model()->GetActiveWebContents(),
@@ -399,8 +407,8 @@
     observer.WaitForExpectedImagesOfType(
         media_session::mojom::MediaSessionImageType::kArtwork,
         expected_artwork);
-    observer.WaitForAudioVideoState(
-        media_session::mojom::MediaAudioVideoState::kAudioVideo);
+    observer.WaitForAudioVideoStates(
+        {media_session::mojom::MediaAudioVideoState::kAudioVideo});
   }
 
   SimulateNavigationToCommit(browser);
@@ -473,8 +481,8 @@
     observer.WaitForState(
         media_session::mojom::MediaSessionInfo::SessionState::kActive);
     observer.WaitForExpectedMetadata(expected_metadata);
-    observer.WaitForAudioVideoState(
-        media_session::mojom::MediaAudioVideoState::kAudioVideo);
+    observer.WaitForAudioVideoStates(
+        {media_session::mojom::MediaAudioVideoState::kAudioVideo});
   }
 
   SimulateNavigationToCommit(browser);
@@ -518,8 +526,8 @@
     observer.WaitForState(
         media_session::mojom::MediaSessionInfo::SessionState::kActive);
     observer.WaitForExpectedMetadata(expected_metadata);
-    observer.WaitForAudioVideoState(
-        media_session::mojom::MediaAudioVideoState::kAudioVideo);
+    observer.WaitForAudioVideoStates(
+        {media_session::mojom::MediaAudioVideoState::kAudioVideo});
   }
 
   SimulateNavigationToCommit(browser);
@@ -599,8 +607,8 @@
     observer.WaitForState(
         media_session::mojom::MediaSessionInfo::SessionState::kActive);
     observer.WaitForExpectedMetadata(GetExpectedMetadata());
-    observer.WaitForAudioVideoState(
-        media_session::mojom::MediaAudioVideoState::kAudioVideo);
+    observer.WaitForAudioVideoStates(
+        {media_session::mojom::MediaAudioVideoState::kAudioVideo});
   }
 
   SimulateNavigationToCommit(browser);
@@ -614,8 +622,8 @@
     observer.WaitForState(
         media_session::mojom::MediaSessionInfo::SessionState::kActive);
     observer.WaitForExpectedMetadata(expected_default_metadata);
-    observer.WaitForAudioVideoState(
-        media_session::mojom::MediaAudioVideoState::kAudioVideo);
+    observer.WaitForAudioVideoStates(
+        {media_session::mojom::MediaAudioVideoState::kAudioVideo});
   }
 
   SimulateNavigationToCommit(browser);
@@ -707,8 +715,8 @@
     observer.WaitForState(
         media_session::mojom::MediaSessionInfo::SessionState::kActive);
     observer.WaitForExpectedMetadata(expected_default_metadata);
-    observer.WaitForAudioVideoState(
-        media_session::mojom::MediaAudioVideoState::kAudioVideo);
+    observer.WaitForAudioVideoStates(
+        {media_session::mojom::MediaAudioVideoState::kAudioVideo});
   }
 
   SimulateNavigationToCommit(browser);
@@ -740,8 +748,8 @@
     observer.WaitForState(
         media_session::mojom::MediaSessionInfo::SessionState::kActive);
     observer.WaitForExpectedMetadata(GetExpectedMetadata());
-    observer.WaitForAudioVideoState(
-        media_session::mojom::MediaAudioVideoState::kAudioVideo);
+    observer.WaitForAudioVideoStates(
+        {media_session::mojom::MediaAudioVideoState::kAudioVideo});
   }
 
   SimulateNavigationToCommit(browser);
@@ -1060,8 +1068,8 @@
         *GetMediaSession(browser));
     observer.WaitForState(
         media_session::mojom::MediaSessionInfo::SessionState::kActive);
-    observer.WaitForAudioVideoState(
-        media_session::mojom::MediaAudioVideoState::kAudioOnly);
+    observer.WaitForAudioVideoStates(
+        {media_session::mojom::MediaAudioVideoState::kAudioOnly});
   }
 
   SimulateNavigationToCommit(browser);
@@ -1086,6 +1094,29 @@
 }
 
 IN_PROC_BROWSER_TEST_P(MediaHistoryBrowserTest,
+                       DoNotRecordSessionForVideoOnlyInPictureInPicture) {
+  auto* browser = CreateBrowserFromParam();
+
+  ASSERT_TRUE(SetupPageAndStartPlayingVideoOnly(browser, GetTestURL()));
+  ASSERT_TRUE(EnterPictureInPicture(browser));
+
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(
+        *GetMediaSession(browser));
+    observer.WaitForState(
+        media_session::mojom::MediaSessionInfo::SessionState::kActive);
+    observer.WaitForAudioVideoStates(
+        {media_session::mojom::MediaAudioVideoState::kVideoOnly});
+  }
+
+  SimulateNavigationToCommit(browser);
+
+  // Verify the session was not recorded.
+  auto sessions = GetPlaybackSessionsSync(GetMediaHistoryService(browser), 1);
+  EXPECT_TRUE(sessions.empty());
+}
+
+IN_PROC_BROWSER_TEST_P(MediaHistoryBrowserTest,
                        ResetFeedsWhenBrowsingDataCleared) {
   auto* browser = CreateBrowserFromParam();
   auto* service = GetMediaHistoryService(browser);
diff --git a/chrome/browser/media/history/media_history_contents_observer.cc b/chrome/browser/media/history/media_history_contents_observer.cc
index 4e839d4..c3806cc 100644
--- a/chrome/browser/media/history/media_history_contents_observer.cc
+++ b/chrome/browser/media/history/media_history_contents_observer.cc
@@ -69,11 +69,11 @@
     has_been_active_ = true;
   }
 
-  if (session_info->audio_video_state ==
-      media_session::mojom::MediaAudioVideoState::kAudioVideo) {
-    has_video_ = true;
+  if (base::Contains(*session_info->audio_video_states,
+                     media_session::mojom::MediaAudioVideoState::kAudioVideo)) {
+    has_audio_and_video_ = true;
   } else {
-    has_video_ = false;
+    has_audio_and_video_ = false;
   }
 }
 
@@ -112,7 +112,7 @@
   // If the media session has never played anything, does not have any metadata
   // or does not have video then we should not commit the media session.
   if (!has_been_active_ || !cached_metadata_ || cached_metadata_->IsEmpty() ||
-      !service_ || !has_video_) {
+      !service_ || !has_audio_and_video_) {
     return;
   }
 
diff --git a/chrome/browser/media/history/media_history_contents_observer.h b/chrome/browser/media/history/media_history_contents_observer.h
index e184405..9d156d7 100644
--- a/chrome/browser/media/history/media_history_contents_observer.h
+++ b/chrome/browser/media/history/media_history_contents_observer.h
@@ -59,8 +59,8 @@
   // Stores whether the media session on this web contents have ever played.
   bool has_been_active_ = false;
 
-  // Stores whether the media session on this web contents has video.
-  bool has_video_ = false;
+  // Stores whether the media session on this web contents has audio and video.
+  bool has_audio_and_video_ = false;
 
   // If the web contents is currently navigating then we freeze any updates to
   // the media session metadata and position. This is because it is cleared
diff --git a/chrome/browser/nearby_sharing/nearby_share_delegate_impl_unittest.cc b/chrome/browser/nearby_sharing/nearby_share_delegate_impl_unittest.cc
index 8d0398b..7bd556b 100644
--- a/chrome/browser/nearby_sharing/nearby_share_delegate_impl_unittest.cc
+++ b/chrome/browser/nearby_sharing/nearby_share_delegate_impl_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/nearby_sharing/nearby_share_delegate_impl.h"
 
+#include <memory>
+
 #include "ash/public/cpp/nearby_share_controller.h"
 #include "ash/public/cpp/session/session_controller.h"
 #include "base/time/clock.h"
@@ -44,9 +46,10 @@
   NearbyShareDelegateImplTest()
       : task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME),
         test_local_device_data_(kDefaultDeviceName),
-        settings_(&test_pref_service_, &test_local_device_data_),
         delegate_(&controller_) {
     RegisterNearbySharingPrefs(test_pref_service_.registry());
+    settings_ = std::make_unique<NearbyShareSettings>(&test_pref_service_,
+                                                      &test_local_device_data_);
   }
 
   ~NearbyShareDelegateImplTest() override = default;
@@ -66,10 +69,10 @@
   }
 
   void SetUp() override {
-    settings_.SetEnabled(false);
+    settings_->SetEnabled(false);
 
     EXPECT_CALL(nearby_share_service_, GetSettings())
-        .WillRepeatedly(Return(&settings_));
+        .WillRepeatedly(Return(settings_.get()));
     EXPECT_CALL(nearby_share_service_, IsInHighVisibility())
         .WillRepeatedly(ReturnPointee(&high_visibility_on_));
     EXPECT_CALL(nearby_share_service_, AddObserver(_))
@@ -87,13 +90,15 @@
     delegate_.set_settings_opener_for_test(std::move(settings_opener));
   }
 
+  NearbyShareSettings* settings() { return settings_.get(); }
+
  protected:
   content::BrowserTaskEnvironment task_environment_;
   MockNearbySharingService nearby_share_service_;
   TestSessionController session_controller_;
   sync_preferences::TestingPrefServiceSyncable test_pref_service_;
   FakeNearbyShareLocalDeviceDataManager test_local_device_data_;
-  NearbyShareSettings settings_;
+  std::unique_ptr<NearbyShareSettings> settings_;
   MockSettingsOpener* settings_opener_;
   MockNearbyShareController controller_;
   NearbyShareDelegateImpl delegate_;
@@ -102,7 +107,7 @@
 };
 
 TEST_F(NearbyShareDelegateImplTest, StartHighVisibilityAndTimeout) {
-  settings_.SetEnabled(true);
+  settings()->SetEnabled(true);
 
   EXPECT_CALL(*settings_opener_, ShowSettingsPage(_));
   EXPECT_CALL(controller_, HighVisibilityEnabledChanged(true));
@@ -119,7 +124,7 @@
 }
 
 TEST_F(NearbyShareDelegateImplTest, StartStopHighVisibility) {
-  settings_.SetEnabled(true);
+  settings()->SetEnabled(true);
 
   EXPECT_CALL(*settings_opener_, ShowSettingsPage(_));
   EXPECT_CALL(controller_, HighVisibilityEnabledChanged(true));
@@ -135,7 +140,7 @@
 }
 
 TEST_F(NearbyShareDelegateImplTest, ShowOnboardingAndTurnOnHighVisibility) {
-  settings_.SetEnabled(false);
+  settings()->SetEnabled(false);
 
   // Called once to start onboarding and once to enter high visibility
   EXPECT_CALL(*settings_opener_, ShowSettingsPage(_)).Times(2);
@@ -146,7 +151,7 @@
 
   // Delegate will observe Nearby Share enabled within onboarding wait period
   // and will turn on high visibility.
-  settings_.SetEnabled(true);
+  settings()->SetEnabled(true);
   SetHighVisibilityOn(true);
 
   EXPECT_CALL(nearby_share_service_, ClearForegroundReceiveSurfaces());
@@ -158,10 +163,10 @@
 }
 
 TEST_F(NearbyShareDelegateImplTest, ShowOnboardingAndTimeout) {
-  settings_.SetEnabled(false);
+  settings()->SetEnabled(false);
 
   EXPECT_CALL(nearby_share_service_, GetSettings())
-      .WillRepeatedly(Return(&settings_));
+      .WillRepeatedly(Return(settings()));
   EXPECT_CALL(*settings_opener_, ShowSettingsPage(_));
 
   delegate_.EnableHighVisibility();
@@ -173,11 +178,11 @@
 
   // Delegate will observe Nearby Share enabled outside of onboarding wait
   // period and will not turn on high visibility.
-  settings_.SetEnabled(true);
+  settings()->SetEnabled(true);
 }
 
 TEST_F(NearbyShareDelegateImplTest, StopHighVisibilityOnScreenLock) {
-  settings_.SetEnabled(true);
+  settings()->SetEnabled(true);
 
   EXPECT_CALL(controller_, HighVisibilityEnabledChanged(true));
   EXPECT_CALL(*settings_opener_, ShowSettingsPage(_));
diff --git a/chrome/browser/nearby_sharing/nearby_share_settings.cc b/chrome/browser/nearby_sharing/nearby_share_settings.cc
index 796d844..1232531 100644
--- a/chrome/browser/nearby_sharing/nearby_share_settings.cc
+++ b/chrome/browser/nearby_sharing/nearby_share_settings.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/nearby_sharing/nearby_share_settings.h"
 
+#include "base/metrics/histogram_functions.h"
 #include "base/values.h"
 #include "chrome/browser/nearby_sharing/common/nearby_share_enums.h"
 #include "chrome/browser/nearby_sharing/common/nearby_share_prefs.h"
@@ -34,6 +35,11 @@
                           base::Unretained(this)));
 
   local_device_data_manager_->AddObserver(this);
+
+  if (GetEnabled()) {
+    base::UmaHistogramEnumeration("Nearby.Share.VisibilityChoice",
+                                  GetVisibility());
+  }
 }
 
 NearbyShareSettings::~NearbyShareSettings() {
diff --git a/chrome/browser/nearby_sharing/nearby_share_settings_unittest.cc b/chrome/browser/nearby_sharing/nearby_share_settings_unittest.cc
index 8e1867d..0a77a63 100644
--- a/chrome/browser/nearby_sharing/nearby_share_settings_unittest.cc
+++ b/chrome/browser/nearby_sharing/nearby_share_settings_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/nearby_sharing/nearby_share_settings.h"
 
+#include <memory>
+
 #include "base/feature_list.h"
 #include "base/run_loop.h"
 #include "base/test/bind.h"
@@ -70,50 +72,59 @@
     scoped_feature_list_.InitAndEnableFeature(features::kNearbySharing);
 
     RegisterNearbySharingPrefs(pref_service_.registry());
+    nearby_share_settings_ = std::make_unique<NearbyShareSettings>(
+        &pref_service_, &local_device_data_manager_);
+    nearby_share_settings_waiter_ =
+        std::make_unique<NearbyShareSettingsAsyncWaiter>(
+            nearby_share_settings_.get());
 
-    nearby_share_settings_.AddSettingsObserver(
+    nearby_share_settings_->AddSettingsObserver(
         observer_.receiver_.BindNewPipeAndPassRemote());
   }
   ~NearbyShareSettingsTest() override = default;
 
   void FlushMojoMessages() { observer_.receiver_.FlushForTesting(); }
 
+  NearbyShareSettings* settings() { return nearby_share_settings_.get(); }
+
+  NearbyShareSettingsAsyncWaiter* settings_waiter() {
+    return nearby_share_settings_waiter_.get();
+  }
+
  protected:
   content::BrowserTaskEnvironment task_environment_;
   base::test::ScopedFeatureList scoped_feature_list_;
   TestingPrefServiceSimple pref_service_;
   FakeNearbyShareLocalDeviceDataManager local_device_data_manager_;
   FakeNearbyShareSettingsObserver observer_;
-  NearbyShareSettings nearby_share_settings_{&pref_service_,
-                                             &local_device_data_manager_};
-  NearbyShareSettingsAsyncWaiter nearby_share_settings_waiter_{
-      &nearby_share_settings_};
+  std::unique_ptr<NearbyShareSettings> nearby_share_settings_;
+  std::unique_ptr<NearbyShareSettingsAsyncWaiter> nearby_share_settings_waiter_;
 };
 
 TEST_F(NearbyShareSettingsTest, GetAndSetEnabled) {
   EXPECT_EQ(false, observer_.enabled);
-  nearby_share_settings_.SetEnabled(true);
-  EXPECT_EQ(true, nearby_share_settings_.GetEnabled());
+  settings()->SetEnabled(true);
+  EXPECT_EQ(true, settings()->GetEnabled());
   FlushMojoMessages();
   EXPECT_EQ(true, observer_.enabled);
 
   bool enabled = false;
-  nearby_share_settings_waiter_.GetEnabled(&enabled);
+  settings_waiter()->GetEnabled(&enabled);
   EXPECT_EQ(true, enabled);
 
-  nearby_share_settings_.SetEnabled(false);
-  EXPECT_EQ(false, nearby_share_settings_.GetEnabled());
+  settings()->SetEnabled(false);
+  EXPECT_EQ(false, settings()->GetEnabled());
   FlushMojoMessages();
   EXPECT_EQ(false, observer_.enabled);
 
-  nearby_share_settings_waiter_.GetEnabled(&enabled);
+  settings_waiter()->GetEnabled(&enabled);
   EXPECT_EQ(false, enabled);
 
   // Verify that setting the value to false again value doesn't trigger an
   // observer event.
   observer_.enabled = true;
-  nearby_share_settings_.SetEnabled(false);
-  EXPECT_EQ(false, nearby_share_settings_.GetEnabled());
+  settings()->SetEnabled(false);
+  EXPECT_EQ(false, settings()->GetEnabled());
   FlushMojoMessages();
   // the observers's value should not have been updated.
   EXPECT_EQ(true, observer_.enabled);
@@ -123,20 +134,20 @@
   auto result = nearby_share::mojom::DeviceNameValidationResult::kValid;
   local_device_data_manager_.set_next_validation_result(
       nearby_share::mojom::DeviceNameValidationResult::kErrorEmpty);
-  nearby_share_settings_waiter_.ValidateDeviceName("", &result);
+  settings_waiter()->ValidateDeviceName("", &result);
   EXPECT_EQ(result,
             nearby_share::mojom::DeviceNameValidationResult::kErrorEmpty);
 
   local_device_data_manager_.set_next_validation_result(
       nearby_share::mojom::DeviceNameValidationResult::kValid);
-  nearby_share_settings_waiter_.ValidateDeviceName(
-      "this string is 32 bytes in UTF-8", &result);
+  settings_waiter()->ValidateDeviceName("this string is 32 bytes in UTF-8",
+                                        &result);
   EXPECT_EQ(result, nearby_share::mojom::DeviceNameValidationResult::kValid);
 }
 
 TEST_F(NearbyShareSettingsTest, GetAndSetDeviceName) {
   std::string name = "not_the_default";
-  nearby_share_settings_waiter_.GetDeviceName(&name);
+  settings_waiter()->GetDeviceName(&name);
   EXPECT_EQ(kDefaultDeviceName, name);
 
   // When we get a validation error, setting the name should not succeed.
@@ -144,51 +155,51 @@
   auto result = nearby_share::mojom::DeviceNameValidationResult::kValid;
   local_device_data_manager_.set_next_validation_result(
       nearby_share::mojom::DeviceNameValidationResult::kErrorEmpty);
-  nearby_share_settings_waiter_.SetDeviceName("", &result);
+  settings_waiter()->SetDeviceName("", &result);
   EXPECT_EQ(result,
             nearby_share::mojom::DeviceNameValidationResult::kErrorEmpty);
-  EXPECT_EQ(kDefaultDeviceName, nearby_share_settings_.GetDeviceName());
+  EXPECT_EQ(kDefaultDeviceName, settings()->GetDeviceName());
 
   // When the name is valid, setting should succeed.
   EXPECT_EQ("uncalled", observer_.device_name);
   result = nearby_share::mojom::DeviceNameValidationResult::kValid;
   local_device_data_manager_.set_next_validation_result(
       nearby_share::mojom::DeviceNameValidationResult::kValid);
-  nearby_share_settings_waiter_.SetDeviceName("d", &result);
+  settings_waiter()->SetDeviceName("d", &result);
   EXPECT_EQ(result, nearby_share::mojom::DeviceNameValidationResult::kValid);
-  EXPECT_EQ("d", nearby_share_settings_.GetDeviceName());
+  EXPECT_EQ("d", settings()->GetDeviceName());
 
   EXPECT_EQ("uncalled", observer_.device_name);
   FlushMojoMessages();
   EXPECT_EQ("d", observer_.device_name);
 
-  nearby_share_settings_waiter_.GetDeviceName(&name);
+  settings_waiter()->GetDeviceName(&name);
   EXPECT_EQ("d", name);
 }
 
 TEST_F(NearbyShareSettingsTest, GetAndSetDataUsage) {
   EXPECT_EQ(nearby_share::mojom::DataUsage::kUnknown, observer_.data_usage);
-  nearby_share_settings_.SetDataUsage(DataUsage::kOffline);
-  EXPECT_EQ(DataUsage::kOffline, nearby_share_settings_.GetDataUsage());
+  settings()->SetDataUsage(DataUsage::kOffline);
+  EXPECT_EQ(DataUsage::kOffline, settings()->GetDataUsage());
   FlushMojoMessages();
   EXPECT_EQ(nearby_share::mojom::DataUsage::kOffline, observer_.data_usage);
 
   nearby_share::mojom::DataUsage data_usage =
       nearby_share::mojom::DataUsage::kUnknown;
-  nearby_share_settings_waiter_.GetDataUsage(&data_usage);
+  settings_waiter()->GetDataUsage(&data_usage);
   EXPECT_EQ(nearby_share::mojom::DataUsage::kOffline, data_usage);
 }
 
 TEST_F(NearbyShareSettingsTest, GetAndSetVisibility) {
   EXPECT_EQ(nearby_share::mojom::Visibility::kUnknown, observer_.visibility);
-  nearby_share_settings_.SetVisibility(Visibility::kNoOne);
-  EXPECT_EQ(Visibility::kNoOne, nearby_share_settings_.GetVisibility());
+  settings()->SetVisibility(Visibility::kNoOne);
+  EXPECT_EQ(Visibility::kNoOne, settings()->GetVisibility());
   FlushMojoMessages();
   EXPECT_EQ(nearby_share::mojom::Visibility::kNoOne, observer_.visibility);
 
   nearby_share::mojom::Visibility visibility =
       nearby_share::mojom::Visibility::kUnknown;
-  nearby_share_settings_waiter_.GetVisibility(&visibility);
+  settings_waiter()->GetVisibility(&visibility);
   EXPECT_EQ(nearby_share::mojom::Visibility::kNoOne, visibility);
 }
 
@@ -197,22 +208,22 @@
 
   std::vector<std::string> allowed_contacts;
 
-  nearby_share_settings_waiter_.GetAllowedContacts(&allowed_contacts);
+  settings_waiter()->GetAllowedContacts(&allowed_contacts);
   EXPECT_EQ(0u, allowed_contacts.size());
 
-  nearby_share_settings_.SetAllowedContacts({id1});
+  settings()->SetAllowedContacts({id1});
   FlushMojoMessages();
   EXPECT_EQ(1u, observer_.allowed_contacts.size());
   EXPECT_EQ(true, base::Contains(observer_.allowed_contacts, id1));
 
-  nearby_share_settings_waiter_.GetAllowedContacts(&allowed_contacts);
+  settings_waiter()->GetAllowedContacts(&allowed_contacts);
   EXPECT_EQ(1u, allowed_contacts.size());
   EXPECT_EQ(true, base::Contains(allowed_contacts, id1));
 
-  nearby_share_settings_.SetAllowedContacts({});
+  settings()->SetAllowedContacts({});
   FlushMojoMessages();
   EXPECT_EQ(0u, observer_.allowed_contacts.size());
 
-  nearby_share_settings_waiter_.GetAllowedContacts(&allowed_contacts);
+  settings_waiter()->GetAllowedContacts(&allowed_contacts);
   EXPECT_EQ(0u, allowed_contacts.size());
 }
diff --git a/chrome/browser/notifications/notification_permission_context_unittest.cc b/chrome/browser/notifications/notification_permission_context_unittest.cc
index 122c106..101e56b 100644
--- a/chrome/browser/notifications/notification_permission_context_unittest.cc
+++ b/chrome/browser/notifications/notification_permission_context_unittest.cc
@@ -325,8 +325,16 @@
                 .content_setting);
 }
 
+#if defined(OS_MAC) && defined(ARCH_CPU_ARM64)
+// Bulk-disabled for arm64 bot stabilization: https://crbug.com/1154345
+#define MAYBE_TestDenyInIncognitoAfterDelay \
+  DISABLED_TestDenyInIncognitoAfterDelay
+#else
+#define MAYBE_TestDenyInIncognitoAfterDelay TestDenyInIncognitoAfterDelay
+#endif
+
 // Tests auto-denial after a time delay in incognito.
-TEST_F(NotificationPermissionContextTest, TestDenyInIncognitoAfterDelay) {
+TEST_F(NotificationPermissionContextTest, MAYBE_TestDenyInIncognitoAfterDelay) {
   TestNotificationPermissionContext permission_context(
       profile()->GetPrimaryOTRProfile());
   GURL url("https://www.example.com");
diff --git a/chrome/browser/optimization_guide/prediction/prediction_manager_browsertest.cc b/chrome/browser/optimization_guide/prediction/prediction_manager_browsertest.cc
index 19aaa9a..25560f6 100644
--- a/chrome/browser/optimization_guide/prediction/prediction_manager_browsertest.cc
+++ b/chrome/browser/optimization_guide/prediction/prediction_manager_browsertest.cc
@@ -12,15 +12,19 @@
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/download/download_service_factory.h"
 #include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
 #include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
 #include "chrome/browser/optimization_guide/optimization_guide_session_statistic.h"
 #include "chrome/browser/optimization_guide/prediction/prediction_manager.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_key.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
+#include "components/download/public/background_service/download_service.h"
+#include "components/download/public/background_service/logger.h"
 #include "components/metrics/content/subprocess_metrics_provider.h"
 #include "components/optimization_guide/optimization_guide_constants.h"
 #include "components/optimization_guide/optimization_guide_features.h"
@@ -40,6 +44,9 @@
 
 namespace {
 
+const char kOptimizationGuidePredictionModelsClient[] =
+    "OptimizationGuidePredictionModels";
+
 // Fetch and calculate the total number of samples from all the bins for
 // |histogram_name|. Note: from some browertests run (such as chromeos) there
 // might be two profiles created, and this will return the total sample count
@@ -181,7 +188,9 @@
   kSuccessfulWithModelsAndFeatures = 0,
   kSuccessfulWithFeaturesAndNoModels = 1,
   kSuccessfulWithModelsAndNoFeatures = 2,
-  kUnsuccessful = 3,
+  kSuccessfulWithValidModelFile = 3,
+  kSuccessfulWithInvalidModelFile = 4,
+  kUnsuccessful = 5,
 };
 
 // A WebContentsObserver that asks whether an optimization target can be
@@ -241,7 +250,8 @@
 
     models_server_ = std::make_unique<net::EmbeddedTestServer>(
         net::EmbeddedTestServer::TYPE_HTTPS);
-    models_server_->ServeFilesFromSourceDirectory("chrome/test/data/previews");
+    models_server_->ServeFilesFromSourceDirectory(
+        "chrome/test/data/optimization_guide");
     models_server_->RegisterRequestHandler(base::BindRepeating(
         &PredictionManagerBrowserTestBase::HandleGetModelsRequest,
         base::Unretained(this)));
@@ -259,6 +269,7 @@
     ASSERT_TRUE(https_server_->Start());
     https_url_with_content_ = https_server_->GetURL("/english_page.html");
     https_url_without_content_ = https_server_->GetURL("/empty.html");
+    model_file_url_ = models_server_->GetURL("/unsignedmodel.crx3");
 
     // Set up an OptimizationGuideKeyedService consumer.
     consumer_ = std::make_unique<OptimizationGuideConsumerWebContentsObserver>(
@@ -355,6 +366,9 @@
  private:
   std::unique_ptr<net::test_server::HttpResponse> HandleGetModelsRequest(
       const net::test_server::HttpRequest& request) {
+    if (request.GetURL() == model_file_url_)
+      return std::unique_ptr<net::test_server::HttpResponse>();
+
     std::unique_ptr<net::test_server::BasicHttpResponse> response;
 
     response = std::make_unique<net::test_server::BasicHttpResponse>();
@@ -388,6 +402,14 @@
     } else if (response_type_ == PredictionModelsFetcherRemoteResponseType::
                                      kSuccessfulWithModelsAndNoFeatures) {
       get_models_response->clear_host_model_features();
+    } else if (response_type_ == PredictionModelsFetcherRemoteResponseType::
+                                     kSuccessfulWithInvalidModelFile) {
+      get_models_response->mutable_models(0)->mutable_model()->set_download_url(
+          https_url_with_content_.spec());
+    } else if (response_type_ == PredictionModelsFetcherRemoteResponseType::
+                                     kSuccessfulWithValidModelFile) {
+      get_models_response->mutable_models(0)->mutable_model()->set_download_url(
+          model_file_url_.spec());
     } else if (response_type_ ==
                PredictionModelsFetcherRemoteResponseType::kUnsuccessful) {
       response->set_code(net::HTTP_NOT_FOUND);
@@ -399,6 +421,7 @@
     return std::move(response);
   }
 
+  GURL model_file_url_;
   GURL https_url_with_content_, https_url_without_content_;
   std::unique_ptr<net::EmbeddedTestServer> https_server_;
   std::unique_ptr<net::EmbeddedTestServer> models_server_;
@@ -409,7 +432,6 @@
   base::flat_set<uint32_t> expected_field_trial_name_hashes_;
 };
 
-// Parametrized on whether the ML Service path is enabled.
 class PredictionManagerBrowserTest : public PredictionManagerBrowserTestBase {
  public:
   PredictionManagerBrowserTest() = default;
@@ -730,4 +752,187 @@
   run_loop->Run();
 }
 
+// Implementation of a download system logger that provides the ability to wait
+// for certain events to happen, notably added and progressing downloads.
+class DownloadServiceObserver : public download::Logger::Observer {
+ public:
+  using DownloadCompletedCallback = base::OnceCallback<void()>;
+
+  DownloadServiceObserver() = default;
+  ~DownloadServiceObserver() override = default;
+
+  // Sets |callback| to be invoked when a download has completed.
+  void set_download_completed_callback(DownloadCompletedCallback callback) {
+    download_completed_callback_ = std::move(callback);
+  }
+
+  // download::Logger::Observer implementation:
+  void OnServiceStatusChanged(const base::Value& service_status) override {}
+  void OnServiceDownloadsAvailable(
+      const base::Value& service_downloads) override {}
+  void OnServiceDownloadFailed(const base::Value& service_download) override {}
+  void OnServiceRequestMade(const base::Value& service_request) override {}
+  void OnServiceDownloadChanged(const base::Value& service_download) override {
+    const std::string& client = service_download.FindKey("client")->GetString();
+    const std::string& state = service_download.FindKey("state")->GetString();
+
+    if (client != kOptimizationGuidePredictionModelsClient)
+      return;
+
+    if (state == "COMPLETE" && download_completed_callback_)
+      std::move(download_completed_callback_).Run();
+  }
+
+ private:
+  DownloadCompletedCallback download_completed_callback_;
+};
+
+class ModelFileObserver : public OptimizationTargetModelObserver {
+ public:
+  using ModelFileReceivedCallback =
+      base::OnceCallback<void(proto::OptimizationTarget,
+                              const base::FilePath&)>;
+
+  ModelFileObserver() = default;
+  ~ModelFileObserver() override = default;
+
+  void set_model_file_received_callback(ModelFileReceivedCallback callback) {
+    file_received_callback_ = std::move(callback);
+  }
+
+  void OnModelFileUpdated(proto::OptimizationTarget optimization_target,
+                          const base::FilePath& file_path) override {
+    if (file_received_callback_)
+      std::move(file_received_callback_).Run(optimization_target, file_path);
+  }
+
+ private:
+  ModelFileReceivedCallback file_received_callback_;
+};
+
+class PredictionManagerModelDownloadingBrowserTest
+    : public PredictionManagerBrowserTest {
+ public:
+  PredictionManagerModelDownloadingBrowserTest() = default;
+  ~PredictionManagerModelDownloadingBrowserTest() override = default;
+
+  void SetUpOnMainThread() override {
+    download_service_observer_ = std::make_unique<DownloadServiceObserver>();
+    DownloadServiceFactory::GetForKey(browser()->profile()->GetProfileKey())
+        ->GetLogger()
+        ->AddObserver(download_service_observer_.get());
+
+    model_file_observer_ = std::make_unique<ModelFileObserver>();
+
+    PredictionManagerBrowserTest::SetUpOnMainThread();
+  }
+
+  void TearDownOnMainThread() override {
+    PredictionManagerBrowserTest::TearDownOnMainThread();
+
+    DownloadServiceFactory::GetForKey(browser()->profile()->GetProfileKey())
+        ->GetLogger()
+        ->RemoveObserver(download_service_observer_.get());
+  }
+
+  DownloadServiceObserver* download_observer() {
+    return download_service_observer_.get();
+  }
+
+  ModelFileObserver* model_file_observer() {
+    return model_file_observer_.get();
+  }
+
+  void RegisterModelFileObserverWithKeyedService() {
+    OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
+        ->AddObserverForOptimizationTargetModel(
+            proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD,
+            model_file_observer_.get());
+  }
+
+ private:
+  void InitializeFeatureList() override {
+    scoped_feature_list_.InitWithFeaturesAndParameters(
+        {
+            {features::kOptimizationHints, {}},
+            {features::kRemoteOptimizationGuideFetching, {}},
+            {features::kOptimizationTargetPrediction, {}},
+            {features::kOptimizationGuideModelDownloading,
+             {{"unrestricted_model_downloading", "true"}}},
+        },
+        {});
+  }
+
+  std::unique_ptr<DownloadServiceObserver> download_service_observer_;
+  std::unique_ptr<ModelFileObserver> model_file_observer_;
+};
+
+IN_PROC_BROWSER_TEST_F(
+    PredictionManagerModelDownloadingBrowserTest,
+    DISABLE_ON_WIN_MAC_CHROMEOS(
+        TestDownloadUrlAcceptedByDownloadServiceButInvalid)) {
+  base::HistogramTester histogram_tester;
+
+  SetResponseType(PredictionModelsFetcherRemoteResponseType::
+                      kSuccessfulWithInvalidModelFile);
+
+  std::unique_ptr<base::RunLoop> completed_run_loop =
+      std::make_unique<base::RunLoop>();
+  download_observer()->set_download_completed_callback(
+      base::BindOnce([](base::RunLoop* run_loop) { run_loop->Quit(); },
+                     completed_run_loop.get()));
+  // Registering should initiate the fetch and receive a response with a model
+  // containing a download URL and then subsequently downloaded.
+  RegisterModelFileObserverWithKeyedService();
+
+  // Wait until the download has completed.
+  completed_run_loop->Run();
+
+  histogram_tester.ExpectUniqueSample(
+      "OptimizationGuide.PredictionModelDownloadManager.DownloadStatus",
+      PredictionModelDownloadStatus::kFailedCrxVerification, 1);
+  // An unverified file should not notify us that it's ready.
+  histogram_tester.ExpectTotalCount(
+      "OptimizationGuide.PredictionModelUpdateVersion.PainfulPageLoad", 0);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    PredictionManagerModelDownloadingBrowserTest,
+    DISABLE_ON_WIN_MAC_CHROMEOS(TestSuccessfulModelFileFlow)) {
+  // TODO(crbug/1146151): Remove this switch once we can produce a signed model
+  // file.
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(
+      switches::kDisableModelDownloadVerificationForTesting);
+
+  base::HistogramTester histogram_tester;
+
+  SetResponseType(
+      PredictionModelsFetcherRemoteResponseType::kSuccessfulWithValidModelFile);
+
+  std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
+  model_file_observer()->set_model_file_received_callback(base::BindOnce(
+      [](base::RunLoop* run_loop, proto::OptimizationTarget optimization_target,
+         const base::FilePath& file_path) {
+        EXPECT_EQ(optimization_target,
+                  proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
+        run_loop->Quit();
+      },
+      run_loop.get()));
+
+  // Registering should initiate the fetch and receive a response with a model
+  // containing a download URL and then subsequently downloaded.
+  RegisterModelFileObserverWithKeyedService();
+
+  // Wait until the observer receives the file.
+  run_loop->Run();
+
+  histogram_tester.ExpectUniqueSample(
+      "OptimizationGuide.PredictionModelDownloadManager.DownloadStatus",
+      PredictionModelDownloadStatus::kSuccess, 1);
+  histogram_tester.ExpectUniqueSample(
+      "OptimizationGuide.PredictionModelUpdateVersion.PainfulPageLoad", 123, 1);
+  histogram_tester.ExpectUniqueSample(
+      "OptimizationGuide.PredictionModelLoadedVersion.PainfulPageLoad", 123, 1);
+}
+
 }  // namespace optimization_guide
diff --git a/chrome/browser/optimization_guide/prediction/prediction_model_download_manager.cc b/chrome/browser/optimization_guide/prediction/prediction_model_download_manager.cc
index 65da14c..c7a34ac 100644
--- a/chrome/browser/optimization_guide/prediction/prediction_model_download_manager.cc
+++ b/chrome/browser/optimization_guide/prediction/prediction_model_download_manager.cc
@@ -24,6 +24,7 @@
 #include "components/download/public/background_service/download_service.h"
 #include "components/optimization_guide/optimization_guide_enums.h"
 #include "components/optimization_guide/optimization_guide_features.h"
+#include "components/optimization_guide/optimization_guide_switches.h"
 #include "components/optimization_guide/optimization_guide_util.h"
 #include "components/services/unzip/content/unzip_service.h"
 #include "components/services/unzip/public/cpp/unzip.h"
@@ -214,7 +215,7 @@
     const base::FilePath& file_path) {
   DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
 
-  if (should_verify_download_) {
+  if (!switches::ShouldSkipModelDownloadVerificationForTesting()) {
     // Verify that the |file_path| contains a file signed with a key we trust.
     crx_file::VerifierResult verifier_result = crx_file::Verify(
         file_path, crx_file::VerifierFormat::CRX3_WITH_PUBLISHER_PROOF,
@@ -269,7 +270,7 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   // Clean up original download file when this function finishes.
-  base::SequencedTaskRunnerHandle::Get()->PostTask(
+  background_task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(base::GetDeleteFileCallback(), original_file_path));
 
@@ -351,8 +352,4 @@
     observer.OnModelReady(*model);
 }
 
-void PredictionModelDownloadManager::TurnOffVerificationForTesting() {
-  should_verify_download_ = false;
-}
-
 }  // namespace optimization_guide
diff --git a/chrome/browser/optimization_guide/prediction/prediction_model_download_manager.h b/chrome/browser/optimization_guide/prediction/prediction_model_download_manager.h
index ae3522df..e846615 100644
--- a/chrome/browser/optimization_guide/prediction/prediction_model_download_manager.h
+++ b/chrome/browser/optimization_guide/prediction/prediction_model_download_manager.h
@@ -116,9 +116,6 @@
   // Must be invoked on the UI thread.
   void NotifyModelReady(const base::Optional<proto::PredictionModel>& model);
 
-  // Turns off CRX3 verification for testing.
-  void TurnOffVerificationForTesting();
-
   // The set of GUIDs that are still pending download.
   std::set<std::string> pending_download_guids_;
 
diff --git a/chrome/browser/optimization_guide/prediction/prediction_model_download_manager_unittest.cc b/chrome/browser/optimization_guide/prediction/prediction_model_download_manager_unittest.cc
index dd952b7..51a379f 100644
--- a/chrome/browser/optimization_guide/prediction/prediction_model_download_manager_unittest.cc
+++ b/chrome/browser/optimization_guide/prediction/prediction_model_download_manager_unittest.cc
@@ -21,6 +21,7 @@
 #include "components/download/public/background_service/test/mock_download_service.h"
 #include "components/optimization_guide/optimization_guide_enums.h"
 #include "components/optimization_guide/optimization_guide_features.h"
+#include "components/optimization_guide/optimization_guide_switches.h"
 #include "components/optimization_guide/optimization_guide_util.h"
 #include "components/services/unzip/content/unzip_service.h"
 #include "components/services/unzip/in_process_unzipper.h"
@@ -158,7 +159,8 @@
   }
 
   void TurnOffDownloadVerification() {
-    download_manager_->TurnOffVerificationForTesting();
+    base::CommandLine::ForCurrentProcess()->AppendSwitch(
+        switches::kDisableModelDownloadVerificationForTesting);
   }
 
  private:
diff --git a/chrome/browser/password_manager/android/save_password_message_delegate.cc b/chrome/browser/password_manager/android/save_password_message_delegate.cc
index eb83c72..9f54d6c3 100644
--- a/chrome/browser/password_manager/android/save_password_message_delegate.cc
+++ b/chrome/browser/password_manager/android/save_password_message_delegate.cc
@@ -4,11 +4,11 @@
 
 #include "chrome/browser/password_manager/android/save_password_message_delegate.h"
 
+#include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/android/android_theme_resources.h"
 #include "chrome/browser/android/resource_mapper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
-#include "chrome/browser/ui/passwords/manage_passwords_view_utils.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/messages/android/message_dispatcher_bridge.h"
 #include "components/password_manager/core/browser/password_bubble_experiment.h"
@@ -63,18 +63,25 @@
       base::BindOnce(&SavePasswordMessageDelegate::HandleDismissCallback,
                      base::Unretained(this)));
 
-  PasswordTitleType type =
-      form_to_save_->GetPendingCredentials().federation_origin.opaque()
-          ? PasswordTitleType::SAVE_PASSWORD
-          : PasswordTitleType::SAVE_ACCOUNT;
+  const password_manager::PasswordForm& pending_credentials =
+      form_to_save_->GetPendingCredentials();
 
-  message_->SetTitle(GetSavePasswordDialogTitleText(
-      web_contents_->GetVisibleURL(),
-      url::Origin::Create(form_to_save_->GetURL()), type));
-  if (type == PasswordTitleType::SAVE_PASSWORD && is_saving_google_account) {
-    message_->SetDescription(
-        l10n_util::GetStringUTF16(IDS_SAVE_PASSWORD_FOOTER));
+  int title_message_id = 0;
+  if (!pending_credentials.federation_origin.opaque()) {
+    title_message_id = is_saving_google_account ? IDS_SAVE_ACCOUNT_TO_GOOGLE
+                                                : IDS_SAVE_ACCOUNT;
+  } else {
+    title_message_id = is_saving_google_account ? IDS_SAVE_PASSWORD_TO_GOOGLE
+                                                : IDS_SAVE_PASSWORD;
   }
+
+  message_->SetTitle(l10n_util::GetStringUTF16(title_message_id));
+
+  base::string16 description = pending_credentials.username_value;
+  description.append(base::ASCIIToUTF16(" "))
+      .append(pending_credentials.password_value.size(), L'•');
+  message_->SetDescription(description);
+
   message_->SetPrimaryButtonText(
       l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_SAVE_BUTTON));
   message_->SetIconResourceId(
diff --git a/chrome/browser/password_manager/android/save_password_message_delegate_unittest.cc b/chrome/browser/password_manager/android/save_password_message_delegate_unittest.cc
index 297eb302..32c27b2 100644
--- a/chrome/browser/password_manager/android/save_password_message_delegate_unittest.cc
+++ b/chrome/browser/password_manager/android/save_password_message_delegate_unittest.cc
@@ -28,8 +28,8 @@
 
 namespace {
 constexpr char kDefaultUrl[] = "http://example.com";
-constexpr char kAlternativeUrl[] = "http://bar.com";
-constexpr char kAlternativeUrlHost[] = "bar.com";
+constexpr char kUsername[] = "username";
+constexpr char kPassword[] = "password";
 constexpr char kDismissalReasonHistogramName[] =
     "PasswordManager.SaveUIDismissalReason";
 }  // namespace
@@ -43,6 +43,7 @@
 
   std::unique_ptr<MockPasswordFormManagerForUI> CreateFormManager(
       const GURL& url);
+  void SetUsernameAndPassword(base::string16 username, base::string16 password);
 
   void CreateMessage(std::unique_ptr<PasswordFormManagerForUI> form_to_save,
                      bool is_saving_google_account);
@@ -89,6 +90,13 @@
   return form_manager;
 }
 
+void SavePasswordMessageDelegateTest::SetUsernameAndPassword(
+    base::string16 username,
+    base::string16 password) {
+  form_.username_value = std::move(username);
+  form_.password_value = std::move(password);
+}
+
 void SavePasswordMessageDelegateTest::CreateMessage(
     std::unique_ptr<PasswordFormManagerForUI> form_to_save,
     bool is_saving_google_account) {
@@ -134,12 +142,18 @@
 // Tests that message properties (title, description, icon, button text) are
 // set correctly.
 TEST_F(SavePasswordMessageDelegateTest, MessagePropertyValues) {
+  SetUsernameAndPassword(base::ASCIIToUTF16(kUsername),
+                         base::ASCIIToUTF16(kPassword));
   auto form_manager = CreateFormManager(GURL(kDefaultUrl));
   CreateMessage(std::move(form_manager), false /*is_saving_google_account*/);
 
   EXPECT_EQ(l10n_util::GetStringUTF16(IDS_SAVE_PASSWORD),
             GetMessageWrapper()->GetTitle());
-  EXPECT_EQ(base::string16(), GetMessageWrapper()->GetDescription());
+  EXPECT_NE(base::string16::npos, GetMessageWrapper()->GetDescription().find(
+                                      base::ASCIIToUTF16(kUsername)));
+  EXPECT_EQ(base::string16::npos, GetMessageWrapper()->GetDescription().find(
+                                      base::ASCIIToUTF16(kPassword)));
+
   EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_SAVE_BUTTON),
             GetMessageWrapper()->GetPrimaryButtonText());
   EXPECT_EQ(
@@ -149,28 +163,14 @@
   TriggerMessageDismissedCallback();
 }
 
-// Tests that the description is set correctly when user is syncing passwords to
+// Tests that the title is set correctly when the user is syncing passwords to
 // their Google Account.
-TEST_F(SavePasswordMessageDelegateTest, SaveToGoogleDescription) {
+TEST_F(SavePasswordMessageDelegateTest, SaveToGoogleTitle) {
   auto form_manager = CreateFormManager(GURL(kDefaultUrl));
   CreateMessage(std::move(form_manager), true /*is_saving_google_account*/);
 
-  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_SAVE_PASSWORD_FOOTER),
-            GetMessageWrapper()->GetDescription());
-
-  TriggerMessageDismissedCallback();
-}
-
-// Tests that the title is set correctly when form domain differs from current
-// page domain.
-TEST_F(SavePasswordMessageDelegateTest, TitleForDifferentDomainPassword) {
-  auto form_manager = CreateFormManager(GURL(kAlternativeUrl));
-  CreateMessage(std::move(form_manager), false /*is_saving_google_account*/);
-
-  EXPECT_NE(l10n_util::GetStringUTF16(IDS_SAVE_PASSWORD),
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_SAVE_PASSWORD_TO_GOOGLE),
             GetMessageWrapper()->GetTitle());
-  EXPECT_NE(base::string16::npos, GetMessageWrapper()->GetTitle().find(
-                                      base::ASCIIToUTF16(kAlternativeUrlHost)));
 
   TriggerMessageDismissedCallback();
 }
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc
index eca32675..c8b1a70 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -94,12 +94,12 @@
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_switches.h"
-#include "content/public/common/origin_util.h"
 #include "extensions/buildflags/buildflags.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "net/base/url_util.h"
 #include "net/cert/cert_status_flags.h"
 #include "services/metrics/public/cpp/ukm_recorder.h"
+#include "services/network/public/cpp/is_potentially_trustworthy.h"
 #include "third_party/re2/src/re2/re2.h"
 #include "url/url_constants.h"
 
@@ -751,7 +751,7 @@
 }
 
 bool ChromePasswordManagerClient::IsCommittedMainFrameSecure() const {
-  return content::IsPotentiallyTrustworthyOrigin(
+  return network::IsOriginPotentiallyTrustworthy(
       web_contents()->GetMainFrame()->GetLastCommittedOrigin());
 }
 
diff --git a/chrome/browser/policy/extension_force_install_mixin.h b/chrome/browser/policy/extension_force_install_mixin.h
index a3cea1cb..e884c7f0 100644
--- a/chrome/browser/policy/extension_force_install_mixin.h
+++ b/chrome/browser/policy/extension_force_install_mixin.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/optional.h"
@@ -117,7 +118,8 @@
   bool ForceInstallFromCrx(const base::FilePath& crx_path,
                            WaitMode wait_mode,
                            extensions::ExtensionId* extension_id = nullptr,
-                           base::Version* extension_version = nullptr);
+                           base::Version* extension_version = nullptr)
+      WARN_UNUSED_RESULT;
   // Force-installs the extension from the given source directory (which should
   // contain the manifest.json file and all other files of the extension).
   // Under the hood, packs the directory into a CRX file and serves it like
@@ -132,7 +134,7 @@
       const base::Optional<base::FilePath>& pem_path,
       WaitMode wait_mode,
       extensions::ExtensionId* extension_id = nullptr,
-      base::Version* extension_version = nullptr);
+      base::Version* extension_version = nullptr) WARN_UNUSED_RESULT;
 
   // Returns the extension, or null if it's not installed yet.
   const extensions::Extension* GetInstalledExtension(
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 326a5aa..1a181d49 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -1077,6 +1077,9 @@
 
 // This method should be periodically pruned of year+ old migrations.
 void MigrateObsoleteLocalStatePrefs(PrefService* local_state) {
+  // BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS
+  // Please don't delete the preceding line. It is used by PRESUBMIT.py.
+
   // Added 1/2020
 #if defined(OS_MAC)
   local_state->ClearPref(kKeyCreated);
@@ -1094,10 +1097,16 @@
   // Added 4/2020.
   local_state->ClearPref(kSupervisedUsersNextId);
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+
+  // Please don't delete the following line. It is used by PRESUBMIT.py.
+  // END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS
 }
 
 // This method should be periodically pruned of year+ old migrations.
 void MigrateObsoleteProfilePrefs(Profile* profile) {
+  // BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS
+  // Please don't delete the preceding line. It is used by PRESUBMIT.py.
+
   PrefService* profile_prefs = profile->GetPrefs();
 
   // Check MigrateDeprecatedAutofillPrefs() to see if this is safe to remove.
@@ -1188,4 +1197,7 @@
 
   // Added 11/2020
   profile_prefs->ClearPref(kDRMSalt);
+
+  // Please don't delete the following line. It is used by PRESUBMIT.py.
+  // END_MIGRATE_OBSOLETE_PROFILE_PREFS
 }
diff --git a/chrome/browser/printing/print_browsertest.cc b/chrome/browser/printing/print_browsertest.cc
index 3c6e795..f517bc21 100644
--- a/chrome/browser/printing/print_browsertest.cc
+++ b/chrome/browser/printing/print_browsertest.cc
@@ -209,8 +209,8 @@
     EXPECT_EQ(document_cookie, document_cookie_);
     ASSERT_TRUE(param->metafile_data_region.IsValid());
     EXPECT_GT(param->metafile_data_region.GetSize(), 0U);
-    task_runner_->PostTask(FROM_HERE, msg_callback_);
     std::move(callback).Run(document_cookie, std::move(param));
+    task_runner_->PostTask(FROM_HERE, msg_callback_);
   }
 
   void Bind(mojo::ScopedInterfaceEndpointHandle handle) {
@@ -218,6 +218,17 @@
         std::move(handle)));
   }
 
+  static mojom::DidPrintContentParamsPtr GetDefaultDidPrintContentParams() {
+    auto printed_frame_params = mojom::DidPrintContentParams::New();
+    // Creates a small amount of region to avoid passing empty data to mojo.
+    constexpr size_t kSize = 10;
+    base::MappedReadOnlyRegion region_mapping =
+        base::ReadOnlySharedMemoryRegion::Create(kSize);
+    printed_frame_params->metafile_data_region =
+        std::move(region_mapping.region);
+    return printed_frame_params;
+  }
+
   // mojom::PrintRenderFrameInterceptorForTesting
   mojom::PrintRenderFrame* GetForwardingInterface() override {
     NOTREACHED();
@@ -226,16 +237,8 @@
   void PrintFrameContent(mojom::PrintFrameContentParamsPtr params,
                          PrintFrameContentCallback callback) override {
     // Sends the printed result back.
-    mojom::DidPrintContentParamsPtr printed_frame_params =
-        mojom::DidPrintContentParams::New();
-    // Creates a small amount of region to avoid passing empty data to mojo.
-    constexpr size_t kSize = 10;
-    base::MappedReadOnlyRegion region_mapping =
-        base::ReadOnlySharedMemoryRegion::Create(kSize);
-    printed_frame_params->metafile_data_region =
-        std::move(region_mapping.region);
     OnDidPrintFrameContent(params->document_cookie,
-                           std::move(printed_frame_params),
+                           GetDefaultDidPrintContentParams(),
                            std::move(callback));
 
     auto* client = PrintCompositeClient::FromWebContents(web_contents_);
@@ -814,6 +817,70 @@
   WaitUntilCallbackReceived();
 }
 
+// Printing frame content with a cross-site iframe before creating
+// PrintCompositor by the main frame.
+// This test passes if PrintCompositeClient queues subframes when
+// it doesn't have PrintCompositor and clears them after PrintCompositor is
+// created.
+IN_PROC_BROWSER_TEST_F(PrintBrowserTest,
+                       PrintSubframeContentBeforeCompositeClientCreation) {
+  ASSERT_TRUE(embedded_test_server()->Started());
+  GURL url(
+      embedded_test_server()->GetURL("/printing/content_with_iframe.html"));
+  ui_test_utils::NavigateToURL(browser(), url);
+
+  // When OOPIF is not enabled, CompositorClient is not used.
+  if (!IsOopifEnabled())
+    return;
+
+  content::WebContents* original_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  ASSERT_EQ(2u, original_contents->GetAllFrames().size());
+  content::RenderFrameHost* main_frame = original_contents->GetMainFrame();
+  ASSERT_TRUE(main_frame);
+  content::RenderFrameHost* test_frame = original_contents->GetAllFrames()[1];
+  ASSERT_TRUE(test_frame);
+  ASSERT_NE(main_frame->GetProcess(), test_frame->GetProcess());
+
+  CreateTestPrintRenderFrame(main_frame, original_contents);
+  CreateTestPrintRenderFrame(test_frame, original_contents);
+  SetNumExpectedMessages(2);
+
+  // Print on the main frame.
+  GetPrintRenderFrame(main_frame)
+      ->PrintFrameContent(GetDefaultPrintFrameParams(), base::DoNothing());
+
+  // The printed result will be received and checked in TestPrintRenderFrame.
+  WaitUntilCallbackReceived();
+
+  // As PrintFrameContent() with the main frame doesn't call
+  // PrintCompositeClient::DoCompositeDocumentToPdf() on this test, when
+  // PrintCompositeClient::OnDidPrintFrameContent() is called with the sub
+  // frame, it doesn't have mojom::PrintCompositor.
+  auto* client = PrintCompositeClient::FromWebContents(original_contents);
+  ASSERT_FALSE(client->compositor_);
+
+  // When there is no mojom::PrintCompositor, PrintCompositeClient queues
+  // subframes and handles them when mojom::PrintCompositor is created.
+  // |requested_subframes_| should have the requested subframes.
+  ASSERT_EQ(1u, client->requested_subframes_.size());
+  PrintCompositeClient::RequestedSubFrame* subframe_in_queue =
+      client->requested_subframes_.begin()->get();
+  ASSERT_EQ(kDefaultDocumentCookie, subframe_in_queue->document_cookie_);
+  ASSERT_EQ(test_frame->GetProcess()->GetID(),
+            subframe_in_queue->render_process_id_);
+  ASSERT_EQ(test_frame->GetRoutingID(), subframe_in_queue->render_frame_id_);
+
+  // Creates mojom::PrintCompositor.
+  client->DoCompositeDocumentToPdf(
+      kDefaultDocumentCookie, main_frame,
+      *TestPrintRenderFrame::GetDefaultDidPrintContentParams(),
+      base::DoNothing());
+  ASSERT_TRUE(client->GetCompositeRequest(kDefaultDocumentCookie));
+  // |requested_subframes_| should be empty.
+  ASSERT_TRUE(client->requested_subframes_.empty());
+}
+
 // Printing preview a simple webpage when site per process is enabled.
 // Test that the basic oopif printing should succeed. The test should not crash
 // or timed out. There could be other reasons that cause the test fail, but the
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_settings.cc b/chrome/browser/privacy_sandbox/privacy_sandbox_settings.cc
index 99fe5a6..ea1e596 100644
--- a/chrome/browser/privacy_sandbox/privacy_sandbox_settings.cc
+++ b/chrome/browser/privacy_sandbox/privacy_sandbox_settings.cc
@@ -10,6 +10,45 @@
 #include "chrome/common/chrome_features.h"
 #include "components/content_settings/core/browser/cookie_settings.h"
 #include "components/prefs/pref_service.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace {
+
+bool HasNonDefaultBlockSetting(const ContentSettingsForOneType& cookie_settings,
+                               const GURL& url,
+                               const GURL& top_frame_origin) {
+  // APIs are allowed unless there is an effective non-default cookie content
+  // setting block exception. A default cookie content setting is one that has a
+  // wildcard pattern for both primary and secondary patterns. Content
+  // settings are listed in descending order of priority such that the first
+  // that matches is the effective content setting. A default setting can appear
+  // anywhere in the list. Content settings which appear after a default content
+  // setting are completely superseded by that content setting and are thus not
+  // consulted. Default settings which appear before other settings are applied
+  // from higher precedence sources, such as policy. The value of a default
+  // content setting applied by a higher precedence provider is not consulted
+  // here. For managed policies, the state will be reflected directly in the
+  // privacy sandbox preference. Other providers (such as extensions) will have
+  // been considered for the initial value of the privacy sandbox preference.
+  for (const auto& setting : cookie_settings) {
+    if (setting.primary_pattern == ContentSettingsPattern::Wildcard() &&
+        setting.secondary_pattern == ContentSettingsPattern::Wildcard()) {
+      return false;
+    }
+    if (setting.primary_pattern.Matches(url) &&
+        setting.secondary_pattern.Matches(top_frame_origin)) {
+      return setting.GetContentSetting() ==
+             ContentSetting::CONTENT_SETTING_BLOCK;
+    }
+  }
+  // ContentSettingsForOneType should always end with a default content setting
+  // from the default provider.
+  NOTREACHED();
+  return false;
+}
+
+}  // namespace
 
 PrivacySandboxSettings::PrivacySandboxSettings(
     content_settings::CookieSettings* cookie_settings,
@@ -21,12 +60,26 @@
 
 bool PrivacySandboxSettings::IsFlocAllowed(
     const GURL& url,
-    const GURL& site_for_cookies,
     const base::Optional<url::Origin>& top_frame_origin) const {
-  // Simply respect cookie settings.
-  // TODO(crbug.com/1152336): Respect privacy sandbox settings.
-  return cookie_settings_->IsCookieAccessAllowed(url, site_for_cookies,
-                                                 top_frame_origin);
+  if (!base::FeatureList::IsEnabled(features::kPrivacySandboxSettings)) {
+    // Simply respect cookie settings if the UI is not available. An empty site
+    // for cookies is provided so the context is always as a third party.
+    return cookie_settings_->IsCookieAccessAllowed(url, GURL(),
+                                                   top_frame_origin);
+  }
+
+  if (!pref_service_->GetBoolean(prefs::kPrivacySandboxApisEnabled))
+    return false;
+
+  // TODO (crbug.com/1155504): Bypassing CookieSettings to access content
+  // settings directly ignores allowlisted schemes and the storage access API.
+  // These should be taken into account here.
+  ContentSettingsForOneType cookie_settings;
+  cookie_settings_->GetCookieSettings(&cookie_settings);
+
+  return !HasNonDefaultBlockSetting(
+      cookie_settings, url,
+      top_frame_origin ? top_frame_origin->GetURL() : GURL());
 }
 
 base::Time PrivacySandboxSettings::FlocDataAccessibleSince() const {
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_settings.h b/chrome/browser/privacy_sandbox/privacy_sandbox_settings.h
index ee4123c..2fea6908 100644
--- a/chrome/browser/privacy_sandbox/privacy_sandbox_settings.h
+++ b/chrome/browser/privacy_sandbox/privacy_sandbox_settings.h
@@ -33,11 +33,9 @@
                          PrefService* prefs);
 
   // Determines whether FLoC is allowable in a particular context.
-  // |site_for_cookies| is used to determine whether a request is in a 3P
-  // context, while |top_frame_origin| if set, is used to check for content
-  // settings which could both affect 1P and 3P cookies.
+  // |top_frame_origin| is used to check for content settings which could both
+  // affect 1P and 3P contexts.
   bool IsFlocAllowed(const GURL& url,
-                     const GURL& site_for_cookies,
                      const base::Optional<url::Origin>& top_frame_origin) const;
 
   // Returns the point in time from which history is elligible to be used when
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_settings_unittest.cc b/chrome/browser/privacy_sandbox/privacy_sandbox_settings_unittest.cc
new file mode 100644
index 0000000..3b69924
--- /dev/null
+++ b/chrome/browser/privacy_sandbox/privacy_sandbox_settings_unittest.cc
@@ -0,0 +1,320 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/privacy_sandbox/privacy_sandbox_settings.h"
+
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/content_settings/cookie_settings_factory.h"
+#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
+#include "chrome/browser/privacy_sandbox/privacy_sandbox_prefs.h"
+#include "chrome/common/chrome_features.h"
+#include "chrome/test/base/testing_profile.h"
+#include "components/content_settings/core/browser/cookie_settings.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/content_settings/core/common/pref_names.h"
+#include "components/content_settings/core/test/content_settings_mock_provider.h"
+#include "components/content_settings/core/test/content_settings_test_utils.h"
+#include "components/sync_preferences/testing_pref_service_syncable.h"
+#include "content/public/test/browser_task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Define an additional content setting value to simulate an unmanaged default
+// content setting.
+const ContentSetting kNoSetting = static_cast<ContentSetting>(-1);
+
+struct CookieContentSettingException {
+  std::string primary_pattern;
+  std::string secondary_pattern;
+  ContentSetting content_setting;
+};
+
+}  // namespace
+
+class PrivacySandboxSettingsTest : public testing::Test {
+ public:
+  PrivacySandboxSettingsTest() = default;
+
+  void SetUp() override {
+    privacy_sandbox_settings_ = std::make_unique<PrivacySandboxSettings>(
+        CookieSettingsFactory::GetForProfile(profile()).get(),
+        profile()->GetPrefs());
+  }
+
+  // Sets up preferences and content settings based on provided parameters.
+  void SetupTestState(
+      bool privacy_sandbox_available,
+      bool privacy_sandbox_enabled,
+      ContentSetting default_cookie_setting,
+      std::vector<CookieContentSettingException> user_cookie_exceptions,
+      ContentSetting managed_cookie_setting,
+      std::vector<CookieContentSettingException> managed_cookie_exceptions) {
+    // Setup cookie content settings.
+    auto* map = HostContentSettingsMapFactory::GetForProfile(profile());
+    auto user_provider = std::make_unique<content_settings::MockProvider>();
+    auto managed_provider = std::make_unique<content_settings::MockProvider>();
+
+    if (default_cookie_setting != kNoSetting) {
+      user_provider->SetWebsiteSetting(
+          ContentSettingsPattern::Wildcard(),
+          ContentSettingsPattern::Wildcard(), ContentSettingsType::COOKIES,
+          std::make_unique<base::Value>(default_cookie_setting));
+    }
+
+    for (const auto& exception : user_cookie_exceptions) {
+      user_provider->SetWebsiteSetting(
+          ContentSettingsPattern::FromString(exception.primary_pattern),
+          ContentSettingsPattern::FromString(exception.secondary_pattern),
+          ContentSettingsType::COOKIES,
+          std::make_unique<base::Value>(exception.content_setting));
+    }
+
+    if (managed_cookie_setting != kNoSetting) {
+      managed_provider->SetWebsiteSetting(
+          ContentSettingsPattern::Wildcard(),
+          ContentSettingsPattern::Wildcard(), ContentSettingsType::COOKIES,
+          std::make_unique<base::Value>(managed_cookie_setting));
+    }
+
+    for (const auto& exception : managed_cookie_exceptions) {
+      managed_provider->SetWebsiteSetting(
+          ContentSettingsPattern::FromString(exception.primary_pattern),
+          ContentSettingsPattern::FromString(exception.secondary_pattern),
+          ContentSettingsType::COOKIES,
+          std::make_unique<base::Value>(exception.content_setting));
+    }
+
+    content_settings::TestUtils::OverrideProvider(
+        map, std::move(user_provider),
+        HostContentSettingsMap::DEFAULT_PROVIDER);
+    content_settings::TestUtils::OverrideProvider(
+        map, std::move(managed_provider),
+        HostContentSettingsMap::POLICY_PROVIDER);
+
+    // Setup privacy sandbox feature & preference.
+    feature_list()->Reset();
+    if (privacy_sandbox_available)
+      feature_list()->InitAndEnableFeature(features::kPrivacySandboxSettings);
+    else
+      feature_list()->InitAndDisableFeature(features::kPrivacySandboxSettings);
+
+    profile()->GetTestingPrefService()->SetUserPref(
+        prefs::kPrivacySandboxApisEnabled,
+        std::make_unique<base::Value>(privacy_sandbox_enabled));
+  }
+
+  TestingProfile* profile() { return &profile_; }
+  PrivacySandboxSettings* privacy_sandbox_settings() {
+    return privacy_sandbox_settings_.get();
+  }
+  base::test::ScopedFeatureList* feature_list() { return &feature_list_; }
+
+ private:
+  content::BrowserTaskEnvironment browser_task_environment_;
+  TestingProfile profile_;
+  std::unique_ptr<PrivacySandboxSettings> privacy_sandbox_settings_;
+  base::test::ScopedFeatureList feature_list_;
+};
+
+TEST_F(PrivacySandboxSettingsTest, CookieSettingAppliesWhenUiDisabled) {
+  // When the Privacy Sandbox UI is unavailable, the cookie setting should
+  // apply directly.
+  SetupTestState(
+      /*privacy_sandbox_available=*/false,
+      /*privacy_sandbox_enabled=*/false,
+      /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_ALLOW,
+      /*user_cookie_exceptions=*/{},
+      /*managed_cookie_setting=*/kNoSetting,
+      /*managed_cookie_exceptions=*/{});
+  EXPECT_TRUE(privacy_sandbox_settings()->IsFlocAllowed(
+      GURL("https://embedded.com"),
+      url::Origin::Create(GURL("https://test.com"))));
+
+  SetupTestState(
+      /*privacy_sandbox_available=*/false,
+      /*privacy_sandbox_enabled=*/false,
+      /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_BLOCK,
+      /*user_cookie_exceptions=*/
+      {{"https://embedded.com", "https://test.com",
+        ContentSetting::CONTENT_SETTING_ALLOW},
+       {"https://another-embedded.com", "*",
+        ContentSetting::CONTENT_SETTING_BLOCK}},
+      /*managed_cookie_setting=*/kNoSetting,
+      /*managed_cookie_exceptions=*/{});
+  EXPECT_TRUE(privacy_sandbox_settings()->IsFlocAllowed(
+      GURL("https://embedded.com"),
+      url::Origin::Create(GURL("https://test.com"))));
+  EXPECT_FALSE(privacy_sandbox_settings()->IsFlocAllowed(
+      GURL("https://another-embedded.com"), base::nullopt));
+
+  SetupTestState(
+      /*privacy_sandbox_available=*/false,
+      /*privacy_sandbox_enabled=*/true,
+      /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_ALLOW,
+      /*user_cookie_exceptions=*/
+      {{"https://embedded.com", "https://test.com",
+        ContentSetting::CONTENT_SETTING_ALLOW}},
+      /*managed_cookie_setting=*/kNoSetting,
+      {{"https://embedded.com", "https://test.com",
+        ContentSetting::CONTENT_SETTING_BLOCK}});
+  EXPECT_FALSE(privacy_sandbox_settings()->IsFlocAllowed(
+      GURL("https://embedded.com"),
+      url::Origin::Create(GURL("https://test.com"))));
+  EXPECT_TRUE(privacy_sandbox_settings()->IsFlocAllowed(
+      GURL("https://embedded.com"), base::nullopt));
+}
+
+TEST_F(PrivacySandboxSettingsTest, PreferenceOverridesDefaultContentSetting) {
+  // When the Privacy Sandbox UI is available, the sandbox preference should
+  // override the default cookie content setting.
+  SetupTestState(
+      /*privacy_sandbox_available=*/true,
+      /*privacy_sandbox_enabled=*/true,
+      /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_BLOCK,
+      /*user_cookie_exceptions=*/{},
+      /*managed_cookie_setting=*/kNoSetting,
+      /*managed_cookie_exceptions=*/{});
+  EXPECT_TRUE(privacy_sandbox_settings()->IsFlocAllowed(
+      GURL("https://embedded.com"),
+      url::Origin::Create(GURL("https://test.com"))));
+
+  // An allow exception should not override the preference value.
+  SetupTestState(
+      /*privacy_sandbox_available=*/true,
+      /*privacy_sandbox_enabled=*/false,
+      /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_ALLOW,
+      /*user_cookie_exceptions=*/
+      {{"https://embedded.com", "https://test.com",
+        ContentSetting::CONTENT_SETTING_ALLOW}},
+      /*managed_cookie_setting=*/kNoSetting,
+      /*managed_cookie_exceptions=*/{});
+  EXPECT_FALSE(privacy_sandbox_settings()->IsFlocAllowed(
+      GURL("https://embedded.com"),
+      url::Origin::Create(GURL("https://test.com"))));
+}
+
+TEST_F(PrivacySandboxSettingsTest, CookieBlockExceptionsApply) {
+  // When the Privacy Sandbox UI & preference are both enabled, targeted cookie
+  // block exceptions should still apply.
+  SetupTestState(
+      /*privacy_sandbox_available=*/true,
+      /*privacy_sandbox_enabled=*/true,
+      /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_ALLOW,
+      /*user_cookie_exceptions=*/
+      {{"https://embedded.com", "https://test.com",
+        ContentSetting::CONTENT_SETTING_BLOCK}},
+      /*managed_cookie_setting=*/kNoSetting,
+      /*managed_cookie_exceptions=*/{});
+  EXPECT_FALSE(privacy_sandbox_settings()->IsFlocAllowed(
+      GURL("https://embedded.com"),
+      url::Origin::Create(GURL("https://test.com"))));
+
+  // User created exceptions should not apply if a managed default coookie
+  // setting exists. What the managed default setting actually is should *not*
+  // affect whether APIs are enabled. The cookie managed state is reflected in
+  // the privacy sandbox preferences directly.
+  SetupTestState(
+      /*privacy_sandbox_available=*/true,
+      /*privacy_sandbox_enabled=*/true,
+      /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_ALLOW,
+      /*user_cookie_exceptions=*/
+      {{"https://embedded.com", "https://test.com",
+        ContentSetting::CONTENT_SETTING_BLOCK}},
+      /*managed_cookie_setting=*/ContentSetting::CONTENT_SETTING_BLOCK,
+      /*managed_cookie_exceptions=*/{});
+  EXPECT_TRUE(privacy_sandbox_settings()->IsFlocAllowed(
+      GURL("https://embedded.com"),
+      url::Origin::Create(GURL("https://test.com"))));
+
+  // Managed content setting exceptions should override both the privacy
+  // sandbox pref and any user settings.
+  SetupTestState(
+      /*privacy_sandbox_available=*/true,
+      /*privacy_sandbox_enabled=*/true,
+      /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_ALLOW,
+      /*user_cookie_exceptions=*/
+      {{"https://embedded.com", "https://test.com",
+        ContentSetting::CONTENT_SETTING_ALLOW}},
+      /*managed_cookie_setting=*/ContentSetting::CONTENT_SETTING_ALLOW,
+      {{"https://embedded.com", "https://test.com",
+        ContentSetting::CONTENT_SETTING_BLOCK}});
+  EXPECT_FALSE(privacy_sandbox_settings()->IsFlocAllowed(
+      GURL("https://embedded.com"),
+      url::Origin::Create(GURL("https://test.com"))));
+  EXPECT_TRUE(privacy_sandbox_settings()->IsFlocAllowed(
+      GURL("https://unrelated.com"),
+      url::Origin::Create(GURL("https://unrelated.com"))));
+
+  // A less specific block exception should not override a more specific allow
+  // exception. The effective content setting in this scenario is still allow,
+  // even though a block exception exists.
+  SetupTestState(
+      /*privacy_sandbox_available=*/true,
+      /*privacy_sandbox_enabled=*/true,
+      /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_ALLOW,
+      /*user_cookie_exceptions=*/
+      {{"https://embedded.com", "https://test.com",
+        ContentSetting::CONTENT_SETTING_ALLOW},
+       {"https://[*.]embedded.com", "https://[*.]test.com",
+        ContentSetting::CONTENT_SETTING_BLOCK}},
+      /*managed_cookie_setting=*/kNoSetting,
+      /*managed_cookie_exceptions=*/{});
+  EXPECT_TRUE(privacy_sandbox_settings()->IsFlocAllowed(
+      GURL("https://embedded.com"),
+      url::Origin::Create(GURL("https://test.com"))));
+
+  // Exceptions which specify a top frame origin should not match against an
+  // empty top frame.
+  SetupTestState(
+      /*privacy_sandbox_available=*/true,
+      /*privacy_sandbox_enabled=*/true,
+      /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_BLOCK,
+      /*user_cookie_exceptions=*/
+      {{"https://embedded.com", "https://test.com",
+        ContentSetting::CONTENT_SETTING_BLOCK}},
+      /*managed_cookie_setting=*/kNoSetting,
+      /*managed_cookie_exceptions=*/
+      {{"https://embedded.com", "https://test.com",
+        ContentSetting::CONTENT_SETTING_BLOCK}});
+  EXPECT_TRUE(privacy_sandbox_settings()->IsFlocAllowed(
+      GURL("https://embedded.com"), base::nullopt));
+
+  // Exceptions which specify a wildcard top frame origin should match both
+  // empty top frames and non empty top frames.
+  SetupTestState(
+      /*privacy_sandbox_available=*/true,
+      /*privacy_sandbox_enabled=*/true,
+      /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_ALLOW,
+      /*user_cookie_exceptions=*/
+      {{"https://embedded.com", "*", ContentSetting::CONTENT_SETTING_BLOCK}},
+      /*managed_cookie_setting=*/kNoSetting,
+      /*managed_cookie_exceptions=*/{});
+  EXPECT_FALSE(privacy_sandbox_settings()->IsFlocAllowed(
+      GURL("https://embedded.com"), base::nullopt));
+  EXPECT_FALSE(privacy_sandbox_settings()->IsFlocAllowed(
+      GURL("https://embedded.com"),
+      url::Origin::Create(GURL("https://test.com"))));
+}
+
+TEST_F(PrivacySandboxSettingsTest, FlocAlwaysThirdParty) {
+  // Check that when the UI is not enabled, all FLoC requests are considered
+  // as third party requests.
+  profile()->GetTestingPrefService()->SetUserPref(
+      prefs::kCookieControlsMode,
+      std::make_unique<base::Value>(static_cast<int>(
+          content_settings::CookieControlsMode::kBlockThirdParty)));
+  SetupTestState(
+      /*privacy_sandbox_available=*/false,
+      /*privacy_sandbox_enabled=*/false,
+      /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_ALLOW,
+      /*user_cookie_exceptions=*/{},
+      /*managed_cookie_setting=*/kNoSetting,
+      /*managed_cookie_exceptions=*/{});
+  EXPECT_FALSE(privacy_sandbox_settings()->IsFlocAllowed(
+      GURL("https://embedded.com"),
+      url::Origin::Create(GURL("https://embedded.com"))));
+  EXPECT_FALSE(privacy_sandbox_settings()->IsFlocAllowed(
+      GURL("https://embedded.com"), base::nullopt));
+}
diff --git a/chrome/browser/resources/inline_login/BUILD.gn b/chrome/browser/resources/inline_login/BUILD.gn
index 3028b89..3cd125f5 100644
--- a/chrome/browser/resources/inline_login/BUILD.gn
+++ b/chrome/browser/resources/inline_login/BUILD.gn
@@ -15,6 +15,7 @@
   deps = [
     ":inline_login_app",
     ":inline_login_browser_proxy",
+    ":welcome_page_app",
   ]
 }
 
@@ -24,12 +25,21 @@
     "//chrome/browser/resources/gaia_auth_host:authenticator.m",
     "//third_party/polymer/v3_0/components-chromium/paper-spinner:paper-spinner-lite",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+    "//ui/webui/resources/cr_elements/cr_view_manager:cr_view_manager.m",
     "//ui/webui/resources/js:assert.m",
+    "//ui/webui/resources/js:load_time_data.m",
     "//ui/webui/resources/js:web_ui_listener_behavior.m",
   ]
   externs_list = [ "$externs_path/webview_tag.js" ]
 }
 
+js_library("welcome_page_app") {
+  deps = [
+    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+    "//ui/webui/resources/js:load_time_data.m",
+  ]
+}
+
 js_library("inline_login_browser_proxy") {
   deps = [
     "//chrome/browser/resources/gaia_auth_host:authenticator.m",
@@ -39,5 +49,8 @@
 }
 
 html_to_js("web_components") {
-  js_files = [ "inline_login_app.js" ]
+  js_files = [
+    "inline_login_app.js",
+    "welcome_page_app.js",
+  ]
 }
diff --git a/chrome/browser/resources/inline_login/inline_login.html b/chrome/browser/resources/inline_login/inline_login.html
index dfc66c3..3ce70ca 100644
--- a/chrome/browser/resources/inline_login/inline_login.html
+++ b/chrome/browser/resources/inline_login/inline_login.html
@@ -10,6 +10,7 @@
   body {
     height: 100%;
     margin: 0;
+    overflow: hidden;
     padding: 0;
   }
 </style>
diff --git a/chrome/browser/resources/inline_login/inline_login_app.html b/chrome/browser/resources/inline_login/inline_login_app.html
index 7e86592..12f6399e 100644
--- a/chrome/browser/resources/inline_login/inline_login_app.html
+++ b/chrome/browser/resources/inline_login/inline_login_app.html
@@ -13,7 +13,8 @@
     width: 100%;
   }
 
-  .container {
+  .container,
+  #addAccount.active {
     align-items: center;
     display: flex;
     flex-grow: 1;
@@ -21,9 +22,15 @@
   }
 
 <if expr="chromeos">
-  .container {
+  /* Content of the webview already has 64px border, add negative margin to make
+   * distance to the top 64px. */
+  #addAccount {
     margin-top: calc(-1 * var(--dialog-top-border-size));
   }
+  /* Make distance to the top 64px. */
+  #welcome {
+    margin-top: calc(64px - var(--dialog-top-border-size));
+  }
 </if>
 
   .signin-frame {
@@ -36,7 +43,8 @@
     padding: 0 32px 32px;
   }
 
-  .action-buttons {
+  .action-buttons,
+  .next-button {
     margin-inline-start: auto;
   }
 
@@ -53,24 +61,48 @@
 </style>
 
 <div class="container">
-  <webview id="signinFrame" name="signin-frame" class="signin-frame"
-      hidden$="[[loading_]]" allowscaling></webview>
-  <paper-spinner-lite active="[[loading_]]">
-  </paper-spinner-lite>
+  <cr-view-manager id="viewManager">
+    <!-- Show welcome screen on Chrome OS to clarify that account will be
+         available in ARC. -->
+    <if expr="chromeos">
+      <div id="[[View.welcome]]" slot="view">
+        <welcome-page-app on-opened-new-window="closeDialog_">
+        </welcome-page-app>
+      </div>
+    </if>
+
+    <div id="[[View.addAccount]]" slot="view">
+      <paper-spinner-lite active="[[loading_]]">
+      </paper-spinner-lite>
+
+      <webview id="signinFrame" name="signin-frame" class="signin-frame"
+        hidden$="[[loading_]]" allowscaling>
+      </webview>
+    </div>
+  </cr-view-manager>
 </div>
 
 <if expr="chromeos">
   <div class="buttons" hidden$="[[loading_]]">
     <cr-button class="back-button"
         aria-label="$i18n{accessibleBackButtonLabel}"
-        on-click="handleGoBack_">
+        on-click="handleGoBack_"
+        hidden$="[[!shouldShowBackButton_(currentView_)]]">
       <iron-icon icon="[[getBackButtonIcon_()]]"></iron-icon>
       $i18n{accessibleBackButtonLabel}
     </cr-button>
 
-    <div class="action-buttons" hidden$="[[!enableGaiaActionButtons_]]">
+    <div class="action-buttons"
+        hidden$="[[!shouldShowGaiaButtons_(currentView_)]]">
       <gaia-action-buttons authenticator="[[authExtHost_]]">
       </gaia-action-buttons>
     </div>
+
+    <cr-button class="next-button action-button"
+        aria-label="$i18n{ok}"
+        on-tap="onOkButtonClick_"
+        hidden$="[[!shouldShowOkButton_(currentView_)]]">
+      $i18n{ok}
+    </cr-button>
   </div>
 </if>
diff --git a/chrome/browser/resources/inline_login/inline_login_app.js b/chrome/browser/resources/inline_login/inline_login_app.js
index 29dae27..cc96f0c 100644
--- a/chrome/browser/resources/inline_login/inline_login_app.js
+++ b/chrome/browser/resources/inline_login/inline_login_app.js
@@ -6,15 +6,21 @@
 import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
 import 'chrome://resources/cr_elements/icons.m.js';
 import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
+import 'chrome://resources/cr_elements/cr_view_manager/cr_view_manager.m.js';
 
-// <if expr="chromeos">
-import './gaia_action_buttons.js';
-// </if>
 
+import {isChromeOS} from '//resources/js/cr.m.js';
+import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {isRTL} from 'chrome://resources/js/util.m.js';
 import {WebUIListenerBehavior} from 'chrome://resources/js/web_ui_listener_behavior.m.js';
 import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
+// <if expr="chromeos">
+import './gaia_action_buttons.js';
+import './welcome_page_app.js';
+import './strings.m.js';
+// </if>
+
 import {AuthCompletedCredentials, Authenticator, AuthParams} from '../gaia_auth_host/authenticator.m.js';
 import {InlineLoginBrowserProxy, InlineLoginBrowserProxyImpl} from './inline_login_browser_proxy.js';
 
@@ -23,6 +29,12 @@
  * Chrome desktop (Windows only).
  */
 
+/** @enum {string} */
+const View = {
+  addAccount: 'addAccount',
+  welcome: 'welcome',
+};
+
 Polymer({
   is: 'inline-login-app',
 
@@ -31,6 +43,12 @@
   behaviors: [WebUIListenerBehavior],
 
   properties: {
+    /** Mirroring the enum so that it can be used from HTML bindings. */
+    View: {
+      type: Object,
+      value: View,
+    },
+
     /**
      * Indicates whether the page is loading.
      * @private {boolean}
@@ -48,6 +66,28 @@
       type: Object,
       value: null,
     },
+
+    /**
+     * True if redesign of account management flows is enabled.
+     * @private
+     */
+    isAccountManagementFlowsV2Enabled_: {
+      type: Boolean,
+      value() {
+        return isChromeOS &&
+            loadTimeData.getBoolean('isAccountManagementFlowsV2Enabled');
+      },
+      readOnly: true,
+    },
+
+    /**
+     * Id of the screen that is currently displayed.
+     * @private {View}
+     */
+    currentView_: {
+      type: String,
+      value: '',
+    },
   },
 
   /** @private {?InlineLoginBrowserProxy} */
@@ -69,6 +109,7 @@
 
   /** @override */
   ready() {
+    this.switchView_(this.getDefaultView_());
     this.authExtHost_ = new Authenticator(
         /** @type {!WebView} */ (this.$.signinFrame));
     this.addAuthExtHostListeners_();
@@ -125,6 +166,11 @@
   onNewWindow_(e) {
     window.open(e.detail.targetUrl, '_blank');
     e.detail.window.discard();
+    if (this.isAccountManagementFlowsV2Enabled_) {
+      // On Chrome OS this dialog is always-on-top, so we have to close it if
+      // user opens a link in a new window.
+      this.closeDialog_();
+    }
   },
 
   /** @private */
@@ -219,6 +265,61 @@
     return isRTL() ? 'cr:chevron-right' : 'cr:chevron-left';
   },
 
+  /**
+   * @return {boolean}
+   * @private
+   */
+  shouldShowBackButton_() {
+    return this.currentView_ === View.addAccount;
+  },
+
+  /**
+   * @return {boolean}
+   * @private
+   */
+  shouldShowOkButton_() {
+    return this.currentView_ === View.welcome;
+  },
+
+  /**
+   * @return {boolean}
+   * @private
+   */
+  shouldShowGaiaButtons_() {
+    return this.enableGaiaActionButtons_ &&
+        this.currentView_ === View.addAccount;
+  },
+
+  /**
+   * @return {View}
+   * @private
+   */
+  getDefaultView_() {
+    return this.isWelcomePageEnabled_() ? View.welcome : View.addAccount;
+  },
+
+  /**
+   * @param {View} id identifier of the view that should be shown.
+   * @private
+   */
+  switchView_(id) {
+    this.currentView_ = id;
+    /** @type {CrViewManagerElement} */ (this.$.viewManager).switchView(id);
+  },
+
+  /**
+   * @return {boolean}
+   * @private
+   */
+  isWelcomePageEnabled_() {
+    return this.isAccountManagementFlowsV2Enabled_;
+  },
+
+  /** @private */
+  onOkButtonClick_() {
+    this.switchView_(View.addAccount);
+  },
+
   /** @param {Object} authExtHost */
   setAuthExtHostForTest(authExtHost) {
     this.authExtHost_ = /** @type {!Authenticator} */ (authExtHost);
diff --git a/chrome/browser/resources/inline_login/welcome_page_app.html b/chrome/browser/resources/inline_login/welcome_page_app.html
new file mode 100644
index 0000000..0aa4f4e
--- /dev/null
+++ b/chrome/browser/resources/inline_login/welcome_page_app.html
@@ -0,0 +1,30 @@
+<style include="shared-css">
+  .image-container {
+    margin-top: 40px;
+  }
+  .welcome-image {
+    width: 338px;
+  }
+  .google-full-logo {
+    width: 74px;
+  }
+  .secondary {
+    color: var(--cr-secondary-text-color);
+  }
+</style>
+
+<div class="main-container">
+  <if expr="_google_chrome">
+    <img class="google-full-logo"
+            src="chrome://theme/IDR_LOGO_GOOGLE_COLOR_90" alt="">
+  </if>
+  <h1>[[getWelcomeTitle_()]]</h1>
+  <p class="secondary" inner-h-t-m-l="[[getWelcomeBody_()]]"></p>
+  <if expr="_google_chrome">
+    <div class="image-container">
+      <img class="welcome-image" alt=""
+          srcset="account_manager_welcome_1x.png 1x,
+                  account_manager_welcome_2x.png 2x">
+    </div>
+  </if>
+</div>
diff --git a/chrome/browser/resources/inline_login/welcome_page_app.js b/chrome/browser/resources/inline_login/welcome_page_app.js
new file mode 100644
index 0000000..0b14987
--- /dev/null
+++ b/chrome/browser/resources/inline_login/welcome_page_app.js
@@ -0,0 +1,42 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
+import './account_manager_shared_css.js';
+
+import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+Polymer({
+  is: 'welcome-page-app',
+
+  _template: html`{__html_template__}`,
+
+  /** @override */
+  ready() {
+    this.$$('#osSettingsLink')
+        .addEventListener(
+            'click',
+            () => this.dispatchEvent(new CustomEvent('opened-new-window')));
+  },
+
+  /**
+   * @return {string}
+   * @private
+   */
+  getWelcomeBody_() {
+    return loadTimeData.getStringF(
+        'accountManagerDialogWelcomeBody', loadTimeData.getString('userName'),
+        loadTimeData.getString('accountManagerOsSettingsUrl'));
+  },
+
+  /**
+   * @return {string}
+   * @private
+   */
+  getWelcomeTitle_() {
+    return loadTimeData.getStringF(
+        'accountManagerDialogWelcomeTitle', loadTimeData.getString('userName'));
+  },
+});
diff --git a/chrome/browser/resources/nearby_share/nearby_confirmation_page.html b/chrome/browser/resources/nearby_share/nearby_confirmation_page.html
index 6309c97b..ca372ef 100644
--- a/chrome/browser/resources/nearby_share/nearby_confirmation_page.html
+++ b/chrome/browser/resources/nearby_share/nearby_confirmation_page.html
@@ -1,6 +1,6 @@
 <style>
   #addContacts {
-    margin-top: 32px;
+    padding: 8px;
   }
 
   #addContactsLabel {
@@ -93,7 +93,7 @@
         <nearby-preview send-preview="[[sendPreview]]"
             disabled="[[errorTitle_]]">
         </nearby-preview>
-        <div id="confirmationToken">
+        <div id="confirmationToken" aria-live="polite">
           <template is="dom-if" if="[[confirmationToken_]]">
             [[i18n('nearbyShareSecureConnectionId', confirmationToken_)]]
           </template>
@@ -104,12 +104,13 @@
       </div>
     </div>
 
-    <template is="dom-if" if="[[contactName_(shareTarget)]]">
-      <cr-checkbox id="addContacts">
-        <div id="addContactsLabel">
+    <template is="dom-if" if="[[contactName_(shareTarget, errorTitle_)]]">
+      <cr-checkbox id="addContacts" aria-labelledby="addContactsLabel"
+          aria-describedby="addContactsLabelSecondary">
+        <div id="addContactsLabel" aria-hidden="true">
           [[contactName_(shareTarget)]]
         </div>
-        <div id="addContactsLabelSecondary">
+        <div id="addContactsLabelSecondary" aria-hidden="true">
           [[i18n('nearbyShareConfirmationPageAddContactSubtitle')]]
         </div>
       </cr-checkbox>
@@ -119,9 +120,12 @@
     <template is="dom-if" if="[[errorTitle_]]">
       <div id="errorSection">
         <iron-icon id="errorIcon" icon="nearby20:info"></iron-icon>
-        <div id="error">
-          <div id="errorTitle">[[errorTitle_]]</div>
-          <div id="errorDescription">[[errorDescription_]]</div>
+        <div id="error" role="alert" aria-labelledby="errorTitle"
+            aria-describedby="errorDescription">
+          <div id="errorTitle" aria-hidden="true">[[errorTitle_]]</div>
+          <div id="errorDescription" aria-hidden="true">
+            [[errorDescription_]]
+          </div>
         </div>
       </div>
     </template>
diff --git a/chrome/browser/resources/nearby_share/nearby_confirmation_page.js b/chrome/browser/resources/nearby_share/nearby_confirmation_page.js
index 84a56dc..cdc1df5 100644
--- a/chrome/browser/resources/nearby_share/nearby_confirmation_page.js
+++ b/chrome/browser/resources/nearby_share/nearby_confirmation_page.js
@@ -213,7 +213,7 @@
   contactName_() {
     // TODO(crbug.com/1123943): Get contact name from ShareTarget.
     const contactName = null;
-    if (!contactName) {
+    if (!contactName || this.errorTitle_) {
       return '';
     }
     return this.i18n('nearbyShareConfirmationPageAddContactTitle', contactName);
diff --git a/chrome/browser/resources/nearby_share/nearby_discovery_page.html b/chrome/browser/resources/nearby_share/nearby_discovery_page.html
index ea38a7e3..fb3b52d 100644
--- a/chrome/browser/resources/nearby_share/nearby_discovery_page.html
+++ b/chrome/browser/resources/nearby_share/nearby_discovery_page.html
@@ -160,9 +160,12 @@
     <template is="dom-if" if="[[errorTitle_]]">
       <div id="errorSection">
         <iron-icon id="errorIcon" icon="nearby20:info"></iron-icon>
-        <div id="error">
-          <div id="errorTitle">[[errorTitle_]]</div>
-          <div id="errorDescription">[[errorDescription_]]</div>
+        <div id="error" role="alert" aria-labelledby="errorTitle"
+            aria-describedby="errorDescription">
+          <div id="errorTitle" aria-hidden="true">[[errorTitle_]]</div>
+          <div id="errorDescription" aria-hidden="true">
+            [[errorDescription_]]
+          </div>
         </div>
       </div>
     </template>
diff --git a/chrome/browser/resources/nearby_share/nearby_progress.html b/chrome/browser/resources/nearby_share/nearby_progress.html
index ea1ff0e..6119bd9f 100644
--- a/chrome/browser/resources/nearby_share/nearby_progress.html
+++ b/chrome/browser/resources/nearby_share/nearby_progress.html
@@ -89,7 +89,9 @@
   }
 </style>
 
-<div id="progress-container"
+<div id="progress-container" role="progressbar" aria-valuemin="0"
+    aria-valuemax="100" aria-valuenow$="[[progress]]"
+    tabindex$="[[getProgressBarTabIndex_(progress)]]"
     class$="[[getProgressWheelClass_(progress, hasError)]]">
   <!-- This svg is inlined so that it can be styled with css; otherwise,
        it would be better to put it in an iron-icon. -->
@@ -101,4 +103,6 @@
   <nearby-device-icon id="icon" share-target="[[shareTarget]]">
   </nearby-device-icon>
 </div>
-<div id="device-name">[[shareTarget.name]]</div>
+<div id="device-name" aria-label="$i18n{nearbyShareOnboardingPageDeviceName}">
+  [[shareTarget.name]]
+</div>
diff --git a/chrome/browser/resources/nearby_share/nearby_progress.js b/chrome/browser/resources/nearby_share/nearby_progress.js
index 0053a38..43481a8 100644
--- a/chrome/browser/resources/nearby_share/nearby_progress.js
+++ b/chrome/browser/resources/nearby_share/nearby_progress.js
@@ -78,4 +78,15 @@
       this.updateStyles({'--progress-percentage': value});
     }
   },
+
+  /**
+   * Allow focusing on the progress bar. Ignored by Chromevox otherwise.
+   * @return {number} The tabindex to be applied to the progress wheel.
+   */
+  getProgressBarTabIndex_() {
+    if (this.progress && !this.hasError) {
+      return 0;
+    }
+    return -1;
+  },
 });
diff --git a/chrome/browser/resources/print_preview/data/printer_status_cros.js b/chrome/browser/resources/print_preview/data/printer_status_cros.js
index 09d00a0b..6c9c5bc4 100644
--- a/chrome/browser/resources/print_preview/data/printer_status_cros.js
+++ b/chrome/browser/resources/print_preview/data/printer_status_cros.js
@@ -134,16 +134,22 @@
 
 /**
  * @param {?PrinterStatusReason} printerStatusReason
+ * @param {boolean} isEnterprisePrinter
  * @return {string}
  */
-export function getPrinterStatusIcon(printerStatusReason) {
+export function getPrinterStatusIcon(printerStatusReason, isEnterprisePrinter) {
   switch (computePrinterState(printerStatusReason)) {
     case PrinterState.GOOD:
-      return 'print-preview:printer-status-green';
+      return isEnterprisePrinter ?
+          'print-preview:business-printer-status-green' :
+          'print-preview:printer-status-green';
     case PrinterState.ERROR:
-      return 'print-preview:printer-status-red';
+      return isEnterprisePrinter ? 'print-preview:business-printer-status-red' :
+                                   'print-preview:printer-status-red';
     case PrinterState.UNKNOWN:
-      return 'print-preview:printer-status-grey';
+      return isEnterprisePrinter ?
+          'print-preview:business-printer-status-grey' :
+          'print-preview:printer-status-grey';
     default:
       assertNotReached();
   }
diff --git a/chrome/browser/resources/print_preview/ui/destination_dropdown_cros.html b/chrome/browser/resources/print_preview/ui/destination_dropdown_cros.html
index 64b1c1d5..c2e4298 100644
--- a/chrome/browser/resources/print_preview/ui/destination_dropdown_cros.html
+++ b/chrome/browser/resources/print_preview/ui/destination_dropdown_cros.html
@@ -125,7 +125,7 @@
               aria-description$="[[getPrinterStatusErrorString_(
                   item.printerStatusReason)]]">
             <iron-icon icon="[[getPrinterStatusIcon_(
-                item.printerStatusReason)]]">
+                item.printerStatusReason, item.isEnterprisePrinter)]]">
             </iron-icon>
             <span class="printer-display-name">[[item.displayName]]</span>
           </button>
diff --git a/chrome/browser/resources/print_preview/ui/destination_dropdown_cros.js b/chrome/browser/resources/print_preview/ui/destination_dropdown_cros.js
index bdd1551..7eeb19b 100644
--- a/chrome/browser/resources/print_preview/ui/destination_dropdown_cros.js
+++ b/chrome/browser/resources/print_preview/ui/destination_dropdown_cros.js
@@ -327,10 +327,11 @@
 
   /**
    * @param {!PrinterStatusReason} printerStatusReason
+   * @param {boolean} isEnterprisePrinter
    * @return {string}
    * @private
    */
-  getPrinterStatusIcon_(printerStatusReason) {
-    return getPrinterStatusIcon(printerStatusReason);
+  getPrinterStatusIcon_(printerStatusReason, isEnterprisePrinter) {
+    return getPrinterStatusIcon(printerStatusReason, isEnterprisePrinter);
   }
 });
diff --git a/chrome/browser/resources/print_preview/ui/destination_list_item.js b/chrome/browser/resources/print_preview/ui/destination_list_item.js
index 203fe7e3..5f3c5dbf 100644
--- a/chrome/browser/resources/print_preview/ui/destination_list_item.js
+++ b/chrome/browser/resources/print_preview/ui/destination_list_item.js
@@ -246,7 +246,9 @@
     // <if expr="chromeos">
     if (this.printerStatusFlagEnabled_ &&
         this.destination.origin === DestinationOrigin.CROS) {
-      return getPrinterStatusIcon(this.destination.printerStatusReason);
+      return getPrinterStatusIcon(
+          this.destination.printerStatusReason,
+          this.destination.isEnterprisePrinter);
     }
     // </if>
 
diff --git a/chrome/browser/resources/print_preview/ui/destination_select_cros.js b/chrome/browser/resources/print_preview/ui/destination_select_cros.js
index 6751f5b..47161af 100644
--- a/chrome/browser/resources/print_preview/ui/destination_select_cros.js
+++ b/chrome/browser/resources/print_preview/ui/destination_select_cros.js
@@ -146,7 +146,9 @@
     if (this.destination && this.destination.key === this.selectedValue) {
       if (this.printerStatusFlagEnabled_ &&
           this.isCurrentDestinationCrosLocal_) {
-        return getPrinterStatusIcon(this.destination.printerStatusReason);
+        return getPrinterStatusIcon(
+            this.destination.printerStatusReason,
+            this.destination.isEnterprisePrinter);
       }
 
       return this.destination.icon;
diff --git a/chrome/browser/resources/print_preview/ui/icons.html b/chrome/browser/resources/print_preview/ui/icons.html
index 58c3fdb..0c6615bc 100644
--- a/chrome/browser/resources/print_preview/ui/icons.html
+++ b/chrome/browser/resources/print_preview/ui/icons.html
@@ -34,6 +34,18 @@
         <path d="M19,8 C20.66,8 22,9.34 22,11 L22,11 L22.0008411,12.1834702 C20.9260374,10.5660653 19.0875152,9.5 17,9.5 C14.2041481,9.5 11.8549346,11.412286 11.1889599,14.0002575 L8,14 L8,19 L12.1267078,19.0009178 C12.7530956,19.8713157 13.6069102,20.5670952 14.6011413,21.0012461 L6,21 L6,17 L2,17 L2,11 C2,9.34 3.34,8 5,8 L5,8 Z M18,3 L18,7 L6,7 L6,3 L18,3 Z"></path>
         <circle fill="#d93025" cx="17" cy="15.5" r="3.5"></circle>
       </g>
+      <g id="business-printer-status-green">
+        <path d="M12,3 L12,7 L22,7 L22.0008411,12.1834702 C21.4889261,11.4131214 20.8037622,10.7678435 20.000963,10.3032504 L20,9 L12,9 L12,11 L13.0312427,11.0000183 C11.7856236,12.0994345 11,13.7079712 11,15.5 C11,16.7266262 11.3680857,17.8672813 11.9998276,18.8175358 L12,19 L12.1267078,19.0009178 C12.7530956,19.8713157 13.6069102,20.5670952 14.6011413,21.0012461 L2,21 L2,3 L12,3 Z M6,17 L4,17 L4,19 L6,19 L6,17 Z M10,17 L8,17 L8,19 L10,19 L10,17 Z M6,13 L4,13 L4,15 L6,15 L6,13 Z M10,13 L8,13 L8,15 L10,15 L10,13 Z M6,9 L4,9 L4,11 L6,11 L6,9 Z M10,9 L8,9 L8,11 L10,11 L10,9 Z M6,5 L4,5 L4,7 L6,7 L6,5 Z M10,5 L8,5 L8,7 L10,7 L10,5 Z"></path>
+        <circle fill="#188038" cx="17" cy="15.5" r="3.5"></circle>
+      </g>
+      <g id="business-printer-status-grey">
+        <path d="M12,3 L12,7 L22,7 L22.0008411,12.1834702 C21.4889261,11.4131214 20.8037622,10.7678435 20.000963,10.3032504 L20,9 L12,9 L12,11 L13.0312427,11.0000183 C11.7856236,12.0994345 11,13.7079712 11,15.5 C11,16.7266262 11.3680857,17.8672813 11.9998276,18.8175358 L12,19 L12.1267078,19.0009178 C12.7530956,19.8713157 13.6069102,20.5670952 14.6011413,21.0012461 L2,21 L2,3 L12,3 Z M6,17 L4,17 L4,19 L6,19 L6,17 Z M10,17 L8,17 L8,19 L10,19 L10,17 Z M6,13 L4,13 L4,15 L6,15 L6,13 Z M10,13 L8,13 L8,15 L10,15 L10,13 Z M6,9 L4,9 L4,11 L6,11 L6,9 Z M10,9 L8,9 L8,11 L10,11 L10,9 Z M6,5 L4,5 L4,7 L6,7 L6,5 Z M10,5 L8,5 L8,7 L10,7 L10,5 Z"></path>
+        <circle fill="#9aa0a6" cx="17" cy="15.5" r="3.5"></circle>
+      </g>
+      <g id="business-printer-status-red">
+        <path d="M12,3 L12,7 L22,7 L22.0008411,12.1834702 C21.4889261,11.4131214 20.8037622,10.7678435 20.000963,10.3032504 L20,9 L12,9 L12,11 L13.0312427,11.0000183 C11.7856236,12.0994345 11,13.7079712 11,15.5 C11,16.7266262 11.3680857,17.8672813 11.9998276,18.8175358 L12,19 L12.1267078,19.0009178 C12.7530956,19.8713157 13.6069102,20.5670952 14.6011413,21.0012461 L2,21 L2,3 L12,3 Z M6,17 L4,17 L4,19 L6,19 L6,17 Z M10,17 L8,17 L8,19 L10,19 L10,17 Z M6,13 L4,13 L4,15 L6,15 L6,13 Z M10,13 L8,13 L8,15 L10,15 L10,13 Z M6,9 L4,9 L4,11 L6,11 L6,9 Z M10,9 L8,9 L8,11 L10,11 L10,9 Z M6,5 L4,5 L4,7 L6,7 L6,5 Z M10,5 L8,5 L8,7 L10,7 L10,5 Z"></path>
+        <circle fill="#d93025" cx="17" cy="15.5" r="3.5"></circle>
+      </g>
     </if>
 
       <!--
diff --git a/chrome/browser/resources/print_preview/ui/plugin_proxy.js b/chrome/browser/resources/print_preview/ui/plugin_proxy.js
index bc1e07d..b360a8f 100644
--- a/chrome/browser/resources/print_preview/ui/plugin_proxy.js
+++ b/chrome/browser/resources/print_preview/ui/plugin_proxy.js
@@ -115,8 +115,6 @@
     this.plugin_ = /** @type {PDFPlugin} */ (
         PDFCreateOutOfProcessPlugin(srcUrl, 'chrome://print/pdf'));
     this.plugin_.classList.add('preview-area-plugin');
-    this.plugin_.setAttribute('aria-live', 'polite');
-    this.plugin_.setAttribute('aria-atomic', 'true');
     // NOTE: The plugin's 'id' field must be set to 'pdf-viewer' since
     // chrome/renderer/printing/print_render_frame_helper.cc actually
     // references it.
diff --git a/chrome/browser/resources/settings/autofill_page/password_check.js b/chrome/browser/resources/settings/autofill_page/password_check.js
index c8c52b1..7bc580f 100644
--- a/chrome/browser/resources/settings/autofill_page/password_check.js
+++ b/chrome/browser/resources/settings/autofill_page/password_check.js
@@ -434,7 +434,7 @@
    * @private
    */
   computeIconHaloClass_() {
-    return !this.isCheckInProgress_() && this.hasInsecureCredentials_() ?
+    return !this.isCheckInProgress_() && this.hasLeakedCredentials_() ?
         'warning-halo' :
         '';
   },
@@ -448,7 +448,7 @@
     if (!this.hasInsecureCredentialsOrErrors_()) {
       return 'settings:check-circle';
     }
-    if (this.hasInsecureCredentials_()) {
+    if (this.hasLeakedCredentials_()) {
       return 'cr:warning';
     }
     return 'cr:info';
@@ -463,7 +463,7 @@
     if (!this.hasInsecureCredentialsOrErrors_()) {
       return this.waitsForFirstCheck_() ? 'hidden' : 'no-security-issues';
     }
-    if (this.hasInsecureCredentials_()) {
+    if (this.hasLeakedCredentials_()) {
       return 'has-security-issues';
     }
     return '';
diff --git a/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc b/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc
index 4f7fd86..3a03204 100644
--- a/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc
+++ b/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc
@@ -224,7 +224,9 @@
   if (settings.has_value()) {
     UploadBinary(reason, std::move(settings.value()));
   } else {
-    std::move(callback_).Run(result);
+    // Post a task to avoid reentrance issue. http://crbug.com//1152451.
+    content::GetUIThreadTaskRunner({})->PostTask(
+        FROM_HERE, base::BindOnce(std::move(callback_), result));
   }
 
   UMA_HISTOGRAM_ENUMERATION("SBClientDownload.CheckDownloadStats", reason,
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc b/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc
index 50cf7f0..67b97e5 100644
--- a/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc
+++ b/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc
@@ -2414,9 +2414,13 @@
     // notification.
   }
 
+  // Result won't be immediately available as it is being posted.
+  EXPECT_FALSE(has_result_);
+  base::RunLoop().RunUntilIdle();
+
   // When download is destroyed, no need to check for client download request
   // result.
-  EXPECT_TRUE(has_result_);
+  EXPECT_TRUE(IsResult(DownloadCheckResult::UNKNOWN));
   EXPECT_FALSE(HasClientDownloadRequest());
 }
 
@@ -3430,6 +3434,10 @@
       std::move(item),
       base::BindOnce(&DownloadProtectionServiceTest::SyncCheckDoneCallback,
                      base::Unretained(this)));
+  // Result won't be immediately available, wait for the response to
+  // be posted.
+  EXPECT_FALSE(has_result_);
+  base::RunLoop().RunUntilIdle();
   ASSERT_TRUE(IsResult(DownloadCheckResult::WHITELISTED_BY_POLICY));
 }
 
diff --git a/chrome/browser/safe_browsing/url_checker_delegate_impl.cc b/chrome/browser/safe_browsing/url_checker_delegate_impl.cc
index 094969580..734ac6b 100644
--- a/chrome/browser/safe_browsing/url_checker_delegate_impl.cc
+++ b/chrome/browser/safe_browsing/url_checker_delegate_impl.cc
@@ -97,7 +97,7 @@
 
 void UrlCheckerDelegateImpl::MaybeDestroyPrerenderContents(
     content::WebContents::OnceGetter web_contents_getter) {
-  // Destroy the prefetch with FINAL_STATUS_SAFEBROSWING.
+  // Destroy the prefetch with FINAL_STATUS_SAFE_BROWSING.
   content::GetUIThreadTaskRunner({})->PostTask(
       FROM_HERE, base::BindOnce(&DestroyPrerenderContents,
                                 std::move(web_contents_getter)));
diff --git a/chrome/browser/sync_file_system/drive_backend/drive_service_on_worker.cc b/chrome/browser/sync_file_system/drive_backend/drive_service_on_worker.cc
index 728221f..8a9acd0 100644
--- a/chrome/browser/sync_file_system/drive_backend/drive_service_on_worker.cc
+++ b/chrome/browser/sync_file_system/drive_backend/drive_service_on_worker.cc
@@ -47,7 +47,7 @@
   return google_apis::CancelCallbackOnce();
 }
 
-google_apis::CancelCallback DriveServiceOnWorker::DeleteResource(
+google_apis::CancelCallbackOnce DriveServiceOnWorker::DeleteResource(
     const std::string& resource_id,
     const std::string& etag,
     google_apis::EntryActionCallback callback) {
@@ -60,7 +60,7 @@
           RelayCallbackToTaskRunner(worker_task_runner_.get(), FROM_HERE,
                                     std::move(callback))));
 
-  return google_apis::CancelCallback();
+  return google_apis::CancelCallbackOnce();
 }
 
 google_apis::CancelCallbackOnce DriveServiceOnWorker::DownloadFile(
@@ -86,7 +86,7 @@
   return google_apis::CancelCallbackOnce();
 }
 
-google_apis::CancelCallback DriveServiceOnWorker::GetAboutResource(
+google_apis::CancelCallbackOnce DriveServiceOnWorker::GetAboutResource(
     google_apis::AboutResourceCallback callback) {
   DCHECK(sequence_checker_.CalledOnValidSequence());
 
@@ -97,10 +97,10 @@
           RelayCallbackToTaskRunner(worker_task_runner_.get(), FROM_HERE,
                                     std::move(callback))));
 
-  return google_apis::CancelCallback();
+  return google_apis::CancelCallbackOnce();
 }
 
-google_apis::CancelCallback DriveServiceOnWorker::GetStartPageToken(
+google_apis::CancelCallbackOnce DriveServiceOnWorker::GetStartPageToken(
     const std::string& team_drive_id,
     google_apis::StartPageTokenCallback callback) {
   DCHECK(sequence_checker_.CalledOnValidSequence());
@@ -112,10 +112,10 @@
           RelayCallbackToTaskRunner(worker_task_runner_.get(), FROM_HERE,
                                     std::move(callback))));
 
-  return google_apis::CancelCallback();
+  return google_apis::CancelCallbackOnce();
 }
 
-google_apis::CancelCallback DriveServiceOnWorker::GetChangeList(
+google_apis::CancelCallbackOnce DriveServiceOnWorker::GetChangeList(
     int64_t start_changestamp,
     google_apis::ChangeListCallback callback) {
   DCHECK(sequence_checker_.CalledOnValidSequence());
@@ -127,10 +127,10 @@
           RelayCallbackToTaskRunner(worker_task_runner_.get(), FROM_HERE,
                                     std::move(callback))));
 
-  return google_apis::CancelCallback();
+  return google_apis::CancelCallbackOnce();
 }
 
-google_apis::CancelCallback DriveServiceOnWorker::GetChangeListByToken(
+google_apis::CancelCallbackOnce DriveServiceOnWorker::GetChangeListByToken(
     const std::string& team_drive_id,
     const std::string& start_page_token,
     google_apis::ChangeListCallback callback) {
@@ -143,7 +143,7 @@
                                     worker_task_runner_.get(), FROM_HERE,
                                     std::move(callback))));
 
-  return google_apis::CancelCallback();
+  return google_apis::CancelCallbackOnce();
 }
 
 google_apis::CancelCallbackOnce DriveServiceOnWorker::GetRemainingChangeList(
@@ -167,7 +167,7 @@
   return "root";
 }
 
-google_apis::CancelCallback DriveServiceOnWorker::GetRemainingTeamDriveList(
+google_apis::CancelCallbackOnce DriveServiceOnWorker::GetRemainingTeamDriveList(
     const std::string& page_token,
     google_apis::TeamDriveListCallback callback) {
   DCHECK(sequence_checker_.CalledOnValidSequence());
@@ -179,7 +179,7 @@
           RelayCallbackToTaskRunner(worker_task_runner_.get(), FROM_HERE,
                                     std::move(callback))));
 
-  return google_apis::CancelCallback();
+  return google_apis::CancelCallbackOnce();
 }
 
 google_apis::CancelCallbackOnce DriveServiceOnWorker::GetRemainingFileList(
@@ -197,7 +197,7 @@
   return google_apis::CancelCallbackOnce();
 }
 
-google_apis::CancelCallback DriveServiceOnWorker::GetFileResource(
+google_apis::CancelCallbackOnce DriveServiceOnWorker::GetFileResource(
     const std::string& resource_id,
     google_apis::FileResourceCallback callback) {
   DCHECK(sequence_checker_.CalledOnValidSequence());
@@ -209,7 +209,7 @@
           RelayCallbackToTaskRunner(worker_task_runner_.get(), FROM_HERE,
                                     std::move(callback))));
 
-  return google_apis::CancelCallback();
+  return google_apis::CancelCallbackOnce();
 }
 
 google_apis::CancelCallbackOnce DriveServiceOnWorker::GetFileListInDirectory(
@@ -319,27 +319,27 @@
     const std::string& search_query,
     google_apis::FileListCallback callback) {
   NOTREACHED();
-  return google_apis::CancelCallback();
+  return google_apis::CancelCallbackOnce();
 }
 
-google_apis::CancelCallback DriveServiceOnWorker::TrashResource(
+google_apis::CancelCallbackOnce DriveServiceOnWorker::TrashResource(
     const std::string& resource_id,
     google_apis::EntryActionCallback callback) {
   NOTREACHED();
-  return google_apis::CancelCallback();
+  return google_apis::CancelCallbackOnce();
 }
 
-google_apis::CancelCallback DriveServiceOnWorker::CopyResource(
+google_apis::CancelCallbackOnce DriveServiceOnWorker::CopyResource(
     const std::string& resource_id,
     const std::string& parent_resource_id,
     const std::string& new_title,
     const base::Time& last_modified,
     google_apis::FileResourceCallback callback) {
   NOTREACHED();
-  return google_apis::CancelCallback();
+  return google_apis::CancelCallbackOnce();
 }
 
-google_apis::CancelCallback DriveServiceOnWorker::UpdateResource(
+google_apis::CancelCallbackOnce DriveServiceOnWorker::UpdateResource(
     const std::string& resource_id,
     const std::string& parent_resource_id,
     const std::string& new_title,
@@ -348,18 +348,18 @@
     const google_apis::drive::Properties& properties,
     google_apis::FileResourceCallback callback) {
   NOTREACHED();
-  return google_apis::CancelCallback();
+  return google_apis::CancelCallbackOnce();
 }
 
-google_apis::CancelCallback DriveServiceOnWorker::AddResourceToDirectory(
+google_apis::CancelCallbackOnce DriveServiceOnWorker::AddResourceToDirectory(
     const std::string& parent_resource_id,
     const std::string& resource_id,
     google_apis::EntryActionCallback callback) {
   NOTREACHED();
-  return google_apis::CancelCallback();
+  return google_apis::CancelCallbackOnce();
 }
 
-google_apis::CancelCallback DriveServiceOnWorker::InitiateUploadNewFile(
+google_apis::CancelCallbackOnce DriveServiceOnWorker::InitiateUploadNewFile(
     const std::string& content_type,
     int64_t content_length,
     const std::string& parent_resource_id,
@@ -367,20 +367,21 @@
     const drive::UploadNewFileOptions& options,
     google_apis::InitiateUploadCallback callback) {
   NOTREACHED();
-  return google_apis::CancelCallback();
+  return google_apis::CancelCallbackOnce();
 }
 
-google_apis::CancelCallback DriveServiceOnWorker::InitiateUploadExistingFile(
+google_apis::CancelCallbackOnce
+DriveServiceOnWorker::InitiateUploadExistingFile(
     const std::string& content_type,
     int64_t content_length,
     const std::string& resource_id,
     const drive::UploadExistingFileOptions& options,
     google_apis::InitiateUploadCallback callback) {
   NOTREACHED();
-  return google_apis::CancelCallback();
+  return google_apis::CancelCallbackOnce();
 }
 
-google_apis::CancelCallback DriveServiceOnWorker::ResumeUpload(
+google_apis::CancelCallbackOnce DriveServiceOnWorker::ResumeUpload(
     const GURL& upload_url,
     int64_t start_position,
     int64_t end_position,
@@ -390,19 +391,18 @@
     google_apis::drive::UploadRangeCallback callback,
     google_apis::ProgressCallback progress_callback) {
   NOTREACHED();
-  return google_apis::CancelCallback();
+  return google_apis::CancelCallbackOnce();
 }
 
-google_apis::CancelCallback DriveServiceOnWorker::GetUploadStatus(
+google_apis::CancelCallbackOnce DriveServiceOnWorker::GetUploadStatus(
     const GURL& upload_url,
     int64_t content_length,
     google_apis::drive::UploadRangeCallback callback) {
   NOTREACHED();
-  return google_apis::CancelCallback();
+  return google_apis::CancelCallbackOnce();
 }
 
-google_apis::CancelCallbackRepeating
-DriveServiceOnWorker::MultipartUploadNewFile(
+google_apis::CancelCallbackOnce DriveServiceOnWorker::MultipartUploadNewFile(
     const std::string& content_type,
     int64_t content_length,
     const std::string& parent_resource_id,
@@ -412,10 +412,11 @@
     google_apis::FileResourceCallback callback,
     google_apis::ProgressCallback progress_callback) {
   NOTREACHED();
-  return google_apis::CancelCallbackRepeating();
+  return google_apis::CancelCallbackOnce();
 }
 
-google_apis::CancelCallback DriveServiceOnWorker::MultipartUploadExistingFile(
+google_apis::CancelCallbackOnce
+DriveServiceOnWorker::MultipartUploadExistingFile(
     const std::string& content_type,
     int64_t content_length,
     const std::string& parent_resource_id,
@@ -424,7 +425,7 @@
     google_apis::FileResourceCallback callback,
     google_apis::ProgressCallback progress_callback) {
   NOTREACHED();
-  return google_apis::CancelCallback();
+  return google_apis::CancelCallbackOnce();
 }
 
 std::unique_ptr<drive::BatchRequestConfiguratorInterface>
@@ -433,13 +434,13 @@
   return std::unique_ptr<drive::BatchRequestConfiguratorInterface>();
 }
 
-google_apis::CancelCallback DriveServiceOnWorker::AddPermission(
+google_apis::CancelCallbackOnce DriveServiceOnWorker::AddPermission(
     const std::string& resource_id,
     const std::string& email,
     google_apis::drive::PermissionRole role,
     google_apis::EntryActionCallback callback) {
   NOTREACHED();
-  return google_apis::CancelCallback();
+  return google_apis::CancelCallbackOnce();
 }
 
 }  // namespace drive_backend
diff --git a/chrome/browser/sync_file_system/drive_backend/drive_service_on_worker.h b/chrome/browser/sync_file_system/drive_backend/drive_service_on_worker.h
index d1b9d18f6..62ca59d 100644
--- a/chrome/browser/sync_file_system/drive_backend/drive_service_on_worker.h
+++ b/chrome/browser/sync_file_system/drive_backend/drive_service_on_worker.h
@@ -44,7 +44,7 @@
       const drive::AddNewDirectoryOptions& options,
       google_apis::FileResourceCallback callback) override;
 
-  google_apis::CancelCallback DeleteResource(
+  google_apis::CancelCallbackOnce DeleteResource(
       const std::string& resource_id,
       const std::string& etag,
       google_apis::EntryActionCallback callback) override;
@@ -56,18 +56,18 @@
       const google_apis::GetContentCallback& get_content_callback,
       google_apis::ProgressCallback progress_callback) override;
 
-  google_apis::CancelCallback GetAboutResource(
+  google_apis::CancelCallbackOnce GetAboutResource(
       google_apis::AboutResourceCallback callback) override;
 
-  google_apis::CancelCallback GetStartPageToken(
+  google_apis::CancelCallbackOnce GetStartPageToken(
       const std::string& team_drive_id,
       google_apis::StartPageTokenCallback callback) override;
 
-  google_apis::CancelCallback GetChangeList(
+  google_apis::CancelCallbackOnce GetChangeList(
       int64_t start_changestamp,
       google_apis::ChangeListCallback callback) override;
 
-  google_apis::CancelCallback GetChangeListByToken(
+  google_apis::CancelCallbackOnce GetChangeListByToken(
       const std::string& team_drive_id,
       const std::string& start_page_token,
       google_apis::ChangeListCallback callback) override;
@@ -78,7 +78,7 @@
 
   std::string GetRootResourceId() const override;
 
-  google_apis::CancelCallback GetRemainingTeamDriveList(
+  google_apis::CancelCallbackOnce GetRemainingTeamDriveList(
       const std::string& page_token,
       google_apis::TeamDriveListCallback callback) override;
 
@@ -86,7 +86,7 @@
       const GURL& next_link,
       google_apis::FileListCallback callback) override;
 
-  google_apis::CancelCallback GetFileResource(
+  google_apis::CancelCallbackOnce GetFileResource(
       const std::string& resource_id,
       google_apis::FileResourceCallback callback) override;
 
@@ -123,16 +123,16 @@
   google_apis::CancelCallbackOnce Search(
       const std::string& search_query,
       google_apis::FileListCallback callback) override;
-  google_apis::CancelCallback TrashResource(
+  google_apis::CancelCallbackOnce TrashResource(
       const std::string& resource_id,
       google_apis::EntryActionCallback callback) override;
-  google_apis::CancelCallback CopyResource(
+  google_apis::CancelCallbackOnce CopyResource(
       const std::string& resource_id,
       const std::string& parent_resource_id,
       const std::string& new_title,
       const base::Time& last_modified,
       google_apis::FileResourceCallback callback) override;
-  google_apis::CancelCallback UpdateResource(
+  google_apis::CancelCallbackOnce UpdateResource(
       const std::string& resource_id,
       const std::string& parent_resource_id,
       const std::string& new_title,
@@ -140,24 +140,24 @@
       const base::Time& last_viewed_by_me,
       const google_apis::drive::Properties& properties,
       google_apis::FileResourceCallback callback) override;
-  google_apis::CancelCallback AddResourceToDirectory(
+  google_apis::CancelCallbackOnce AddResourceToDirectory(
       const std::string& parent_resource_id,
       const std::string& resource_id,
       google_apis::EntryActionCallback callback) override;
-  google_apis::CancelCallback InitiateUploadNewFile(
+  google_apis::CancelCallbackOnce InitiateUploadNewFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& parent_resource_id,
       const std::string& title,
       const drive::UploadNewFileOptions& options,
       google_apis::InitiateUploadCallback callback) override;
-  google_apis::CancelCallback InitiateUploadExistingFile(
+  google_apis::CancelCallbackOnce InitiateUploadExistingFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& resource_id,
       const drive::UploadExistingFileOptions& options,
       google_apis::InitiateUploadCallback callback) override;
-  google_apis::CancelCallback ResumeUpload(
+  google_apis::CancelCallbackOnce ResumeUpload(
       const GURL& upload_url,
       int64_t start_position,
       int64_t end_position,
@@ -166,11 +166,11 @@
       const base::FilePath& local_file_path,
       google_apis::drive::UploadRangeCallback callback,
       google_apis::ProgressCallback progress_callback) override;
-  google_apis::CancelCallback GetUploadStatus(
+  google_apis::CancelCallbackOnce GetUploadStatus(
       const GURL& upload_url,
       int64_t content_length,
       google_apis::drive::UploadRangeCallback callback) override;
-  google_apis::CancelCallbackRepeating MultipartUploadNewFile(
+  google_apis::CancelCallbackOnce MultipartUploadNewFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& parent_resource_id,
@@ -179,7 +179,7 @@
       const drive::UploadNewFileOptions& options,
       google_apis::FileResourceCallback callback,
       google_apis::ProgressCallback progress_callback) override;
-  google_apis::CancelCallbackRepeating MultipartUploadExistingFile(
+  google_apis::CancelCallbackOnce MultipartUploadExistingFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& resource_id,
@@ -189,7 +189,7 @@
       google_apis::ProgressCallback progress_callback) override;
   std::unique_ptr<drive::BatchRequestConfiguratorInterface> StartBatchRequest()
       override;
-  google_apis::CancelCallback AddPermission(
+  google_apis::CancelCallbackOnce AddPermission(
       const std::string& resource_id,
       const std::string& email,
       google_apis::drive::PermissionRole role,
diff --git a/chrome/browser/sync_file_system/drive_backend/fake_drive_uploader.cc b/chrome/browser/sync_file_system/drive_backend/fake_drive_uploader.cc
index e1ed068..4e37b8c 100644
--- a/chrome/browser/sync_file_system/drive_backend/fake_drive_uploader.cc
+++ b/chrome/browser/sync_file_system/drive_backend/fake_drive_uploader.cc
@@ -16,7 +16,6 @@
 
 using drive::FakeDriveService;
 using drive::UploadCompletionCallback;
-using google_apis::CancelCallback;
 using google_apis::CancelCallbackOnce;
 using google_apis::DriveApiErrorCode;
 using google_apis::FileResource;
diff --git a/chrome/browser/ui/ash/clipboard_history_browsertest.cc b/chrome/browser/ui/ash/clipboard_history_browsertest.cc
index 6c676c2c..9e8583d 100644
--- a/chrome/browser/ui/ash/clipboard_history_browsertest.cc
+++ b/chrome/browser/ui/ash/clipboard_history_browsertest.cc
@@ -866,26 +866,9 @@
       GetContextMenu()->GetMenuItemViewAtForTest(/*index=*/0);
   GetEventGenerator()->MoveMouseTo(
       inaccessible_menu_item_view->GetBoundsInScreen().CenterPoint());
-
-  // Verify that `inaccessible_menu_item_view` cannot be selected by mouse
-  // hovering. It does not respond to mouse click either.
-  EXPECT_FALSE(inaccessible_menu_item_view->IsSelected());
   GetEventGenerator()->ClickLeftButton();
+
+  // Verify that the text is not pasted and menu is closed after click.
   EXPECT_EQ("", base::UTF16ToUTF8(textfield_->GetText()));
-
-  // Move the selection through the arrow key. Then delete the item by the
-  // backspace key. After deletion, `inaccessible_menu_item_view` is left.
-  PressAndRelease(ui::KeyboardCode::VKEY_DOWN, ui::EF_NONE);
-  PressAndRelease(ui::KeyboardCode::VKEY_BACK, ui::EF_NONE);
-  EXPECT_TRUE(VerifyClipboardTextData({"B"}));
-  EXPECT_EQ(1, GetContextMenu()->GetMenuItemsCount());
-
-  // Move the selection through the arrow key again. Verify that
-  // `inaccessible_menu_item_view` cannot be selected. Pressing the backspace
-  // key does not delete the item.
-  PressAndRelease(ui::KeyboardCode::VKEY_DOWN, ui::EF_NONE);
-  PressAndRelease(ui::KeyboardCode::VKEY_BACK, ui::EF_NONE);
-  EXPECT_FALSE(inaccessible_menu_item_view->IsSelected());
-  EXPECT_TRUE(VerifyClipboardTextData({"B"}));
-  EXPECT_EQ(1, GetContextMenu()->GetMenuItemsCount());
+  EXPECT_FALSE(GetClipboardHistoryController()->IsMenuShowing());
 }
diff --git a/chrome/browser/ui/cocoa/notifications/unnotification_builder_mac_unittest.mm b/chrome/browser/ui/cocoa/notifications/unnotification_builder_mac_unittest.mm
index 021c0bb8..26430bf1 100644
--- a/chrome/browser/ui/cocoa/notifications/unnotification_builder_mac_unittest.mm
+++ b/chrome/browser/ui/cocoa/notifications/unnotification_builder_mac_unittest.mm
@@ -10,6 +10,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_path_override.h"
 #include "base/test/task_environment.h"
+#include "build/build_config.h"
 #include "chrome/browser/notifications/notification_handler.h"
 #include "chrome/browser/notifications/notification_image_retainer.h"
 #include "chrome/browser/ui/cocoa/notifications/notification_constants_mac.h"
@@ -511,7 +512,14 @@
   }
 }
 
-TEST(UNNotificationBuilderMacTest, TestIconWrongPath) {
+#if defined(ARCH_CPU_ARM64)
+// Bulk-disabled for arm64 bot stabilization: https://crbug.com/1154345
+#define MAYBE_TestIconWrongPath DISABLED_TestIconWrongPath
+#else
+#define MAYBE_TestIconWrongPath TestIconWrongPath
+#endif
+
+TEST(UNNotificationBuilderMacTest, MAYBE_TestIconWrongPath) {
   if (@available(macOS 10.14, *)) {
     base::scoped_nsobject<UNNotificationBuilder> builder =
         NewTestBuilder(NotificationHandler::Type::WEB_PERSISTENT);
diff --git a/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc b/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc
index b8d8c0f..2f1b067 100644
--- a/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc
+++ b/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc
@@ -11,7 +11,6 @@
 #include "base/bind.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/global_media_controls/media_notification_service.h"
 #include "chrome/browser/ui/global_media_controls/overlay_media_notification.h"
@@ -23,6 +22,7 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/sync_preferences/pref_service_syncable.h"
+#include "components/vector_icons/vector_icons.h"
 #include "media/base/media_switches.h"
 #include "services/media_session/public/mojom/media_session.mojom.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -254,9 +254,9 @@
   }
 
   auto live_caption_image = std::make_unique<views::ImageView>();
-  live_caption_image->SetImage(
-      gfx::CreateVectorIcon(kLiveCaptionIcon, kLiveCaptionImageWidthDip,
-                            SkColor(gfx::kGoogleGrey700)));
+  live_caption_image->SetImage(gfx::CreateVectorIcon(
+      vector_icons::kLiveCaptionOnIcon, kLiveCaptionImageWidthDip,
+      SkColor(gfx::kGoogleGrey700)));
   live_caption_container->AddChildView(std::move(live_caption_image));
 
   auto live_caption_title = std::make_unique<views::Label>(
@@ -281,9 +281,9 @@
     live_caption_title_->SetVisible(false);
   }
 
-  auto live_caption_button =
-      std::make_unique<views::ToggleButton>(base::BindRepeating(
-          &MediaDialogView::LiveCaptionButtonPressed, base::Unretained(this)));
+  auto live_caption_button = std::make_unique<views::ToggleButton>(
+      base::BindRepeating(&MediaDialogView::OnLiveCaptionButtonPressed,
+                          base::Unretained(this)));
   live_caption_button->SetIsOn(
       profile_->GetPrefs()->GetBoolean(prefs::kLiveCaptionEnabled));
   live_caption_button->SetAccessibleName(live_caption_title_->GetText());
@@ -305,7 +305,7 @@
   }
 }
 
-void MediaDialogView::LiveCaptionButtonPressed(const ui::Event& event) {
+void MediaDialogView::OnLiveCaptionButtonPressed() {
   bool enabled = !profile_->GetPrefs()->GetBoolean(prefs::kLiveCaptionEnabled);
   ToggleLiveCaption(enabled);
   base::UmaHistogramBoolean(
diff --git a/chrome/browser/ui/views/global_media_controls/media_dialog_view.h b/chrome/browser/ui/views/global_media_controls/media_dialog_view.h
index 14eccb3..5e49e175 100644
--- a/chrome/browser/ui/views/global_media_controls/media_dialog_view.h
+++ b/chrome/browser/ui/views/global_media_controls/media_dialog_view.h
@@ -92,7 +92,7 @@
   void WindowClosing() override;
 
   // views::Button::PressedCallback
-  void LiveCaptionButtonPressed(const ui::Event& event);
+  void OnLiveCaptionButtonPressed();
 
   void ToggleLiveCaption(bool enabled);
   void UpdateBubbleSize();
diff --git a/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.cc b/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.cc
index a7732fa..0541b2e 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.cc
@@ -99,10 +99,27 @@
 }
 
 ax::mojom::Role LocationBarBubbleDelegateView::GetAccessibleWindowRole() {
-  if (display_reason_ == USER_GESTURE)
+  if (display_reason_ == USER_GESTURE) {
+    // crbug.com/1132318: The bubble appears as a direct result of a user
+    // action and will get focused. If we used an alert-like role, it would
+    // produce an event that would cause double-speaking the bubble.
     return ax::mojom::Role::kDialog;
+  }
 
+  // crbug.com/1079320, crbug.com/1119367, crbug.com/1119734: The bubble
+  // appears spontaneously over the course of the user's interaction with
+  // Chrome and doesn't get focused. We need an alert-like role so the
+  // corresponding event is triggered and ATs announce the bubble.
+#if defined(OS_WIN)
+  // crbug.com/1125118: Windows ATs only announce these bubbles if the alert
+  // role is used, despite it not being the most appropriate choice.
+  // TODO(accessibility): review the role mappings for alerts and dialogs,
+  // making sure they are translated to the best candidate in each flatform
+  // without resorting to hacks like this.
+  return ax::mojom::Role::kAlert;
+#else
   return ax::mojom::Role::kAlertDialog;
+#endif
 }
 
 void LocationBarBubbleDelegateView::OnFullscreenStateChanged() {
diff --git a/chrome/browser/ui/views/permission_bubble/permission_prompt_bubble_view.cc b/chrome/browser/ui/views/permission_bubble/permission_prompt_bubble_view.cc
index 39cb0c2..82f17c1b 100644
--- a/chrome/browser/ui/views/permission_bubble/permission_prompt_bubble_view.cc
+++ b/chrome/browser/ui/views/permission_bubble/permission_prompt_bubble_view.cc
@@ -39,6 +39,8 @@
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/layout/box_layout.h"
+#include "ui/views/layout/layout_provider.h"
+#include "ui/views/style/platform_style.h"
 #include "ui/views/widget/widget.h"
 
 PermissionPromptBubbleView::PermissionPromptBubbleView(
@@ -60,41 +62,65 @@
   SetDefaultButton(ui::DIALOG_BUTTON_NONE);
 
   if (ShouldShowAllowThisTimeButton()) {
+    // Host every button in the extra_view to have full control over the width
+    // of the dialog.
+    SetButtons(ui::DIALOG_BUTTON_NONE);
+
+    views::LayoutProvider* const layout_provider = views::LayoutProvider::Get();
+    const int button_spacing = layout_provider->GetDistanceMetric(
+        views::DISTANCE_RELATED_BUTTON_HORIZONTAL);
+    auto buttons_container = std::make_unique<views::View>();
+    buttons_container->SetLayoutManager(std::make_unique<views::BoxLayout>(
+        views::BoxLayout::Orientation::kHorizontal, gfx::Insets(),
+        button_spacing));
+
+    auto allow_once_button = std::make_unique<views::MdTextButton>(
+        base::BindRepeating(
+            &PermissionPromptBubbleView::AcceptPermissionThisTime,
+            base::Unretained(this)),
+        l10n_util::GetStringUTF16(IDS_PERMISSION_ALLOW_ONCE));
+
+    auto allow_always_button = std::make_unique<views::MdTextButton>(
+        base::BindRepeating(&PermissionPromptBubbleView::AcceptPermission,
+                            base::Unretained(this)),
+        l10n_util::GetStringUTF16(IDS_PERMISSION_ALLOW_ALWAYS));
+
+    auto block_button = std::make_unique<views::MdTextButton>(
+        base::BindRepeating(&PermissionPromptBubbleView::DenyPermission,
+                            base::Unretained(this)),
+        l10n_util::GetStringUTF16(IDS_PERMISSION_DENY));
+
     if (permissions::feature_params::kOkButtonBehavesAsAllowAlways.Get()) {
-      SetButtonLabel(ui::DIALOG_BUTTON_OK,
-                     l10n_util::GetStringUTF16(IDS_PERMISSION_ALLOW_ALWAYS));
-      SetAcceptCallback(
-          base::BindOnce(&PermissionPromptBubbleView::AcceptPermission,
-                         base::Unretained(this)));
-
-      SetExtraView(std::make_unique<views::MdTextButton>(
-          base::BindRepeating(
-              &PermissionPromptBubbleView::AcceptPermissionThisTime,
-              base::Unretained(this)),
-          l10n_util::GetStringUTF16(IDS_PERMISSION_ALLOW_ONCE)));
+      buttons_container->AddChildView(std::move(allow_once_button));
+      if (views::PlatformStyle::kIsOkButtonLeading) {
+        buttons_container->AddChildView(std::move(allow_always_button));
+        buttons_container->AddChildView(std::move(block_button));
+      } else {
+        buttons_container->AddChildView(std::move(block_button));
+        buttons_container->AddChildView(std::move(allow_always_button));
+      }
     } else {
-      SetButtonLabel(ui::DIALOG_BUTTON_OK,
-                     l10n_util::GetStringUTF16(IDS_PERMISSION_ALLOW_ONCE));
-      SetAcceptCallback(
-          base::BindOnce(&PermissionPromptBubbleView::AcceptPermissionThisTime,
-                         base::Unretained(this)));
-
-      SetExtraView(std::make_unique<views::MdTextButton>(
-          base::BindRepeating(&PermissionPromptBubbleView::AcceptPermission,
-                              base::Unretained(this)),
-          l10n_util::GetStringUTF16(IDS_PERMISSION_ALLOW_ALWAYS)));
+      buttons_container->AddChildView(std::move(allow_always_button));
+      if (views::PlatformStyle::kIsOkButtonLeading) {
+        buttons_container->AddChildView(std::move(allow_once_button));
+        buttons_container->AddChildView(std::move(block_button));
+      } else {
+        buttons_container->AddChildView(std::move(block_button));
+        buttons_container->AddChildView(std::move(allow_once_button));
+      }
     }
+    SetExtraView(std::move(buttons_container));
   } else {
     SetButtonLabel(ui::DIALOG_BUTTON_OK,
                    l10n_util::GetStringUTF16(IDS_PERMISSION_ALLOW));
     SetAcceptCallback(base::BindOnce(
         &PermissionPromptBubbleView::AcceptPermission, base::Unretained(this)));
-  }
 
-  SetButtonLabel(ui::DIALOG_BUTTON_CANCEL,
-                 l10n_util::GetStringUTF16(IDS_PERMISSION_DENY));
-  SetCancelCallback(base::BindOnce(&PermissionPromptBubbleView::DenyPermission,
-                                   base::Unretained(this)));
+    SetButtonLabel(ui::DIALOG_BUTTON_CANCEL,
+                   l10n_util::GetStringUTF16(IDS_PERMISSION_DENY));
+    SetCancelCallback(base::BindOnce(
+        &PermissionPromptBubbleView::DenyPermission, base::Unretained(this)));
+  }
 
   SetPromptStyle(prompt_style);
 
diff --git a/chrome/browser/ui/webui/nearby_share/public/mojom/nearby_share_settings.mojom b/chrome/browser/ui/webui/nearby_share/public/mojom/nearby_share_settings.mojom
index a6498d1..f0ac5fe 100644
--- a/chrome/browser/ui/webui/nearby_share/public/mojom/nearby_share_settings.mojom
+++ b/chrome/browser/ui/webui/nearby_share/public/mojom/nearby_share_settings.mojom
@@ -19,7 +19,9 @@
 };
 
 // TODO(crbug.com/1110098): Remove kUnknown.
-// Represents who the user has chosen to be visible to.
+// Represents who the user has chosen to be visible to. Note: These values are
+// persisted to logs. Entries should not be renumbered and numeric values
+// should never be reused.
 enum Visibility {
   kUnknown = 0,
   // The user is not advertising to anyone.
diff --git a/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc b/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc
index 157ccab..18a237e 100644
--- a/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc
@@ -286,17 +286,17 @@
 }
 
 namespace {
-base::ListValue UsbDevicesToListValue(
-    const std::vector<CrosUsbDeviceInfo> shared_usbs) {
+base::ListValue GetSharableUsbDevices(CrosUsbDetector* detector) {
   base::ListValue usb_devices_list;
-  for (auto& device : shared_usbs) {
+  for (const auto& device : detector->GetDevicesSharableWithCrostini()) {
     base::Value device_info(base::Value::Type::DICTIONARY);
     device_info.SetStringKey("guid", device.guid);
     device_info.SetStringKey("label", device.label);
     bool shared = device.shared_vm_name == crostini::kCrostiniDefaultVmName;
     device_info.SetBoolKey("shared", shared);
-    device_info.SetBoolKey("shareWillReassign",
-                           device.shared_vm_name && !shared);
+    device_info.SetBoolKey(
+        "shareWillReassign",
+        !shared && detector->SharingRequiresReassignPrompt(device));
     usb_devices_list.Append(std::move(device_info));
   }
   return usb_devices_list;
@@ -357,9 +357,8 @@
 void CrostiniHandler::OnUsbDevicesChanged() {
   chromeos::CrosUsbDetector* detector = chromeos::CrosUsbDetector::Get();
   DCHECK(detector);  // This callback is called by the detector.
-  FireWebUIListener(
-      "crostini-shared-usb-devices-changed",
-      UsbDevicesToListValue(detector->GetDevicesSharableWithCrostini()));
+  FireWebUIListener("crostini-shared-usb-devices-changed",
+                    GetSharableUsbDevices(detector));
 }
 
 void CrostiniHandler::HandleExportCrostiniContainer(
diff --git a/chrome/browser/ui/webui/settings/chromeos/plugin_vm_handler.cc b/chrome/browser/ui/webui/settings/chromeos/plugin_vm_handler.cc
index c0517aa..b53e6c3 100644
--- a/chrome/browser/ui/webui/settings/chromeos/plugin_vm_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/plugin_vm_handler.cc
@@ -20,17 +20,17 @@
 
 namespace {
 
-base::ListValue UsbDevicesToListValue(
-    const std::vector<CrosUsbDeviceInfo>& shared_usbs) {
+base::ListValue GetSharableUsbDevices(CrosUsbDetector* detector) {
   base::ListValue usb_devices_list;
-  for (const auto& device : shared_usbs) {
+  for (const auto& device : detector->GetDevicesSharableWithCrostini()) {
     base::Value device_info(base::Value::Type::DICTIONARY);
     device_info.SetStringKey("guid", device.guid);
     device_info.SetStringKey("label", device.label);
     bool shared = device.shared_vm_name == plugin_vm::kPluginVmName;
     device_info.SetBoolKey("shared", shared);
-    device_info.SetBoolKey("shareWillReassign",
-                           device.shared_vm_name && !shared);
+    device_info.SetBoolKey(
+        "shareWillReassign",
+        !shared && detector->SharingRequiresReassignPrompt(device));
     usb_devices_list.Append(std::move(device_info));
   }
   return usb_devices_list;
@@ -151,12 +151,9 @@
 
 void PluginVmHandler::OnUsbDevicesChanged() {
   chromeos::CrosUsbDetector* detector = chromeos::CrosUsbDetector::Get();
-  if (!detector)
-    return;
-
-  FireWebUIListener(
-      "plugin-vm-shared-usb-devices-changed",
-      UsbDevicesToListValue(detector->GetDevicesSharableWithCrostini()));
+  DCHECK(detector);  // This callback is called by the detector.
+  FireWebUIListener("plugin-vm-shared-usb-devices-changed",
+                    GetSharableUsbDevices(detector));
 }
 
 void PluginVmHandler::HandleIsRelaunchNeededForNewPermissions(
diff --git a/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.cc b/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.cc
index 1d50fec..3263ef9f 100644
--- a/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.cc
+++ b/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.cc
@@ -583,7 +583,7 @@
           identity_manager_->GetPrimaryAccountMutator();
       DCHECK(primary_account_mutator);
       primary_account_mutator->ClearPrimaryAccount(
-          signin::PrimaryAccountMutator::ClearAccountsAction::kKeepAll,
+          signin::PrimaryAccountMutator::ClearAccountsAction::kDefault,
           signin_metrics::ABORT_SIGNIN,
           signin_metrics::SignoutDelete::IGNORE_METRIC);
       AbortAndDelete();
diff --git a/chrome/browser/ui/webui/signin/inline_login_dialog_chromeos.cc b/chrome/browser/ui/webui/signin/inline_login_dialog_chromeos.cc
index d6d60f1..6f0b711 100644
--- a/chrome/browser/ui/webui/signin/inline_login_dialog_chromeos.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_dialog_chromeos.cc
@@ -22,6 +22,7 @@
 #include "chrome/browser/supervised_user/supervised_user_service_factory.h"
 #include "chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.h"
 #include "chrome/common/webui_url_constants.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "components/session_manager/core/session_manager.h"
@@ -194,6 +195,12 @@
                 std::min(kSigninDialogHeight, display.work_area().height()));
 }
 
+ui::ModalType InlineLoginDialogChromeOS::GetDialogModalType() const {
+  return chromeos::features::IsAccountManagementFlowsV2Enabled()
+             ? ui::MODAL_TYPE_SYSTEM
+             : ui::MODAL_TYPE_NONE;
+}
+
 std::string InlineLoginDialogChromeOS::GetDialogArgs() const {
   if (url_.GetWithEmptyPath() !=
       GURL(chrome::kChromeUIAccountManagerErrorURL)) {
diff --git a/chrome/browser/ui/webui/signin/inline_login_dialog_chromeos.h b/chrome/browser/ui/webui/signin/inline_login_dialog_chromeos.h
index 638ab47..94270cd 100644
--- a/chrome/browser/ui/webui/signin/inline_login_dialog_chromeos.h
+++ b/chrome/browser/ui/webui/signin/inline_login_dialog_chromeos.h
@@ -103,6 +103,7 @@
 
   // ui::WebDialogDelegate overrides
   void GetDialogSize(gfx::Size* size) const override;
+  ui::ModalType GetDialogModalType() const override;
   std::string GetDialogArgs() const override;
   bool ShouldShowDialogTitle() const override;
   void OnDialogShown(content::WebUI* webui) override;
diff --git a/chrome/browser/ui/webui/signin/inline_login_ui.cc b/chrome/browser/ui/webui/signin/inline_login_ui.cc
index 64b912f..dfdc0528 100644
--- a/chrome/browser/ui/webui/signin/inline_login_ui.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_ui.cc
@@ -31,14 +31,18 @@
 #include "content/public/browser/web_ui_data_source.h"
 #include "content/public/common/content_switches.h"
 #include "services/network/public/mojom/content_security_policy.mojom.h"
+#include "ui/base/webui/web_ui_util.h"
 #include "ui/resources/grit/webui_resources.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/supervised_user/supervised_user_features.h"
+#include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/webui/chromeos/edu_account_login_handler_chromeos.h"
 #include "chrome/browser/ui/webui/chromeos/edu_coexistence_login_handler_chromeos.h"
+#include "chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom.h"
 #include "chrome/browser/ui/webui/signin/inline_login_handler_chromeos.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/strings/grit/ui_strings.h"
 #else
@@ -105,7 +109,7 @@
 }
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-content::WebUIDataSource* CreateWebUIDataSource() {
+content::WebUIDataSource* CreateWebUIDataSource(Profile* profile) {
   content::WebUIDataSource* source =
         content::WebUIDataSource::Create(chrome::kChromeUIChromeSigninHost);
   webui::SetupWebUIDataSource(
@@ -126,6 +130,8 @@
     {"inline_login_app.js", IDR_INLINE_LOGIN_APP_JS},
     {"inline_login_browser_proxy.js", IDR_INLINE_LOGIN_BROWSER_PROXY_JS},
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+    {"welcome_page_app.js", IDR_INLINE_LOGIN_WELCOME_PAGE_APP_JS},
+    {"account_manager_shared_css.js", IDR_ACCOUNT_MANAGER_SHARED_CSS_JS},
     {"gaia_action_buttons.js", IDR_GAIA_ACTION_BUTTONS_JS},
     {"error_screen.js", IDR_ACCOUNT_MANAGER_COMPONENTS_ERROR_SCREEN_JS},
     {"edu", IDR_EDU_LOGIN_EDU_LOGIN_HTML},
@@ -163,30 +169,51 @@
     {"edu_coexistence_css.js", IDR_EDU_COEXISTENCE_EDU_COEXISTENCE_CSS_JS},
 
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+    {"account_manager_welcome_1x.png", IDR_ACCOUNT_MANAGER_WELCOME_1X_PNG},
+    {"account_manager_welcome_2x.png", IDR_ACCOUNT_MANAGER_WELCOME_2X_PNG},
     {"googleg.svg", IDR_ACCOUNT_MANAGER_WELCOME_GOOGLE_LOGO_SVG},
 #endif
     {"family_link_logo.svg", IDR_FAMILY_LINK_LOGO_SVG},
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
   };
-
   webui::AddResourcePathsBulk(source, kResources);
 
-  source->AddLocalizedString("title", IDS_CHROME_SIGNIN_TITLE);
-  source->AddLocalizedString(
-      "accessibleCloseButtonLabel", IDS_SIGNIN_ACCESSIBLE_CLOSE_BUTTON);
-  source->AddLocalizedString(
-      "accessibleBackButtonLabel", IDS_SIGNIN_ACCESSIBLE_BACK_BUTTON);
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  source->AddLocalizedString("accountManagerErrorNoInternetTitle",
-                             IDS_ACCOUNT_MANAGER_ERROR_NO_INTERNET_TITLE);
-  source->AddLocalizedString("accountManagerErrorNoInternetBody",
-                             IDS_ACCOUNT_MANAGER_ERROR_NO_INTERNET_BODY);
-  source->AddLocalizedString(
-      "accountManagerErrorCannotAddAccountTitle",
-      IDS_ACCOUNT_MANAGER_ERROR_CANNOT_ADD_ACCOUNT_TITLE);
-  source->AddLocalizedString("accountManagerErrorCannotAddAccountBody",
-                             IDS_ACCOUNT_MANAGER_ERROR_CANNOT_ADD_ACCOUNT_BODY);
+  static constexpr webui::LocalizedString kLocalizedStrings[] = {
+    {"title", IDS_CHROME_SIGNIN_TITLE},
+    {"accessibleCloseButtonLabel", IDS_SIGNIN_ACCESSIBLE_CLOSE_BUTTON},
+    {"accessibleBackButtonLabel", IDS_SIGNIN_ACCESSIBLE_BACK_BUTTON},
+#if defined(OS_CHROMEOS)
+    {"ok", IDS_APP_OK},
+    {"accountManagerDialogWelcomeTitle",
+     IDS_ACCOUNT_MANAGER_DIALOG_WELCOME_TITLE},
+    {"accountManagerDialogWelcomeBody",
+     IDS_ACCOUNT_MANAGER_DIALOG_WELCOME_BODY},
+    {"accountManagerErrorNoInternetTitle",
+     IDS_ACCOUNT_MANAGER_ERROR_NO_INTERNET_TITLE},
+    {"accountManagerErrorNoInternetBody",
+     IDS_ACCOUNT_MANAGER_ERROR_NO_INTERNET_BODY},
+    {"accountManagerErrorCannotAddAccountTitle",
+     IDS_ACCOUNT_MANAGER_ERROR_CANNOT_ADD_ACCOUNT_TITLE},
+    {"accountManagerErrorCannotAddAccountBody",
+     IDS_ACCOUNT_MANAGER_ERROR_CANNOT_ADD_ACCOUNT_BODY},
 #endif
+  };
+  AddLocalizedStringsBulk(source, kLocalizedStrings);
+
+#if defined(OS_CHROMEOS)
+  source->AddBoolean("isAccountManagementFlowsV2Enabled",
+                     chromeos::features::IsAccountManagementFlowsV2Enabled());
+
+  user_manager::User* user =
+      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+  DCHECK(user);
+  source->AddString("userName", user->GetGivenName());
+  source->AddString("accountManagerOsSettingsUrl",
+                    chrome::GetOSSettingsUrl(
+                        chromeos::settings::mojom::kMyAccountsSubpagePath)
+                        .spec());
+#endif
+
   return source;
 }
 
@@ -231,7 +258,7 @@
     return;
 
   Profile* profile = Profile::FromWebUI(web_ui);
-  content::WebUIDataSource* source = CreateWebUIDataSource();
+  content::WebUIDataSource* source = CreateWebUIDataSource(profile);
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   base::string16 username =
       chromeos::ProfileHelper::Get()->GetUserByProfile(profile)->GetGivenName();
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 5222e7d..cdf9198 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-master-1607039886-9857a5090b09116b4b309953eec41db8862dfe90.profdata
+chrome-linux-master-1607082643-9d7584569e97498303bfc8f363e6d14838d94e40.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index e2b48f38..aa65cb2 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-master-1607039886-1ddd5c45cae9e9c7a03307d574bbe9f5985fa593.profdata
+chrome-mac-master-1607082643-ec3aa91ed6cc9a4e56961da34010bfe7d1bfcfad.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 57c29529..bf88bb32 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-master-1606996231-fb1aa25fe6cd29fd31733f8199da138cbb1f5caf.profdata
+chrome-win32-master-1607061555-42057a46d6898e28766e44cc3eff7a0d211d34f4.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index d056c96..7242510c2 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-master-1607018334-2342e7b4fc523afed7119425e6663fe86ee0646f.profdata
+chrome-win64-master-1607061555-9d7880873554417bd44ed300f865acac635c5256.profdata
diff --git a/chrome/common/chrome_content_client_unittest.cc b/chrome/common/chrome_content_client_unittest.cc
index b95f4612..43c9ba0d 100644
--- a/chrome/common/chrome_content_client_unittest.cc
+++ b/chrome/common/chrome_content_client_unittest.cc
@@ -16,6 +16,7 @@
 #include "content/public/test/test_utils.h"
 #include "extensions/common/constants.h"
 #include "ppapi/buildflags/buildflags.h"
+#include "services/network/public/cpp/is_potentially_trustworthy.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/loader/network_utils.h"
 #include "url/gurl.h"
@@ -110,7 +111,7 @@
   EXPECT_TRUE(blink::network_utils::IsOriginSecure(chrome_url));
   EXPECT_FALSE(content::OriginCanAccessServiceWorkers(chrome_url));
   EXPECT_TRUE(
-      content::IsPotentiallyTrustworthyOrigin(url::Origin::Create(chrome_url)));
+      network::IsOriginPotentiallyTrustworthy(url::Origin::Create(chrome_url)));
 }
 
 class OriginTrialInitializationTestThread
diff --git a/chrome/common/chrome_paths.cc b/chrome/common/chrome_paths.cc
index 959979b..2baba49 100644
--- a/chrome/common/chrome_paths.cc
+++ b/chrome/common/chrome_paths.cc
@@ -565,6 +565,7 @@
       if (!base::PathService::Get(chrome::DIR_USER_DATA, &cur))
         return false;
       cur = cur.Append(FILE_PATH_LITERAL("OptimizationGuidePredictionModels"));
+      create_dir = true;
       break;
 
     default:
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 491d91d..6fec07ee 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -990,13 +990,13 @@
       "../browser/browsing_data/navigation_entry_remover_browsertest.cc",
       "../browser/chrome_back_forward_cache_browsertest.cc",
       "../browser/chrome_content_browser_client_browsertest.cc",
-      "../browser/chrome_cross_origin_opener_policy_browsertest.cc",
       "../browser/chrome_do_not_track_browsertest.cc",
       "../browser/chrome_find_request_manager_browsertest.cc",
       "../browser/chrome_navigation_browsertest.cc",
       "../browser/chrome_origin_trials_browsertest.cc",
       "../browser/chrome_security_exploit_browsertest.cc",
       "../browser/chrome_service_worker_browsertest.cc",
+      "../browser/chrome_web_platform_security_metrics_browsertest.cc",
       "../browser/chrome_worker_browsertest.cc",
       "../browser/client_hints/client_hints_browsertest.cc",
       "../browser/component_updater/component_patcher_operation_browsertest.cc",
@@ -3672,6 +3672,7 @@
     "../browser/previews/previews_service_render_view_unittest.cc",
     "../browser/previews/previews_service_unittest.cc",
     "../browser/previews/previews_ui_tab_helper_unittest.cc",
+    "../browser/privacy_sandbox/privacy_sandbox_settings_unittest.cc",
     "../browser/profiles/gaia_info_update_service_unittest.cc",
     "../browser/profiles/guest_mode_policy_handler_unittest.cc",
     "../browser/profiles/incognito_mode_policy_handler_unittest.cc",
diff --git a/chrome/test/data/extensions/api_test/enterprise_platform_keys/background.js b/chrome/test/data/extensions/api_test/enterprise_platform_keys/background.js
index be4e015..31c4dda 100644
--- a/chrome/test/data/extensions/api_test/enterprise_platform_keys/background.js
+++ b/chrome/test/data/extensions/api_test/enterprise_platform_keys/background.js
@@ -4,12 +4,17 @@
 
 'use strict';
 
-// The message sent from a browsertest to the background script in case the
-// system token is enabled.
-const SYSTEM_TOKEN_ENABLED_MESSAGE = 'System token enabled.';
-// The message sent from a browsertest to the background script in case the
-// system token is disabled.
-const SYSTEM_TOKEN_DISABLED_MESSAGE = 'System token disabled.';
+// TODO(crbug.com/1148294): Add LOGIN_SCREEN_MODE.
+// This message sent from a browsertest to the background script to test the API
+// behavior for an extension running in a user session with system token
+// enabled.
+const USER_SESSION_WITH_SYSTEM_TOKEN_ENABLED_MODE =
+    'User session with system token enabled mode.';
+// This message sent from a browsertest to the background script to test the API
+// behavior for an extension running in a user session with system token
+// disabled.
+const USER_SESSION_WITH_SYSTEM_TOKEN_DISABLED_MODE =
+    'User session with system token disabled mode.';
 
 var assertEq = chrome.test.assertEq;
 var assertTrue = chrome.test.assertTrue;
@@ -881,20 +886,17 @@
   chrome.test.runTests(testsIndependentOfKeys.concat(testsNotParameterized));
 }
 
-// |waitForSystemTokenStateMessage()| waits for the browser test to send a
-// message with the state of the system token to run tests accordingly. The
-// browser test logic can be found at:
+// This function is executed when the C++ side of the test sends the test mode.
+// The browser test logic can be found at:
 // c/b/e/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc
-function waitForSystemTokenStateMessage(systemTokenStateMessage) {
-  if (systemTokenStateMessage == SYSTEM_TOKEN_ENABLED_MESSAGE) {
+function testModeListener(message) {
+  if (message.data === USER_SESSION_WITH_SYSTEM_TOKEN_ENABLED_MODE) {
     beforeTests(/*systemTokenEnabled=*/ true, runTests);
-  } else if (systemTokenStateMessage == SYSTEM_TOKEN_DISABLED_MESSAGE) {
+  } else if (message.data === USER_SESSION_WITH_SYSTEM_TOKEN_DISABLED_MODE) {
     beforeTests(/*systemTokenEnabled=*/ false, runTests);
   } else {
-    // No background script tests should run.
-    succeed();
+    fail();
   }
 }
 
-chrome.test.sendMessage(
-    'Waiting for system token state message', waitForSystemTokenStateMessage);
+chrome.test.onMessage.addListener(testModeListener);
diff --git a/chrome/test/data/media/media_history.html b/chrome/test/data/media/media_history.html
index 223618ea..4a6f79c 100644
--- a/chrome/test/data/media/media_history.html
+++ b/chrome/test/data/media/media_history.html
@@ -80,5 +80,15 @@
   const video = document.querySelector('video');
   video.currentTime = video.duration;
 }
+
+function enterPictureInPicture() {
+  const video = document.querySelector('video');
+  video.requestPictureInPicture().then(() => {
+    window.domAutomationController.send(true);
+  }).catch(() => {
+    window.domAutomationController.send(false);
+  });
+}
+
 </script>
 </html>
diff --git a/chrome/test/data/optimization_guide/unsignedmodel.crx3 b/chrome/test/data/optimization_guide/unsignedmodel.crx3
new file mode 100644
index 0000000..6c09929
--- /dev/null
+++ b/chrome/test/data/optimization_guide/unsignedmodel.crx3
Binary files differ
diff --git a/chrome/test/data/webui/nearby_share/nearby_confirmation_page_test.js b/chrome/test/data/webui/nearby_share/nearby_confirmation_page_test.js
index 6f22fe2..6798243 100644
--- a/chrome/test/data/webui/nearby_share/nearby_confirmation_page_test.js
+++ b/chrome/test/data/webui/nearby_share/nearby_confirmation_page_test.js
@@ -95,7 +95,7 @@
     };
     const renderedName = confirmationPageElement.$$('nearby-progress')
                              .$$('#device-name')
-                             .textContent;
+                             .innerText;
     assertEquals(name, renderedName);
   });
 
diff --git a/chrome/test/data/webui/nearby_share/nearby_progress_test.js b/chrome/test/data/webui/nearby_share/nearby_progress_test.js
index afef1f9..4d18741 100644
--- a/chrome/test/data/webui/nearby_share/nearby_progress_test.js
+++ b/chrome/test/data/webui/nearby_share/nearby_progress_test.js
@@ -38,7 +38,7 @@
     });
     progressElement.shareTarget = shareTarget;
 
-    const renderedName = progressElement.$$('#device-name').textContent;
+    const renderedName = progressElement.$$('#device-name').innerText;
     assertEquals(name, renderedName);
   });
 });
diff --git a/chrome/test/data/webui/print_preview/destination_select_test_cros.js b/chrome/test/data/webui/print_preview/destination_select_test_cros.js
index 4f4c41b..7e80273 100644
--- a/chrome/test/data/webui/print_preview/destination_select_test_cros.js
+++ b/chrome/test/data/webui/print_preview/destination_select_test_cros.js
@@ -359,7 +359,8 @@
       destinationSelect.destination = crosEnterprisePrinter;
       destinationSelect.updateDestination();
       assertEquals(
-          'print-preview:printer-status-grey', dropdown.destinationIcon);
+          'print-preview:business-printer-status-grey',
+          dropdown.destinationIcon);
 
       destinationSelect.destination = mobilePrinter;
       destinationSelect.updateDestination();
diff --git a/chrome/test/data/webui/settings/password_check_test.js b/chrome/test/data/webui/settings/password_check_test.js
index a530a8b..1fd5acb9 100644
--- a/chrome/test/data/webui/settings/password_check_test.js
+++ b/chrome/test/data/webui/settings/password_check_test.js
@@ -653,6 +653,27 @@
     expectFalse(icon.classList.contains('no-security-issues'));
   });
 
+  // Tests that the spinner is replaced with an info icon if only weak passwords
+  // were found.
+  test('showsInfoIconWhenFinishedWithWeakPasswords', async function() {
+    loadTimeData.overrideValues({passwordsWeaknessCheck: true});
+    const data = passwordManager.data;
+    assertEquals(PasswordCheckState.IDLE, data.checkStatus.state);
+    data.weakCredentials = [
+      makeInsecureCredential('one.com', 'test5'),
+    ];
+
+    const checkPasswordSection = createCheckPasswordSection();
+    await passwordManager.whenCalled('getPasswordCheckStatus');
+    flush();
+    const icon = checkPasswordSection.$$('iron-icon');
+    const spinner = checkPasswordSection.$$('paper-spinner-lite');
+    expectFalse(isElementVisible(spinner));
+    assertTrue(isElementVisible(icon));
+    expectFalse(icon.classList.contains('has-security-issues'));
+    expectFalse(icon.classList.contains('no-security-issues'));
+  });
+
   // Tests that the spinner is replaced with a warning on errors.
   test('showsInfoIconWhenFinishedWithErrors', async function() {
     passwordManager.data.checkStatus = makePasswordCheckStatus(
diff --git a/chromecast/media/cma/backend/android/volume_control_android.cc b/chromecast/media/cma/backend/android/volume_control_android.cc
index ae3175c..d22658e 100644
--- a/chromecast/media/cma/backend/android/volume_control_android.cc
+++ b/chromecast/media/cma/backend/android/volume_control_android.cc
@@ -133,7 +133,8 @@
   thread_.task_runner()->PostTask(
       FROM_HERE,
       base::BindOnce(&VolumeControlAndroid::ReportVolumeChangeOnThread,
-                     base::Unretained(this), (AudioContentType)type, level));
+                     base::Unretained(this),
+                     static_cast<AudioContentType>(type), level));
 }
 
 void VolumeControlAndroid::OnMuteChange(
@@ -142,9 +143,9 @@
     jint type,
     jboolean muted) {
   thread_.task_runner()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&VolumeControlAndroid::ReportMuteChangeOnThread,
-                     base::Unretained(this), (AudioContentType)type, muted));
+      FROM_HERE, base::BindOnce(&VolumeControlAndroid::ReportMuteChangeOnThread,
+                                base::Unretained(this),
+                                static_cast<AudioContentType>(type), muted));
 }
 
 #if BUILDFLAG(ENABLE_VOLUME_TABLES_ACCESS)
@@ -335,7 +336,7 @@
 
 // static
 void VolumeControl::Initialize(const std::vector<std::string>& argv) {
-  // Nothing to do.
+  GetVolumeControl();
 }
 
 // static
diff --git a/chromeos/components/sensors/mojom/sensor.mojom b/chromeos/components/sensors/mojom/sensor.mojom
index ee18e46..121deb0 100644
--- a/chromeos/components/sensors/mojom/sensor.mojom
+++ b/chromeos/components/sensors/mojom/sensor.mojom
@@ -44,8 +44,8 @@
   COUNT = 4,
   MAGN = 5,
   ANGL = 6,
-  ACPI_ALS = 7,
-  BARO = 8,
+  BARO = 7,
+  MAX = 8,
 };
 
 enum ObserverErrorType {
diff --git a/chromeos/disks/mock_disk_mount_manager.cc b/chromeos/disks/mock_disk_mount_manager.cc
index 38094f8..c3e7392 100644
--- a/chromeos/disks/mock_disk_mount_manager.cc
+++ b/chromeos/disks/mock_disk_mount_manager.cc
@@ -147,6 +147,11 @@
 }
 
 void MockDiskMountManager::CreateDiskEntryForMountDevice(
+    std::unique_ptr<Disk> disk) {
+  disks_[disk->device_path()] = std::move(disk);
+}
+
+void MockDiskMountManager::CreateDiskEntryForMountDevice(
     const DiskMountManager::MountPointInfo& mount_info,
     const std::string& device_id,
     const std::string& device_label,
@@ -176,7 +181,7 @@
           .SetOnRemovableDevice(on_removable_device)
           .SetFileSystemType(file_system_type)
           .Build();
-  disks_[std::string(mount_info.source_path)] = std::move(disk_ptr);
+  CreateDiskEntryForMountDevice(std::move(disk_ptr));
 }
 
 void MockDiskMountManager::RemoveDiskEntryForMountDevice(
diff --git a/chromeos/disks/mock_disk_mount_manager.h b/chromeos/disks/mock_disk_mount_manager.h
index bb27744..25778a6 100644
--- a/chromeos/disks/mock_disk_mount_manager.h
+++ b/chromeos/disks/mock_disk_mount_manager.h
@@ -74,8 +74,10 @@
   // Sets up default results for mock methods.
   void SetupDefaultReplies();
 
-  // Creates a fake disk entry for the mounted device. This function is
-  // primarily for StorageMonitorTest.
+  // Creates a fake disk entry for the mounted device.
+  void CreateDiskEntryForMountDevice(std::unique_ptr<Disk> disk);
+
+  // Creates a fake disk entry for the mounted device.
   void CreateDiskEntryForMountDevice(
       const DiskMountManager::MountPointInfo& mount_info,
       const std::string& device_id,
diff --git a/chromeos/network/network_connection_handler_impl.cc b/chromeos/network/network_connection_handler_impl.cc
index e7648d0..c6171cf 100644
--- a/chromeos/network/network_connection_handler_impl.cc
+++ b/chromeos/network/network_connection_handler_impl.cc
@@ -14,6 +14,7 @@
 #include "base/time/time.h"
 #include "chromeos/dbus/shill/shill_manager_client.h"
 #include "chromeos/dbus/shill/shill_service_client.h"
+#include "chromeos/login/login_state/login_state.h"
 #include "chromeos/network/client_cert_resolver.h"
 #include "chromeos/network/client_cert_util.h"
 #include "chromeos/network/device_state.h"
@@ -36,6 +37,12 @@
 
 namespace {
 
+// If connection to a network that may require a client certificate is requested
+// when client certificates are not loaded yet, wait this long until
+// certificates have been loaded.
+constexpr base::TimeDelta kMaxCertLoadTimeSeconds =
+    base::TimeDelta::FromSeconds(15);
+
 bool IsAuthenticationError(const std::string& error) {
   return (error == shill::kErrorBadWEPKey ||
           error == shill::kErrorPppAuthFailed ||
@@ -169,7 +176,6 @@
     : network_cert_loader_(nullptr),
       network_state_handler_(nullptr),
       configuration_handler_(nullptr),
-      logged_in_(false),
       certificates_loaded_(false) {}
 
 NetworkConnectionHandlerImpl::~NetworkConnectionHandlerImpl() {
@@ -177,17 +183,12 @@
     network_state_handler_->RemoveObserver(this, FROM_HERE);
   if (network_cert_loader_)
     network_cert_loader_->RemoveObserver(this);
-  if (LoginState::IsInitialized())
-    LoginState::Get()->RemoveObserver(this);
 }
 
 void NetworkConnectionHandlerImpl::Init(
     NetworkStateHandler* network_state_handler,
     NetworkConfigurationHandler* network_configuration_handler,
     ManagedNetworkConfigurationHandler* managed_network_configuration_handler) {
-  if (LoginState::IsInitialized())
-    LoginState::Get()->AddObserver(this);
-
   if (NetworkCertLoader::IsInitialized()) {
     network_cert_loader_ = NetworkCertLoader::Get();
     network_cert_loader_->AddObserver(this);
@@ -210,18 +211,6 @@
 
   // After this point, the NetworkConnectionHandlerImpl is fully initialized
   // (all handler references set, observers registered, ...).
-
-  if (LoginState::IsInitialized())
-    LoggedInStateChanged();
-}
-
-void NetworkConnectionHandlerImpl::LoggedInStateChanged() {
-  LoginState* login_state = LoginState::Get();
-  if (logged_in_ || !login_state->IsUserLoggedIn())
-    return;
-
-  logged_in_ = true;
-  logged_in_time_ = base::TimeTicks::Now();
 }
 
 void NetworkConnectionHandlerImpl::OnCertificatesLoaded() {
@@ -561,13 +550,6 @@
     NET_LOG(DEBUG) << "Client cert type for: " << NetworkPathId(service_path)
                    << ": " << client_cert_type;
 
-    // User must be logged in to connect to a network requiring a certificate.
-    if (!logged_in_ || !network_cert_loader_) {
-      NET_LOG(ERROR) << "User not logged in for: "
-                     << NetworkPathId(service_path);
-      ErrorCallbackForPendingRequest(service_path, kErrorCertificateRequired);
-      return;
-    }
     // If certificates have not been loaded yet, queue the connect request.
     if (!certificates_loaded_) {
       NET_LOG(EVENT) << "Certificates not loaded for: "
@@ -650,16 +632,6 @@
     return;
   }
 
-  const int kMaxCertLoadTimeSeconds = 15;
-  base::TimeDelta dtime = base::TimeTicks::Now() - logged_in_time_;
-  if (dtime > base::TimeDelta::FromSeconds(kMaxCertLoadTimeSeconds)) {
-    NET_LOG(ERROR) << "Certificate load timeout: "
-                   << NetworkPathId(service_path);
-    InvokeConnectErrorCallback(service_path, std::move(request->error_callback),
-                               kErrorCertLoadTimeout);
-    return;
-  }
-
   NET_LOG(EVENT) << "Connect Request Queued: " << NetworkPathId(service_path);
   queued_connect_.reset(new ConnectRequest(request->mode, service_path,
                                            request->profile_path,
@@ -674,7 +646,7 @@
       FROM_HERE,
       base::BindOnce(&NetworkConnectionHandlerImpl::CheckCertificatesLoaded,
                      AsWeakPtr()),
-      base::TimeDelta::FromSeconds(kMaxCertLoadTimeSeconds) - dtime);
+      kMaxCertLoadTimeSeconds);
 }
 
 // Called after a delay to check whether certificates loaded. If they did not
diff --git a/chromeos/network/network_connection_handler_impl.h b/chromeos/network/network_connection_handler_impl.h
index 5d04cbf3..4a5eeaa 100644
--- a/chromeos/network/network_connection_handler_impl.h
+++ b/chromeos/network/network_connection_handler_impl.h
@@ -7,7 +7,6 @@
 
 #include "base/component_export.h"
 #include "chromeos/dbus/dbus_method_call_status.h"
-#include "chromeos/login/login_state/login_state.h"
 #include "chromeos/network/network_cert_loader.h"
 #include "chromeos/network/network_connection_handler.h"
 #include "chromeos/network/network_state_handler_observer.h"
@@ -17,7 +16,6 @@
 // Implementation of NetworkConnectionHandler.
 class COMPONENT_EXPORT(CHROMEOS_NETWORK) NetworkConnectionHandlerImpl
     : public NetworkConnectionHandler,
-      public LoginState::Observer,
       public NetworkCertLoader::Observer,
       public NetworkStateHandlerObserver,
       public base::SupportsWeakPtr<NetworkConnectionHandlerImpl> {
@@ -40,9 +38,6 @@
   void NetworkListChanged() override;
   void NetworkPropertiesUpdated(const NetworkState* network) override;
 
-  // LoginState::Observer
-  void LoggedInStateChanged() override;
-
   // NetworkCertLoader::Observer
   void OnCertificatesLoaded() override;
 
@@ -148,9 +143,7 @@
   std::unique_ptr<ConnectRequest> queued_connect_;
 
   // Track certificate loading state.
-  bool logged_in_;
   bool certificates_loaded_;
-  base::TimeTicks logged_in_time_;
 
   DISALLOW_COPY_AND_ASSIGN(NetworkConnectionHandlerImpl);
 };
diff --git a/chromeos/network/network_connection_handler_impl_unittest.cc b/chromeos/network/network_connection_handler_impl_unittest.cc
index 797e8cf..9f11e841 100644
--- a/chromeos/network/network_connection_handler_impl_unittest.cc
+++ b/chromeos/network/network_connection_handler_impl_unittest.cc
@@ -501,9 +501,8 @@
   EXPECT_EQ(kSuccessResult, GetResultAndReset());
 }
 
-// Disabled, see http://crbug.com/396729.
 TEST_F(NetworkConnectionHandlerImplTest,
-       DISABLED_ConnectWithCertificateRequestedBeforeCertsAreLoaded) {
+       ConnectWithCertificateRequestedBeforeCertsAreLoaded) {
   scoped_refptr<net::X509Certificate> cert = ImportTestClientCert();
   ASSERT_TRUE(cert.get());
 
diff --git a/components/autofill/core/browser/autofill_handler.cc b/components/autofill/core/browser/autofill_handler.cc
index 183277e..c715d0d12 100644
--- a/components/autofill/core/browser/autofill_handler.cc
+++ b/components/autofill/core/browser/autofill_handler.cc
@@ -432,7 +432,52 @@
 
 void AutofillHandler::OnLoadedServerPredictions(
     std::string response,
-    const std::vector<FormSignature>& queried_form_signatures) {}
+    const std::vector<FormSignature>& queried_form_signatures) {
+  // Get the current valid FormStructures represented by
+  // |queried_form_signatures|.
+  std::vector<FormStructure*> queried_forms;
+  queried_forms.reserve(queried_form_signatures.size());
+  for (const auto& form_signature : queried_form_signatures) {
+    FindCachedFormsBySignature(form_signature, &queried_forms);
+  }
+
+  // Each form signature in |queried_form_signatures| is supposed to be unique,
+  // and therefore appear only once. This ensures that
+  // FindCachedFormsBySignature() produces an output without duplicates in the
+  // forms.
+  // TODO(crbug/1064709): |queried_forms| could be a set data structure; their
+  // order should be irrelevant.
+  DCHECK_EQ(queried_forms.size(),
+            std::set<FormStructure*>(queried_forms.begin(), queried_forms.end())
+                .size());
+
+  // If there are no current forms corresponding to the queried signatures, drop
+  // the query response.
+  if (queried_forms.empty())
+    return;
+
+  // Parse and store the server predictions.
+  FormStructure::ParseApiQueryResponse(std::move(response), queried_forms,
+                                       queried_form_signatures,
+                                       form_interactions_ukm_logger());
+
+  // Will log quality metrics for each FormStructure based on the presence of
+  // autocomplete attributes, if available.
+  for (FormStructure* cur_form : queried_forms) {
+    cur_form->LogQualityMetricsBasedOnAutocomplete(
+        form_interactions_ukm_logger());
+  }
+
+  // Send field type predictions to the renderer so that it can possibly
+  // annotate forms with the predicted types or add console warnings.
+  driver()->SendAutofillTypePredictionsToRenderer(queried_forms);
+
+  LogAutofillTypePredictionsAvailable(log_manager_, queried_forms);
+
+  // Forward form structures to the password generation manager to detect
+  // account creation forms.
+  driver()->PropagateAutofillPredictions(queried_forms);
+}
 
 void AutofillHandler::OnServerRequestError(
     FormSignature form_signature,
diff --git a/components/autofill/core/browser/autofill_handler.h b/components/autofill/core/browser/autofill_handler.h
index be55b48..1abb9fa 100644
--- a/components/autofill/core/browser/autofill_handler.h
+++ b/components/autofill/core/browser/autofill_handler.h
@@ -176,6 +176,14 @@
   FormStructure* ParseFormForTest(const FormData& form) {
     return ParseForm(form, nullptr);
   }
+
+  // A public wrapper that calls |OnLoadedServerPredictions| for testing
+  // purposes only.
+  void OnLoadedServerPredictionsForTest(
+      std::string response,
+      const std::vector<FormSignature>& queried_form_signatures) {
+    OnLoadedServerPredictions(response, queried_form_signatures);
+  }
 #endif  // UNIT_TEST
 
  protected:
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc
index 248fb1e..3446e002 100644
--- a/components/autofill/core/browser/autofill_manager.cc
+++ b/components/autofill/core/browser/autofill_manager.cc
@@ -1388,55 +1388,6 @@
     TriggerRefill(form);
 }
 
-void AutofillManager::OnLoadedServerPredictions(
-    std::string response,
-    const std::vector<FormSignature>& queried_form_signatures) {
-  // Get the current valid FormStructures represented by
-  // |queried_form_signatures|.
-  std::vector<FormStructure*> queried_forms;
-  queried_forms.reserve(queried_form_signatures.size());
-  for (const auto& form_signature : queried_form_signatures) {
-    FindCachedFormsBySignature(form_signature, &queried_forms);
-  }
-
-  // Each form signature in |queried_form_signatures| is supposed to be unique,
-  // and therefore appear only once. This ensures that
-  // FindCachedFormsBySignature() produces an output without duplicates in the
-  // forms.
-  // TODO(crbug/1064709): |queried_forms| could be a set data structure; their
-  // order should be irrelevant.
-  DCHECK_EQ(queried_forms.size(),
-            std::set<FormStructure*>(queried_forms.begin(), queried_forms.end())
-                .size());
-
-  // If there are no current forms corresponding to the queried signatures, drop
-  // the query response.
-  if (queried_forms.empty())
-    return;
-
-  // Parse and store the server predictions.
-  FormStructure::ParseApiQueryResponse(std::move(response), queried_forms,
-                                       queried_form_signatures,
-                                       form_interactions_ukm_logger());
-
-  // Will log quality metrics for each FormStructure based on the presence of
-  // autocomplete attributes, if available.
-  for (FormStructure* cur_form : queried_forms) {
-    cur_form->LogQualityMetricsBasedOnAutocomplete(
-        form_interactions_ukm_logger());
-  }
-
-  // Send field type predictions to the renderer so that it can possibly
-  // annotate forms with the predicted types or add console warnings.
-  driver()->SendAutofillTypePredictionsToRenderer(queried_forms);
-
-  LogAutofillTypePredictionsAvailable(log_manager_, queried_forms);
-
-  // Forward form structures to the password generation manager to detect
-  // account creation forms.
-  driver()->PropagateAutofillPredictions(queried_forms);
-}
-
 void AutofillManager::OnCreditCardFetched(bool did_succeed,
                                           const CreditCard* credit_card,
                                           const base::string16& cvc) {
diff --git a/components/autofill/core/browser/autofill_manager.h b/components/autofill/core/browser/autofill_manager.h
index 8d4f461..a0ca353 100644
--- a/components/autofill/core/browser/autofill_manager.h
+++ b/components/autofill/core/browser/autofill_manager.h
@@ -47,7 +47,6 @@
 namespace autofill {
 
 class AutofillDataModel;
-class AutofillDownloadManager;
 class AutofillExternalDelegate;
 class AutofillField;
 class AutofillClient;
@@ -270,14 +269,6 @@
                                          app_locale, submitted_form);
   }
 
-  // A public wrapper that calls |OnLoadedServerPredictions| for testing
-  // purposes only.
-  void OnLoadedServerPredictionsForTest(
-      std::string response,
-      const std::vector<FormSignature>& queried_form_signatures) {
-    OnLoadedServerPredictions(response, queried_form_signatures);
-  }
-
   // A public wrapper that calls |MakeFrontendID| for testing purposes only.
   int MakeFrontendIDForTest(const std::string& cc_backend_id,
                             const std::string& profile_backend_id) const {
@@ -424,11 +415,6 @@
     SuppressReason suppress_reason = SuppressReason::kNotSuppressed;
   };
 
-  // AutofillDownloadManager::Observer:
-  void OnLoadedServerPredictions(
-      std::string response,
-      const std::vector<FormSignature>& queried_form_signatures) override;
-
   // CreditCardAccessManager::Accessor
   void OnCreditCardFetched(
       bool did_succeed,
diff --git a/components/autofill/core/browser/payments/credit_card_cvc_authenticator.cc b/components/autofill/core/browser/payments/credit_card_cvc_authenticator.cc
index c5ce8b4..1f3916f 100644
--- a/components/autofill/core/browser/payments/credit_card_cvc_authenticator.cc
+++ b/components/autofill/core/browser/payments/credit_card_cvc_authenticator.cc
@@ -4,6 +4,8 @@
 
 #include "components/autofill/core/browser/payments/credit_card_cvc_authenticator.h"
 
+#include <memory>
+
 #include "base/strings/string16.h"
 #include "build/build_config.h"
 #include "components/autofill/core/browser/autofill_client.h"
@@ -28,11 +30,13 @@
     PersonalDataManager* personal_data_manager,
     const base::TimeTicks& form_parsed_timestamp) {
   requester_ = requester;
-  if (!card)
-    return OnFullCardRequestFailed();
-  full_card_request_.reset(new payments::FullCardRequest(
+  if (!card) {
+    return OnFullCardRequestFailed(
+        payments::FullCardRequest::FailureType::GENERIC_FAILURE);
+  }
+  full_card_request_ = std::make_unique<payments::FullCardRequest>(
       client_, client_->GetPaymentsClient(), personal_data_manager,
-      form_parsed_timestamp));
+      form_parsed_timestamp);
   full_card_request_->GetFullCard(*card, AutofillClient::UNMASK_FOR_AUTOFILL,
                                   weak_ptr_factory_.GetWeakPtr(),
                                   weak_ptr_factory_.GetWeakPtr());
@@ -54,7 +58,8 @@
           .with_card_authorization_token(response.card_authorization_token));
 }
 
-void CreditCardCVCAuthenticator::OnFullCardRequestFailed() {
+void CreditCardCVCAuthenticator::OnFullCardRequestFailed(
+    payments::FullCardRequest::FailureType failure_type) {
   requester_->OnCVCAuthenticationComplete(
       CVCAuthenticationResponse().with_did_succeed(false));
 }
diff --git a/components/autofill/core/browser/payments/credit_card_cvc_authenticator.h b/components/autofill/core/browser/payments/credit_card_cvc_authenticator.h
index fee486e..20fe78c 100644
--- a/components/autofill/core/browser/payments/credit_card_cvc_authenticator.h
+++ b/components/autofill/core/browser/payments/credit_card_cvc_authenticator.h
@@ -95,7 +95,8 @@
       const payments::FullCardRequest& full_card_request,
       const CreditCard& card,
       const base::string16& cvc) override;
-  void OnFullCardRequestFailed() override;
+  void OnFullCardRequestFailed(
+      payments::FullCardRequest::FailureType failure_type) override;
 
   // payments::FullCardRequest::UIDelegate
   void ShowUnmaskPrompt(const CreditCard& card,
diff --git a/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc b/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc
index d7b17fdd..62cea32b 100644
--- a/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc
+++ b/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc
@@ -520,7 +520,8 @@
   requester_->OnFIDOAuthenticationComplete(/*did_succeed=*/true, &card, cvc);
 }
 
-void CreditCardFIDOAuthenticator::OnFullCardRequestFailed() {
+void CreditCardFIDOAuthenticator::OnFullCardRequestFailed(
+    payments::FullCardRequest::FailureType failure_type) {
   DCHECK_EQ(AUTHENTICATION_FLOW, current_flow_);
   current_flow_ = NONE_FLOW;
   requester_->OnFIDOAuthenticationComplete(/*did_succeed=*/false);
diff --git a/components/autofill/core/browser/payments/credit_card_fido_authenticator.h b/components/autofill/core/browser/payments/credit_card_fido_authenticator.h
index 93b1135..c857d84 100644
--- a/components/autofill/core/browser/payments/credit_card_fido_authenticator.h
+++ b/components/autofill/core/browser/payments/credit_card_fido_authenticator.h
@@ -194,7 +194,8 @@
       const payments::FullCardRequest& full_card_request,
       const CreditCard& card,
       const base::string16& cvc) override;
-  void OnFullCardRequestFailed() override;
+  void OnFullCardRequestFailed(
+      payments::FullCardRequest::FailureType failure_type) override;
 
   // Converts |request_options| from JSON to mojom pointer.
   PublicKeyCredentialRequestOptionsPtr ParseRequestOptions(
diff --git a/components/autofill/core/browser/payments/full_card_request.cc b/components/autofill/core/browser/payments/full_card_request.cc
index a09cde2f..16acda8 100644
--- a/components/autofill/core/browser/payments/full_card_request.cc
+++ b/components/autofill/core/browser/payments/full_card_request.cc
@@ -82,7 +82,7 @@
   // |result_delegate_| is already set, then immediately reject the new request
   // through the method parameter |result_delegate_|.
   if (result_delegate_) {
-    result_delegate_->OnFullCardRequestFailed();
+    result_delegate_->OnFullCardRequestFailed(FailureType::GENERIC_FAILURE);
     return;
   }
 
@@ -160,7 +160,7 @@
 
 void FullCardRequest::OnUnmaskPromptClosed() {
   if (result_delegate_)
-    result_delegate_->OnFullCardRequestFailed();
+    result_delegate_->OnFullCardRequestFailed(FailureType::PROMPT_CLOSED);
 
   Reset();
 }
@@ -216,10 +216,15 @@
 
     // Neither PERMANENT_FAILURE nor NETWORK_ERROR allow retry.
     case AutofillClient::PERMANENT_FAILURE:
-    // Intentional fall through.
+      if (result_delegate_) {
+        result_delegate_->OnFullCardRequestFailed(
+            FailureType::VERIFICATION_DECLINED);
+      }
+      Reset();
+      break;
     case AutofillClient::NETWORK_ERROR: {
       if (result_delegate_)
-        result_delegate_->OnFullCardRequestFailed();
+        result_delegate_->OnFullCardRequestFailed(FailureType::GENERIC_FAILURE);
       Reset();
       break;
     }
diff --git a/components/autofill/core/browser/payments/full_card_request.h b/components/autofill/core/browser/payments/full_card_request.h
index 20c9408..b09fbb8 100644
--- a/components/autofill/core/browser/payments/full_card_request.h
+++ b/components/autofill/core/browser/payments/full_card_request.h
@@ -32,6 +32,24 @@
 // TODO(crbug/1061638): Refactor to use base::WaitableEvent where possible.
 class FullCardRequest final : public CardUnmaskDelegate {
  public:
+  // The type of failure.
+  enum FailureType {
+    // The user closed the prompt. The following scenarios are possible:
+    // 1) The user declined to enter their CVC and closed the prompt.
+    // 2) The user provided their CVC, got auth declined and then closed the
+    //    prompt without attempting a second time.
+    // 3) The user provided their CVC and closed the prompt before waiting for
+    //    the result.
+    PROMPT_CLOSED,
+
+    // The card could not be looked up due to card auth declined or failed.
+    VERIFICATION_DECLINED,
+
+    // The request failed for technical reasons, such as a closing page or lack
+    // of network connection.
+    GENERIC_FAILURE
+  };
+
   // The interface for receiving the full card details.
   class ResultDelegate {
    public:
@@ -40,7 +58,7 @@
         const payments::FullCardRequest& full_card_request,
         const CreditCard& card,
         const base::string16& cvc) = 0;
-    virtual void OnFullCardRequestFailed() = 0;
+    virtual void OnFullCardRequestFailed(FailureType failure_type) = 0;
   };
 
   // The delegate responsible for displaying the unmask prompt UI.
diff --git a/components/autofill/core/browser/payments/full_card_request_unittest.cc b/components/autofill/core/browser/payments/full_card_request_unittest.cc
index 909a356..8602bf04 100644
--- a/components/autofill/core/browser/payments/full_card_request_unittest.cc
+++ b/components/autofill/core/browser/payments/full_card_request_unittest.cc
@@ -42,7 +42,8 @@
                void(const payments::FullCardRequest&,
                     const CreditCard&,
                     const base::string16&));
-  MOCK_METHOD0(OnFullCardRequestFailed, void());
+  MOCK_METHOD1(OnFullCardRequestFailed,
+               void(payments::FullCardRequest::FailureType));
 };
 
 // The delegate responsible for displaying the unmask prompt UI.
@@ -402,7 +403,9 @@
 
 // Only one request at a time should be allowed.
 TEST_F(FullCardRequestTest, OneRequestAtATime) {
-  EXPECT_CALL(*result_delegate(), OnFullCardRequestFailed());
+  EXPECT_CALL(
+      *result_delegate(),
+      OnFullCardRequestFailed(FullCardRequest::FailureType::GENERIC_FAILURE));
   EXPECT_CALL(*ui_delegate(), ShowUnmaskPrompt(_, _, _));
   EXPECT_CALL(*ui_delegate(), OnUnmaskVerificationResult(_)).Times(0);
 
@@ -418,7 +421,7 @@
 
 // After the first request completes, it's OK to start the second request.
 TEST_F(FullCardRequestTest, SecondRequestOkAfterFirstFinished) {
-  EXPECT_CALL(*result_delegate(), OnFullCardRequestFailed()).Times(0);
+  EXPECT_CALL(*result_delegate(), OnFullCardRequestFailed(_)).Times(0);
   EXPECT_CALL(
       *result_delegate(),
       OnFullCardRequestSucceeded(testing::Ref(*request()),
@@ -450,7 +453,9 @@
 // If the user cancels the CVC prompt,
 // FullCardRequest::Delegate::OnFullCardRequestFailed() should be invoked.
 TEST_F(FullCardRequestTest, ClosePromptWithoutUserInput) {
-  EXPECT_CALL(*result_delegate(), OnFullCardRequestFailed());
+  EXPECT_CALL(
+      *result_delegate(),
+      OnFullCardRequestFailed(FullCardRequest::FailureType::PROMPT_CLOSED));
   EXPECT_CALL(*ui_delegate(), ShowUnmaskPrompt(_, _, _));
   EXPECT_CALL(*ui_delegate(), OnUnmaskVerificationResult(_)).Times(0);
 
@@ -464,7 +469,9 @@
 // If the server provides an empty PAN with PERMANENT_FAILURE error,
 // FullCardRequest::Delegate::OnFullCardRequestFailed() should be invoked.
 TEST_F(FullCardRequestTest, PermanentFailure) {
-  EXPECT_CALL(*result_delegate(), OnFullCardRequestFailed());
+  EXPECT_CALL(*result_delegate(),
+              OnFullCardRequestFailed(
+                  FullCardRequest::FailureType::VERIFICATION_DECLINED));
   EXPECT_CALL(*ui_delegate(), ShowUnmaskPrompt(_, _, _));
   EXPECT_CALL(*ui_delegate(),
               OnUnmaskVerificationResult(AutofillClient::PERMANENT_FAILURE));
@@ -483,7 +490,9 @@
 // If the server provides an empty PAN with NETWORK_ERROR error,
 // FullCardRequest::Delegate::OnFullCardRequestFailed() should be invoked.
 TEST_F(FullCardRequestTest, NetworkError) {
-  EXPECT_CALL(*result_delegate(), OnFullCardRequestFailed());
+  EXPECT_CALL(
+      *result_delegate(),
+      OnFullCardRequestFailed(FullCardRequest::FailureType::GENERIC_FAILURE));
   EXPECT_CALL(*ui_delegate(), ShowUnmaskPrompt(_, _, _));
   EXPECT_CALL(*ui_delegate(),
               OnUnmaskVerificationResult(AutofillClient::NETWORK_ERROR));
@@ -502,7 +511,9 @@
 // If the server provides an empty PAN with TRY_AGAIN_FAILURE, the user can
 // manually cancel out of the dialog.
 TEST_F(FullCardRequestTest, TryAgainFailureGiveUp) {
-  EXPECT_CALL(*result_delegate(), OnFullCardRequestFailed());
+  EXPECT_CALL(
+      *result_delegate(),
+      OnFullCardRequestFailed(FullCardRequest::FailureType::PROMPT_CLOSED));
   EXPECT_CALL(*ui_delegate(), ShowUnmaskPrompt(_, _, _));
   EXPECT_CALL(*ui_delegate(),
               OnUnmaskVerificationResult(AutofillClient::TRY_AGAIN_FAILURE));
@@ -521,7 +532,7 @@
 // If the server provides an empty PAN with TRY_AGAIN_FAILURE, the user can
 // correct their mistake and resubmit.
 TEST_F(FullCardRequestTest, TryAgainFailureRetry) {
-  EXPECT_CALL(*result_delegate(), OnFullCardRequestFailed()).Times(0);
+  EXPECT_CALL(*result_delegate(), OnFullCardRequestFailed(_)).Times(0);
   EXPECT_CALL(*result_delegate(),
               OnFullCardRequestSucceeded(
                   testing::Ref(*request()),
diff --git a/components/autofill_assistant/browser/actions/action_delegate_util.cc b/components/autofill_assistant/browser/actions/action_delegate_util.cc
index b5c8868..4f8283d 100644
--- a/components/autofill_assistant/browser/actions/action_delegate_util.cc
+++ b/components/autofill_assistant/browser/actions/action_delegate_util.cc
@@ -47,11 +47,12 @@
     return;
   }
 
-  std::move((*perform_actions)[action_index])
-      .Run(element,
-           base::BindOnce(&PerformActionsSequentially,
-                          std::move(perform_actions), std::move(status_details),
-                          action_index + 1, element, std::move(done)));
+  ElementActionCallback action = std::move((*perform_actions)[action_index]);
+  std::move(action).Run(
+      element,
+      base::BindOnce(&PerformActionsSequentially, std::move(perform_actions),
+                     std::move(status_details), action_index + 1, element,
+                     std::move(done)));
 }
 
 void OnFindElement(ElementActionCallback perform,
@@ -64,8 +65,9 @@
     return;
   }
 
+  const ElementFinder::Result* element_result_ptr = element_result.get();
   std::move(perform).Run(
-      *element_result,
+      *element_result_ptr,
       base::BindOnce(&RetainElementAndExecuteCallback,
                      std::move(element_result), std::move(done)));
 }
diff --git a/components/autofill_assistant/browser/actions/action_delegate_util.h b/components/autofill_assistant/browser/actions/action_delegate_util.h
index 1c1a916..681979f 100644
--- a/components/autofill_assistant/browser/actions/action_delegate_util.h
+++ b/components/autofill_assistant/browser/actions/action_delegate_util.h
@@ -72,8 +72,9 @@
     return;
   }
 
+  const ElementFinder::Result* element_result_ptr = element_result.get();
   std::move(perform_and_get)
-      .Run(*element_result,
+      .Run(*element_result_ptr,
            base::BindOnce(&RetainElementAndExecuteGetCallback<R>,
                           std::move(element_result), std::move(done)));
 }
diff --git a/components/autofill_assistant/browser/actions/collect_user_data_action.cc b/components/autofill_assistant/browser/actions/collect_user_data_action.cc
index 87910d2..34f34bd 100644
--- a/components/autofill_assistant/browser/actions/collect_user_data_action.cc
+++ b/components/autofill_assistant/browser/actions/collect_user_data_action.cc
@@ -797,9 +797,10 @@
        collect_user_data.login_details().login_options()) {
     switch (login_option.type_case()) {
       case LoginDetailsProto::LoginOptionProto::kCustom: {
+        const std::string identifier = base::NumberToString(
+            collect_user_data_options_->login_choices.size());
         LoginChoice choice = {
-            base::NumberToString(
-                collect_user_data_options_->login_choices.size()),
+            identifier,
             login_option.custom().label(),
             login_option.sublabel(),
             login_option.has_sublabel_accessibility_hint()
@@ -819,7 +820,7 @@
         collect_user_data_options_->login_choices.emplace_back(
             std::move(choice));
         login_details_map_.emplace(
-            choice.identifier,
+            identifier,
             std::make_unique<LoginDetails>(
                 login_option.choose_automatically_if_no_stored_login(),
                 login_option.payload()));
diff --git a/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler.cc b/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler.cc
index df37384..24596df 100644
--- a/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler.cc
+++ b/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler.cc
@@ -284,8 +284,9 @@
     return;
   }
 
+  const ElementFinder::Result* element_result_ptr = element_result.get();
   action_delegate_->GetWebController()->GetElementTag(
-      *element_result,
+      *element_result_ptr,
       base::BindOnce(
           &RequiredFieldsFallbackHandler::OnGetFallbackFieldElementTag,
           weak_ptr_factory_.GetWeakPtr(), value, required_fields_index,
@@ -326,17 +327,20 @@
         break;
     }
 
+    const ElementFinder::Result* element_ptr = element.get();
     action_delegate_->SelectOption(
-        re2, /* case_sensitive= */ false, option_comparison_attribute, *element,
+        re2, /* case_sensitive= */ false, option_comparison_attribute,
+        *element_ptr,
         base::BindOnce(&RequiredFieldsFallbackHandler::OnSetFallbackFieldValue,
                        weak_ptr_factory_.GetWeakPtr(), required_fields_index,
                        std::move(element)));
     return;
   }
 
+  const ElementFinder::Result* element_ptr = element.get();
   action_delegate_util::PerformSetFieldValue(
       action_delegate_, value, required_field.fill_strategy,
-      required_field.delay_in_millisecond, *element,
+      required_field.delay_in_millisecond, *element_ptr,
       base::BindOnce(&RequiredFieldsFallbackHandler::OnSetFallbackFieldValue,
                      weak_ptr_factory_.GetWeakPtr(), required_fields_index,
                      std::move(element)));
diff --git a/components/autofill_assistant/browser/controller_unittest.cc b/components/autofill_assistant/browser/controller_unittest.cc
index 390ade9..4c0b419 100644
--- a/components/autofill_assistant/browser/controller_unittest.cc
+++ b/components/autofill_assistant/browser/controller_unittest.cc
@@ -1563,6 +1563,13 @@
   // AA.
   SimulateNavigateToUrl(GURL("http://other-example.com/"));
   EXPECT_EQ(AutofillAssistantState::BROWSE, controller_->GetState());
+
+  // Navigation to different domain should stop AA.
+  EXPECT_CALL(
+      mock_client_,
+      RecordDropOut(Metrics::DropOutReason::DOMAIN_CHANGE_DURING_BROWSE_MODE));
+  SimulateNavigateToUrl(GURL("http://unknown.com"));
+  EXPECT_EQ(AutofillAssistantState::STOPPED, controller_->GetState());
 }
 
 TEST_F(ControllerTest, BrowseStateWithDomainAllowlistCleanup) {
diff --git a/components/autofill_assistant/browser/self_delete_full_card_requester.cc b/components/autofill_assistant/browser/self_delete_full_card_requester.cc
index b2b6573..f0848b3 100644
--- a/components/autofill_assistant/browser/self_delete_full_card_requester.cc
+++ b/components/autofill_assistant/browser/self_delete_full_card_requester.cc
@@ -18,6 +18,8 @@
 
 namespace autofill_assistant {
 
+using autofill::payments::FullCardRequest;
+
 SelfDeleteFullCardRequester::SelfDeleteFullCardRequester() {}
 
 void SelfDeleteFullCardRequester::GetFullCard(
@@ -30,14 +32,14 @@
   autofill::ContentAutofillDriverFactory* factory =
       autofill::ContentAutofillDriverFactory::FromWebContents(web_contents);
   if (!factory) {
-    OnFullCardRequestFailed();
+    OnFullCardRequestFailed(FullCardRequest::FailureType::GENERIC_FAILURE);
     return;
   }
 
   autofill::ContentAutofillDriver* driver =
       factory->DriverForFrame(web_contents->GetMainFrame());
   if (!driver) {
-    OnFullCardRequestFailed();
+    OnFullCardRequestFailed(FullCardRequest::FailureType::GENERIC_FAILURE);
     return;
   }
 
@@ -50,14 +52,15 @@
 SelfDeleteFullCardRequester::~SelfDeleteFullCardRequester() = default;
 
 void SelfDeleteFullCardRequester::OnFullCardRequestSucceeded(
-    const autofill::payments::FullCardRequest& /* full_card_request */,
+    const FullCardRequest& /* full_card_request */,
     const autofill::CreditCard& card,
     const base::string16& cvc) {
   std::move(callback_).Run(std::make_unique<autofill::CreditCard>(card), cvc);
   delete this;
 }
 
-void SelfDeleteFullCardRequester::OnFullCardRequestFailed() {
+void SelfDeleteFullCardRequester::OnFullCardRequestFailed(
+    FullCardRequest::FailureType failure_type) {
   // Failed might because of cancel, so return nullptr to notice caller.
   //
   // TODO(crbug.com/806868): Split the fail notification so that "cancel" and
diff --git a/components/autofill_assistant/browser/self_delete_full_card_requester.h b/components/autofill_assistant/browser/self_delete_full_card_requester.h
index 4c01bcf..9861b96 100644
--- a/components/autofill_assistant/browser/self_delete_full_card_requester.h
+++ b/components/autofill_assistant/browser/self_delete_full_card_requester.h
@@ -27,14 +27,14 @@
  private:
   ~SelfDeleteFullCardRequester() override;
 
-  // payments::FullCardRequest::ResultDelegate:
+  // autofill::payments::FullCardRequest::ResultDelegate:
   void OnFullCardRequestSucceeded(
       const autofill::payments::FullCardRequest& /* full_card_request */,
       const autofill::CreditCard& card,
       const base::string16& cvc) override;
-
-  // payments::FullCardRequest::ResultDelegate:
-  void OnFullCardRequestFailed() override;
+  void OnFullCardRequestFailed(
+      autofill::payments::FullCardRequest::FailureType /* failure_type */)
+      override;
 
   ActionDelegate::GetFullCardCallback callback_;
 
diff --git a/components/autofill_assistant/browser/service.proto b/components/autofill_assistant/browser/service.proto
index 9e85239..84771bb0 100644
--- a/components/autofill_assistant/browser/service.proto
+++ b/components/autofill_assistant/browser/service.proto
@@ -281,8 +281,12 @@
     // Show the UI if it's not shown yet. Setting this to false is useful for
     // scripts started by direct actions.
     optional bool needs_ui = 15 [default = true];
+
+    reserved 1, 2, 6, 7, 10, 11, 16 to 18;
   }
   optional PresentationProto presentation = 2;
+
+  reserved 3;
 }
 
 enum ScriptStatusProto {
diff --git a/components/drive/drive_uploader.cc b/components/drive/drive_uploader.cc
index 97ba2d32..25bd00c8 100644
--- a/components/drive/drive_uploader.cc
+++ b/components/drive/drive_uploader.cc
@@ -20,7 +20,6 @@
 #include "services/device/public/mojom/wake_lock.mojom.h"
 
 using google_apis::CancelCallbackOnce;
-using google_apis::CancelCallbackRepeating;
 using google_apis::DRIVE_CANCELLED;
 using google_apis::DRIVE_NO_SPACE;
 using google_apis::DriveApiErrorCode;
@@ -156,7 +155,7 @@
   // once Cancel() is called. DriveUploader will check this field before after
   // an async task other than HTTP requests and cancels the subsequent requests
   // if this is flagged to true.
-  CancelCallbackRepeating cancel_callback;
+  CancelCallbackOnce cancel_callback;
   bool cancelled;
 
  private:
diff --git a/components/drive/drive_uploader_unittest.cc b/components/drive/drive_uploader_unittest.cc
index f25fdef..6e819c9 100644
--- a/components/drive/drive_uploader_unittest.cc
+++ b/components/drive/drive_uploader_unittest.cc
@@ -24,8 +24,7 @@
 #include "google_apis/drive/test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using google_apis::CancelCallback;
-using google_apis::CancelCallbackRepeating;
+using google_apis::CancelCallbackOnce;
 using google_apis::DRIVE_NO_CONNECTION;
 using google_apis::DRIVE_OTHER_ERROR;
 using google_apis::DriveApiErrorCode;
@@ -57,7 +56,7 @@
 const int64_t kUploadChunkSize = 1024 * 1024 * 1024;
 const char kTestETag[] = "test_etag";
 
-CancelCallbackRepeating SendMultipartUploadResult(
+CancelCallbackOnce SendMultipartUploadResult(
     DriveApiErrorCode response_code,
     int64_t content_length,
     google_apis::FileResourceCallback callback,
@@ -79,7 +78,7 @@
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(std::move(callback), response_code, std::move(entry)));
-  return CancelCallbackRepeating();
+  return CancelCallbackOnce();
 }
 
 // Mock DriveService that verifies if the uploaded content matches the preset
@@ -110,7 +109,7 @@
  private:
   // DriveServiceInterface overrides.
   // Handles a request for obtaining an upload location URL.
-  CancelCallback InitiateUploadNewFile(
+  CancelCallbackOnce InitiateUploadNewFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& parent_resource_id,
@@ -127,10 +126,10 @@
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), HTTP_SUCCESS,
                                   GURL(kTestUploadNewFileURL)));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
-  CancelCallback InitiateUploadExistingFile(
+  CancelCallbackOnce InitiateUploadExistingFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& resource_id,
@@ -144,7 +143,7 @@
       base::ThreadTaskRunnerHandle::Get()->PostTask(
           FROM_HERE,
           base::BindOnce(std::move(callback), HTTP_PRECONDITION, GURL()));
-      return CancelCallback();
+      return CancelCallbackOnce();
     }
 
     // Calls back the upload URL for subsequent ResumeUpload requests.
@@ -152,18 +151,18 @@
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), HTTP_SUCCESS,
                                   GURL(kTestUploadExistingFileURL)));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   // Handles a request for uploading a chunk of bytes.
-  CancelCallback ResumeUpload(const GURL& upload_location,
-                              int64_t start_position,
-                              int64_t end_position,
-                              int64_t content_length,
-                              const std::string& content_type,
-                              const base::FilePath& local_file_path,
-                              UploadRangeCallback callback,
-                              ProgressCallback progress_callback) override {
+  CancelCallbackOnce ResumeUpload(const GURL& upload_location,
+                                  int64_t start_position,
+                                  int64_t end_position,
+                                  int64_t content_length,
+                                  const std::string& content_type,
+                                  const base::FilePath& local_file_path,
+                                  UploadRangeCallback callback,
+                                  ProgressCallback progress_callback) override {
     // The upload range should start from the current first unreceived byte.
     EXPECT_EQ(received_bytes_, start_position);
     EXPECT_EQ(expected_upload_file_, local_file_path);
@@ -195,20 +194,20 @@
     }
 
     SendUploadRangeResponse(upload_location, std::move(callback));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   // Handles a request to fetch the current upload status.
-  CancelCallback GetUploadStatus(const GURL& upload_location,
-                                 int64_t content_length,
-                                 UploadRangeCallback callback) override {
+  CancelCallbackOnce GetUploadStatus(const GURL& upload_location,
+                                     int64_t content_length,
+                                     UploadRangeCallback callback) override {
     EXPECT_EQ(expected_content_length_, content_length);
     // The upload URL returned by InitiateUpload() must be used.
     EXPECT_TRUE(upload_location == kTestUploadNewFileURL ||
                 upload_location == kTestUploadExistingFileURL);
 
     SendUploadRangeResponse(upload_location, std::move(callback));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   // Runs |callback| with the current upload status.
@@ -235,7 +234,7 @@
         base::BindOnce(std::move(callback), response, std::move(entry)));
   }
 
-  CancelCallbackRepeating MultipartUploadNewFile(
+  CancelCallbackOnce MultipartUploadNewFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& parent_resource_id,
@@ -256,7 +255,7 @@
                                      std::move(callback), progress_callback);
   }
 
-  CancelCallbackRepeating MultipartUploadExistingFile(
+  CancelCallbackOnce MultipartUploadExistingFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& resource_id,
@@ -273,7 +272,7 @@
       base::ThreadTaskRunnerHandle::Get()->PostTask(
           FROM_HERE,
           base::BindOnce(std::move(callback), HTTP_PRECONDITION, nullptr));
-      return CancelCallbackRepeating();
+      return CancelCallbackOnce();
     }
 
     received_bytes_ = content_length;
@@ -292,7 +291,7 @@
 // Mock DriveService that returns a failure at InitiateUpload().
 class MockDriveServiceNoConnectionAtInitiate : public DummyDriveService {
   // Returns error.
-  CancelCallback InitiateUploadNewFile(
+  CancelCallbackOnce InitiateUploadNewFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& parent_resource_id,
@@ -302,10 +301,10 @@
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::BindOnce(std::move(callback), DRIVE_NO_CONNECTION, GURL()));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
-  CancelCallback InitiateUploadExistingFile(
+  CancelCallbackOnce InitiateUploadExistingFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& resource_id,
@@ -314,23 +313,23 @@
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::BindOnce(std::move(callback), DRIVE_NO_CONNECTION, GURL()));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   // Should not be used.
-  CancelCallback ResumeUpload(const GURL& upload_url,
-                              int64_t start_position,
-                              int64_t end_position,
-                              int64_t content_length,
-                              const std::string& content_type,
-                              const base::FilePath& local_file_path,
-                              UploadRangeCallback callback,
-                              ProgressCallback progress_callback) override {
+  CancelCallbackOnce ResumeUpload(const GURL& upload_url,
+                                  int64_t start_position,
+                                  int64_t end_position,
+                                  int64_t content_length,
+                                  const std::string& content_type,
+                                  const base::FilePath& local_file_path,
+                                  UploadRangeCallback callback,
+                                  ProgressCallback progress_callback) override {
     NOTREACHED();
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
-  CancelCallbackRepeating MultipartUploadNewFile(
+  CancelCallbackOnce MultipartUploadNewFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& parent_resource_id,
@@ -342,10 +341,10 @@
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::BindOnce(std::move(callback), DRIVE_NO_CONNECTION, nullptr));
-    return CancelCallbackRepeating();
+    return CancelCallbackOnce();
   }
 
-  CancelCallbackRepeating MultipartUploadExistingFile(
+  CancelCallbackOnce MultipartUploadExistingFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& resource_id,
@@ -356,14 +355,14 @@
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::BindOnce(std::move(callback), DRIVE_NO_CONNECTION, nullptr));
-    return CancelCallbackRepeating();
+    return CancelCallbackOnce();
   }
 };
 
 // Mock DriveService that returns a failure at ResumeUpload().
 class MockDriveServiceNoConnectionAtResume : public DummyDriveService {
   // Succeeds and returns an upload location URL.
-  CancelCallback InitiateUploadNewFile(
+  CancelCallbackOnce InitiateUploadNewFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& parent_resource_id,
@@ -373,10 +372,10 @@
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), HTTP_SUCCESS,
                                   GURL(kTestUploadNewFileURL)));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
-  CancelCallback InitiateUploadExistingFile(
+  CancelCallbackOnce InitiateUploadExistingFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& resource_id,
@@ -385,39 +384,39 @@
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), HTTP_SUCCESS,
                                   GURL(kTestUploadExistingFileURL)));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   // Returns error.
-  CancelCallback ResumeUpload(const GURL& upload_url,
-                              int64_t start_position,
-                              int64_t end_position,
-                              int64_t content_length,
-                              const std::string& content_type,
-                              const base::FilePath& local_file_path,
-                              UploadRangeCallback callback,
-                              ProgressCallback progress_callback) override {
+  CancelCallbackOnce ResumeUpload(const GURL& upload_url,
+                                  int64_t start_position,
+                                  int64_t end_position,
+                                  int64_t content_length,
+                                  const std::string& content_type,
+                                  const base::FilePath& local_file_path,
+                                  UploadRangeCallback callback,
+                                  ProgressCallback progress_callback) override {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::BindOnce(std::move(callback),
                        UploadRangeResponse(DRIVE_NO_CONNECTION, -1, -1),
                        nullptr));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 };
 
 // Mock DriveService that returns a failure at GetUploadStatus().
 class MockDriveServiceNoConnectionAtGetUploadStatus : public DummyDriveService {
   // Returns error.
-  CancelCallback GetUploadStatus(const GURL& upload_url,
-                                 int64_t content_length,
-                                 UploadRangeCallback callback) override {
+  CancelCallbackOnce GetUploadStatus(const GURL& upload_url,
+                                     int64_t content_length,
+                                     UploadRangeCallback callback) override {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::BindOnce(std::move(callback),
                        UploadRangeResponse(DRIVE_NO_CONNECTION, -1, -1),
                        nullptr));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 };
 
@@ -805,7 +804,7 @@
         MockDriveServiceForBatchProcessing* service)
         : service(service) {}
 
-    CancelCallback MultipartUploadNewFile(
+    CancelCallbackOnce MultipartUploadNewFile(
         const std::string& content_type,
         int64_t content_length,
         const std::string& parent_resource_id,
@@ -824,10 +823,10 @@
       info.callback = std::move(callback);
       info.progress_callback = progress_callback;
       service->files.push_back(std::move(info));
-      return CancelCallback();
+      return CancelCallbackOnce();
     }
 
-    CancelCallback MultipartUploadExistingFile(
+    CancelCallbackOnce MultipartUploadExistingFile(
         const std::string& content_type,
         int64_t content_length,
         const std::string& resource_id,
@@ -844,7 +843,7 @@
       info.callback = std::move(callback);
       info.progress_callback = progress_callback;
       service->files.push_back(std::move(info));
-      return CancelCallback();
+      return CancelCallbackOnce();
     }
 
     void Commit() override {
diff --git a/components/drive/service/drive_api_service.cc b/components/drive/service/drive_api_service.cc
index 9f46cc3..e41f255 100644
--- a/components/drive/service/drive_api_service.cc
+++ b/components/drive/service/drive_api_service.cc
@@ -24,7 +24,6 @@
 
 using google_apis::AboutResourceCallback;
 using google_apis::AuthStatusCallback;
-using google_apis::CancelCallback;
 using google_apis::CancelCallbackOnce;
 using google_apis::CancelCallbackRepeating;
 using google_apis::ChangeList;
@@ -147,12 +146,11 @@
     const base::WeakPtr<google_apis::drive::BatchUploadRequest>& batch_request,
     base::SequencedTaskRunner* task_runner,
     const google_apis::DriveApiUrlGenerator& url_generator,
-    const google_apis::CancelCallback& cancel_callback)
+    const google_apis::CancelCallbackRepeating& cancel_callback)
     : batch_request_(batch_request),
       task_runner_(task_runner),
       url_generator_(url_generator),
-      cancel_callback_(cancel_callback) {
-}
+      cancel_callback_(cancel_callback) {}
 
 BatchRequestConfigurator::~BatchRequestConfigurator() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -161,7 +159,7 @@
     cancel_callback_.Run();
 }
 
-google_apis::CancelCallbackRepeating
+google_apis::CancelCallbackOnce
 BatchRequestConfigurator::MultipartUploadNewFile(
     const std::string& content_type,
     int64_t content_length,
@@ -189,7 +187,7 @@
   return cancel_callback_;
 }
 
-google_apis::CancelCallback
+google_apis::CancelCallbackOnce
 BatchRequestConfigurator::MultipartUploadExistingFile(
     const std::string& content_type,
     int64_t content_length,
@@ -389,8 +387,8 @@
   return sender_->StartRequestWithAuthRetry(std::move(request));
 }
 
-CancelCallback DriveAPIService::GetChangeList(int64_t start_changestamp,
-                                              ChangeListCallback callback) {
+CancelCallbackOnce DriveAPIService::GetChangeList(int64_t start_changestamp,
+                                                  ChangeListCallback callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(callback);
 
@@ -403,7 +401,7 @@
   return sender_->StartRequestWithAuthRetry(std::move(request));
 }
 
-CancelCallback DriveAPIService::GetChangeListByToken(
+CancelCallbackOnce DriveAPIService::GetChangeListByToken(
     const std::string& team_drive_id,
     const std::string& start_page_token,
     ChangeListCallback callback) {
@@ -435,7 +433,7 @@
   return sender_->StartRequestWithAuthRetry(std::move(request));
 }
 
-CancelCallback DriveAPIService::GetRemainingTeamDriveList(
+CancelCallbackOnce DriveAPIService::GetRemainingTeamDriveList(
     const std::string& page_token,
     TeamDriveListCallback callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
@@ -466,8 +464,9 @@
   return sender_->StartRequestWithAuthRetry(std::move(request));
 }
 
-CancelCallback DriveAPIService::GetFileResource(const std::string& resource_id,
-                                                FileResourceCallback callback) {
+CancelCallbackOnce DriveAPIService::GetFileResource(
+    const std::string& resource_id,
+    FileResourceCallback callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
@@ -478,7 +477,7 @@
   return sender_->StartRequestWithAuthRetry(std::move(request));
 }
 
-CancelCallback DriveAPIService::GetAboutResource(
+CancelCallbackOnce DriveAPIService::GetAboutResource(
     AboutResourceCallback callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(callback);
@@ -489,7 +488,7 @@
   return sender_->StartRequestWithAuthRetry(std::move(request));
 }
 
-CancelCallback DriveAPIService::GetStartPageToken(
+CancelCallbackOnce DriveAPIService::GetStartPageToken(
     const std::string& team_drive_id,
     StartPageTokenCallback callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
@@ -519,9 +518,10 @@
           progress_callback));
 }
 
-CancelCallback DriveAPIService::DeleteResource(const std::string& resource_id,
-                                               const std::string& etag,
-                                               EntryActionCallback callback) {
+CancelCallbackOnce DriveAPIService::DeleteResource(
+    const std::string& resource_id,
+    const std::string& etag,
+    EntryActionCallback callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(callback);
 
@@ -533,8 +533,9 @@
   return sender_->StartRequestWithAuthRetry(std::move(request));
 }
 
-CancelCallback DriveAPIService::TrashResource(const std::string& resource_id,
-                                              EntryActionCallback callback) {
+CancelCallbackOnce DriveAPIService::TrashResource(
+    const std::string& resource_id,
+    EntryActionCallback callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(callback);
 
@@ -569,7 +570,7 @@
   return sender_->StartRequestWithAuthRetry(std::move(request));
 }
 
-CancelCallback DriveAPIService::CopyResource(
+CancelCallbackOnce DriveAPIService::CopyResource(
     const std::string& resource_id,
     const std::string& parent_resource_id,
     const std::string& new_title,
@@ -589,7 +590,7 @@
   return sender_->StartRequestWithAuthRetry(std::move(request));
 }
 
-CancelCallback DriveAPIService::UpdateResource(
+CancelCallbackOnce DriveAPIService::UpdateResource(
     const std::string& resource_id,
     const std::string& parent_resource_id,
     const std::string& new_title,
@@ -623,7 +624,7 @@
   return sender_->StartRequestWithAuthRetry(std::move(request));
 }
 
-CancelCallback DriveAPIService::AddResourceToDirectory(
+CancelCallbackOnce DriveAPIService::AddResourceToDirectory(
     const std::string& parent_resource_id,
     const std::string& resource_id,
     EntryActionCallback callback) {
@@ -653,7 +654,7 @@
   return sender_->StartRequestWithAuthRetry(std::move(request));
 }
 
-CancelCallback DriveAPIService::InitiateUploadNewFile(
+CancelCallbackOnce DriveAPIService::InitiateUploadNewFile(
     const std::string& content_type,
     int64_t content_length,
     const std::string& parent_resource_id,
@@ -673,7 +674,7 @@
   return sender_->StartRequestWithAuthRetry(std::move(request));
 }
 
-CancelCallback DriveAPIService::InitiateUploadExistingFile(
+CancelCallbackOnce DriveAPIService::InitiateUploadExistingFile(
     const std::string& content_type,
     int64_t content_length,
     const std::string& resource_id,
@@ -694,7 +695,7 @@
   return sender_->StartRequestWithAuthRetry(std::move(request));
 }
 
-CancelCallback DriveAPIService::ResumeUpload(
+CancelCallbackOnce DriveAPIService::ResumeUpload(
     const GURL& upload_url,
     int64_t start_position,
     int64_t end_position,
@@ -713,9 +714,10 @@
           progress_callback));
 }
 
-CancelCallback DriveAPIService::GetUploadStatus(const GURL& upload_url,
-                                                int64_t content_length,
-                                                UploadRangeCallback callback) {
+CancelCallbackOnce DriveAPIService::GetUploadStatus(
+    const GURL& upload_url,
+    int64_t content_length,
+    UploadRangeCallback callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
@@ -724,7 +726,7 @@
           sender_.get(), upload_url, content_length, std::move(callback)));
 }
 
-CancelCallbackRepeating DriveAPIService::MultipartUploadNewFile(
+CancelCallbackOnce DriveAPIService::MultipartUploadNewFile(
     const std::string& content_type,
     int64_t content_length,
     const std::string& parent_resource_id,
@@ -747,7 +749,7 @@
               progress_callback)));
 }
 
-CancelCallbackRepeating DriveAPIService::MultipartUploadExistingFile(
+CancelCallbackOnce DriveAPIService::MultipartUploadExistingFile(
     const std::string& content_type,
     int64_t content_length,
     const std::string& resource_id,
@@ -770,7 +772,7 @@
               std::move(callback), progress_callback)));
 }
 
-google_apis::CancelCallback DriveAPIService::AddPermission(
+google_apis::CancelCallbackOnce DriveAPIService::AddPermission(
     const std::string& resource_id,
     const std::string& email,
     google_apis::drive::PermissionRole role,
@@ -845,7 +847,7 @@
   // RequestSender before the request is committed because the request has a
   // reference to RequestSender and we should ensure to delete the request when
   // the sender is deleted. Resolve the circulating dependency and fix it.
-  const google_apis::CancelCallback callback =
+  const google_apis::CancelCallbackRepeating callback =
       sender_->StartRequestWithAuthRetry(std::move(request));
   return std::make_unique<BatchRequestConfigurator>(
       weak_ref, sender_->blocking_task_runner(), url_generator_, callback);
diff --git a/components/drive/service/drive_api_service.h b/components/drive/service/drive_api_service.h
index 9cd57e3..e12b8d31 100644
--- a/components/drive/service/drive_api_service.h
+++ b/components/drive/service/drive_api_service.h
@@ -55,11 +55,11 @@
           batch_request,
       base::SequencedTaskRunner* task_runner,
       const google_apis::DriveApiUrlGenerator& url_generator,
-      const google_apis::CancelCallback& cancel_callback);
+      const google_apis::CancelCallbackRepeating& cancel_callback);
   ~BatchRequestConfigurator() override;
 
   // BatchRequestConfiguratorInterface overrides.
-  google_apis::CancelCallbackRepeating MultipartUploadNewFile(
+  google_apis::CancelCallbackOnce MultipartUploadNewFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& parent_resource_id,
@@ -68,7 +68,7 @@
       const UploadNewFileOptions& options,
       google_apis::FileResourceCallback callback,
       google_apis::ProgressCallback progress_callback) override;
-  google_apis::CancelCallbackRepeating MultipartUploadExistingFile(
+  google_apis::CancelCallbackOnce MultipartUploadExistingFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& resource_id,
@@ -144,14 +144,14 @@
       const std::string& title,
       const std::string& directory_resource_id,
       google_apis::FileListCallback callback) override;
-  google_apis::CancelCallback GetChangeList(
+  google_apis::CancelCallbackOnce GetChangeList(
       int64_t start_changestamp,
       google_apis::ChangeListCallback callback) override;
-  google_apis::CancelCallback GetChangeListByToken(
+  google_apis::CancelCallbackOnce GetChangeListByToken(
       const std::string& team_drive_id,
       const std::string& start_page_token,
       google_apis::ChangeListCallback callback) override;
-  google_apis::CancelCallback GetRemainingTeamDriveList(
+  google_apis::CancelCallbackOnce GetRemainingTeamDriveList(
       const std::string& page_token,
       google_apis::TeamDriveListCallback callback) override;
   google_apis::CancelCallbackOnce GetRemainingChangeList(
@@ -160,19 +160,19 @@
   google_apis::CancelCallbackOnce GetRemainingFileList(
       const GURL& next_link,
       google_apis::FileListCallback callback) override;
-  google_apis::CancelCallback GetFileResource(
+  google_apis::CancelCallbackOnce GetFileResource(
       const std::string& resource_id,
       google_apis::FileResourceCallback callback) override;
-  google_apis::CancelCallback GetAboutResource(
+  google_apis::CancelCallbackOnce GetAboutResource(
       google_apis::AboutResourceCallback callback) override;
-  google_apis::CancelCallback GetStartPageToken(
+  google_apis::CancelCallbackOnce GetStartPageToken(
       const std::string& team_drive_id,
       google_apis::StartPageTokenCallback callback) override;
-  google_apis::CancelCallback DeleteResource(
+  google_apis::CancelCallbackOnce DeleteResource(
       const std::string& resource_id,
       const std::string& etag,
       google_apis::EntryActionCallback callback) override;
-  google_apis::CancelCallback TrashResource(
+  google_apis::CancelCallbackOnce TrashResource(
       const std::string& resource_id,
       google_apis::EntryActionCallback callback) override;
   google_apis::CancelCallbackOnce DownloadFile(
@@ -181,13 +181,13 @@
       google_apis::DownloadActionCallback download_action_callback,
       const google_apis::GetContentCallback& get_content_callback,
       google_apis::ProgressCallback progress_callback) override;
-  google_apis::CancelCallback CopyResource(
+  google_apis::CancelCallbackOnce CopyResource(
       const std::string& resource_id,
       const std::string& parent_resource_id,
       const std::string& new_title,
       const base::Time& last_modified,
       google_apis::FileResourceCallback callback) override;
-  google_apis::CancelCallback UpdateResource(
+  google_apis::CancelCallbackOnce UpdateResource(
       const std::string& resource_id,
       const std::string& parent_resource_id,
       const std::string& new_title,
@@ -195,7 +195,7 @@
       const base::Time& last_viewed_by_me,
       const google_apis::drive::Properties& properties,
       google_apis::FileResourceCallback callback) override;
-  google_apis::CancelCallback AddResourceToDirectory(
+  google_apis::CancelCallbackOnce AddResourceToDirectory(
       const std::string& parent_resource_id,
       const std::string& resource_id,
       google_apis::EntryActionCallback callback) override;
@@ -208,20 +208,20 @@
       const std::string& directory_title,
       const AddNewDirectoryOptions& options,
       google_apis::FileResourceCallback callback) override;
-  google_apis::CancelCallback InitiateUploadNewFile(
+  google_apis::CancelCallbackOnce InitiateUploadNewFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& parent_resource_id,
       const std::string& title,
       const UploadNewFileOptions& options,
       google_apis::InitiateUploadCallback callback) override;
-  google_apis::CancelCallback InitiateUploadExistingFile(
+  google_apis::CancelCallbackOnce InitiateUploadExistingFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& resource_id,
       const UploadExistingFileOptions& options,
       google_apis::InitiateUploadCallback callback) override;
-  google_apis::CancelCallback ResumeUpload(
+  google_apis::CancelCallbackOnce ResumeUpload(
       const GURL& upload_url,
       int64_t start_position,
       int64_t end_position,
@@ -230,11 +230,11 @@
       const base::FilePath& local_file_path,
       google_apis::drive::UploadRangeCallback callback,
       google_apis::ProgressCallback progress_callback) override;
-  google_apis::CancelCallback GetUploadStatus(
+  google_apis::CancelCallbackOnce GetUploadStatus(
       const GURL& upload_url,
       int64_t content_length,
       google_apis::drive::UploadRangeCallback callback) override;
-  google_apis::CancelCallbackRepeating MultipartUploadNewFile(
+  google_apis::CancelCallbackOnce MultipartUploadNewFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& parent_resource_id,
@@ -243,7 +243,7 @@
       const drive::UploadNewFileOptions& options,
       google_apis::FileResourceCallback callback,
       google_apis::ProgressCallback progress_callback) override;
-  google_apis::CancelCallbackRepeating MultipartUploadExistingFile(
+  google_apis::CancelCallbackOnce MultipartUploadExistingFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& resource_id,
@@ -251,7 +251,7 @@
       const drive::UploadExistingFileOptions& options,
       google_apis::FileResourceCallback callback,
       google_apis::ProgressCallback progress_callback) override;
-  google_apis::CancelCallback AddPermission(
+  google_apis::CancelCallbackOnce AddPermission(
       const std::string& resource_id,
       const std::string& email,
       google_apis::drive::PermissionRole role,
diff --git a/components/drive/service/drive_api_service_unittest.cc b/components/drive/service/drive_api_service_unittest.cc
index 1492169..580c047 100644
--- a/components/drive/service/drive_api_service_unittest.cc
+++ b/components/drive/service/drive_api_service_unittest.cc
@@ -57,7 +57,7 @@
   sender.StartRequestWithAuthRetry(std::move(request));
   BatchRequestConfigurator configurator(
       request_ptr->GetWeakPtrAsBatchUploadRequest(), task_runner.get(),
-      url_generator, google_apis::CancelCallback());
+      url_generator, google_apis::CancelCallbackRepeating());
   static_cast<TestAuthService*>(sender.auth_service())->SendHttpError();
 
   {
diff --git a/components/drive/service/drive_service_interface.h b/components/drive/service/drive_service_interface.h
index 7e7feec9..0620ce2 100644
--- a/components/drive/service/drive_service_interface.h
+++ b/components/drive/service/drive_service_interface.h
@@ -118,7 +118,7 @@
   // for small files than using |InitiateUploadNewFile| and |ResumeUpload|.
   // |content_type| and |content_length| should be the ones of the file to be
   // uploaded.  |callback| must not be null. |progress_callback| may be null.
-  virtual google_apis::CancelCallbackRepeating MultipartUploadNewFile(
+  virtual google_apis::CancelCallbackOnce MultipartUploadNewFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& parent_resource_id,
@@ -132,7 +132,7 @@
   // for small files than using |InitiateUploadExistingFile| and |ResumeUpload|.
   // |content_type| and |content_length| should be the ones of the file to be
   // uploaded.  |callback| must not be null. |progress_callback| may be null.
-  virtual google_apis::CancelCallbackRepeating MultipartUploadExistingFile(
+  virtual google_apis::CancelCallbackOnce MultipartUploadExistingFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& resource_id,
@@ -266,7 +266,7 @@
   // GetRemainingChangeList.
   //
   // |callback| must not be null.
-  virtual google_apis::CancelCallback GetChangeList(
+  virtual google_apis::CancelCallbackOnce GetChangeList(
       int64_t start_changestamp,
       google_apis::ChangeListCallback callback) = 0;
 
@@ -279,7 +279,7 @@
   // GetRemainingChangeList.
   //
   // |callback| must not be null.
-  virtual google_apis::CancelCallback GetChangeListByToken(
+  virtual google_apis::CancelCallbackOnce GetChangeListByToken(
       const std::string& team_drive_id,
       const std::string& start_page_token,
       google_apis::ChangeListCallback callback) = 0;
@@ -299,7 +299,7 @@
   // method. |callback| will be called upon completion.
   //
   // |next_link| must not be empty. |callback| must not be null.
-  virtual google_apis::CancelCallback GetRemainingTeamDriveList(
+  virtual google_apis::CancelCallbackOnce GetRemainingTeamDriveList(
       const std::string& page_token,
       google_apis::TeamDriveListCallback callback) = 0;
 
@@ -317,14 +317,14 @@
   // |resource_id|.
   // Upon completion, invokes |callback| with results on the calling thread.
   // |callback| must not be null.
-  virtual google_apis::CancelCallback GetFileResource(
+  virtual google_apis::CancelCallbackOnce GetFileResource(
       const std::string& resource_id,
       google_apis::FileResourceCallback callback) = 0;
 
   // Gets the about resource information from the server.
   // Upon completion, invokes |callback| with results on the calling thread.
   // |callback| must not be null.
-  virtual google_apis::CancelCallback GetAboutResource(
+  virtual google_apis::CancelCallbackOnce GetAboutResource(
       google_apis::AboutResourceCallback callback) = 0;
 
   // Gets the start page token information from the server.
@@ -332,7 +332,7 @@
   // the users changelog.
   // Upon completion, invokes |callback| with results on the calling thread.
   // |callback| must not be null.
-  virtual google_apis::CancelCallback GetStartPageToken(
+  virtual google_apis::CancelCallbackOnce GetStartPageToken(
       const std::string& team_drive_id,
       google_apis::StartPageTokenCallback callback) = 0;
 
@@ -341,7 +341,7 @@
   // HTTP_PRECONDITION error.
   // Upon completion, invokes |callback| with results on the calling thread.
   // |callback| must not be null.
-  virtual google_apis::CancelCallback DeleteResource(
+  virtual google_apis::CancelCallbackOnce DeleteResource(
       const std::string& resource_id,
       const std::string& etag,
       google_apis::EntryActionCallback callback) = 0;
@@ -349,7 +349,7 @@
   // Trashes a resource identified by its |resource_id|.
   // Upon completion, invokes |callback| with results on the calling thread.
   // |callback| must not be null.
-  virtual google_apis::CancelCallback TrashResource(
+  virtual google_apis::CancelCallbackOnce TrashResource(
       const std::string& resource_id,
       google_apis::EntryActionCallback callback) = 0;
 
@@ -360,7 +360,7 @@
   // server will be set to the date.
   // Upon completion, invokes |callback| with results on the calling thread.
   // |callback| must not be null.
-  virtual google_apis::CancelCallback CopyResource(
+  virtual google_apis::CancelCallbackOnce CopyResource(
       const std::string& resource_id,
       const std::string& parent_resource_id,
       const std::string& new_title,
@@ -374,7 +374,7 @@
   // If |properties| are specified, then they will be set on |resource_id|.
   // Upon completion, invokes |callback| with results on the calling thread.
   // |callback| must not be null.
-  virtual google_apis::CancelCallback UpdateResource(
+  virtual google_apis::CancelCallbackOnce UpdateResource(
       const std::string& resource_id,
       const std::string& parent_resource_id,
       const std::string& new_title,
@@ -387,7 +387,7 @@
   // |resource_id| to a collection represented by the |parent_resource_id|.
   // Upon completion, invokes |callback| with results on the calling thread.
   // |callback| must not be null.
-  virtual google_apis::CancelCallback AddResourceToDirectory(
+  virtual google_apis::CancelCallbackOnce AddResourceToDirectory(
       const std::string& parent_resource_id,
       const std::string& resource_id,
       google_apis::EntryActionCallback callback) = 0;
@@ -437,7 +437,7 @@
   // |content_type| and |content_length| should be the ones of the file to be
   // uploaded.
   // |callback| must not be null.
-  virtual google_apis::CancelCallback InitiateUploadNewFile(
+  virtual google_apis::CancelCallbackOnce InitiateUploadNewFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& parent_resource_id,
@@ -449,7 +449,7 @@
   // |content_type| and |content_length| should be the ones of the file to be
   // uploaded.
   // |callback| must not be null.
-  virtual google_apis::CancelCallback InitiateUploadExistingFile(
+  virtual google_apis::CancelCallbackOnce InitiateUploadExistingFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& resource_id,
@@ -458,7 +458,7 @@
 
   // Resumes uploading of a document/file on the calling thread.
   // |callback| must not be null. |progress_callback| may be null.
-  virtual google_apis::CancelCallback ResumeUpload(
+  virtual google_apis::CancelCallbackOnce ResumeUpload(
       const GURL& upload_url,
       int64_t start_position,
       int64_t end_position,
@@ -472,14 +472,14 @@
   // |drive_file_path| and |content_length| should be set to the same value
   // which is used for ResumeUpload.
   // |callback| must not be null.
-  virtual google_apis::CancelCallback GetUploadStatus(
+  virtual google_apis::CancelCallbackOnce GetUploadStatus(
       const GURL& upload_url,
       int64_t content_length,
       google_apis::drive::UploadRangeCallback callback) = 0;
 
   // Authorizes the account |email| to access |resource_id| as a |role|.
   // |callback| must not be null.
-  virtual google_apis::CancelCallback AddPermission(
+  virtual google_apis::CancelCallbackOnce AddPermission(
       const std::string& resource_id,
       const std::string& email,
       google_apis::drive::PermissionRole role,
diff --git a/components/drive/service/dummy_drive_service.cc b/components/drive/service/dummy_drive_service.cc
index 18d7f4e..4ab390f 100644
--- a/components/drive/service/dummy_drive_service.cc
+++ b/components/drive/service/dummy_drive_service.cc
@@ -10,7 +10,6 @@
 
 using google_apis::AboutResourceCallback;
 using google_apis::AuthStatusCallback;
-using google_apis::CancelCallback;
 using google_apis::CancelCallbackOnce;
 using google_apis::ChangeListCallback;
 using google_apis::DownloadActionCallback;
@@ -72,7 +71,7 @@
 
 CancelCallbackOnce DummyDriveService::Search(const std::string& search_query,
                                              FileListCallback callback) {
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
 CancelCallbackOnce DummyDriveService::SearchByTitle(
@@ -82,16 +81,17 @@
   return CancelCallbackOnce();
 }
 
-CancelCallback DummyDriveService::GetChangeList(int64_t start_changestamp,
-                                                ChangeListCallback callback) {
-  return CancelCallback();
+CancelCallbackOnce DummyDriveService::GetChangeList(
+    int64_t start_changestamp,
+    ChangeListCallback callback) {
+  return CancelCallbackOnce();
 }
 
-CancelCallback DummyDriveService::GetChangeListByToken(
+CancelCallbackOnce DummyDriveService::GetChangeListByToken(
     const std::string& team_drive_id,
     const std::string& start_page_token,
     ChangeListCallback callback) {
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
 CancelCallbackOnce DummyDriveService::GetRemainingChangeList(
@@ -100,44 +100,46 @@
   return CancelCallbackOnce();
 }
 
-CancelCallback DummyDriveService::GetRemainingTeamDriveList(
+CancelCallbackOnce DummyDriveService::GetRemainingTeamDriveList(
     const std::string& page_token,
     TeamDriveListCallback callback) {
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
 CancelCallbackOnce DummyDriveService::GetRemainingFileList(
     const GURL& next_link,
     FileListCallback callback) {
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
-CancelCallback DummyDriveService::GetFileResource(
+CancelCallbackOnce DummyDriveService::GetFileResource(
     const std::string& resource_id,
     FileResourceCallback callback) {
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
-CancelCallback DummyDriveService::GetAboutResource(
+CancelCallbackOnce DummyDriveService::GetAboutResource(
     AboutResourceCallback callback) {
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
-CancelCallback DummyDriveService::GetStartPageToken(
+CancelCallbackOnce DummyDriveService::GetStartPageToken(
     const std::string& team_drive_id,
     google_apis::StartPageTokenCallback callback) {
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
-CancelCallback DummyDriveService::DeleteResource(const std::string& resource_id,
-                                                 const std::string& etag,
-                                                 EntryActionCallback callback) {
-  return CancelCallback();
+CancelCallbackOnce DummyDriveService::DeleteResource(
+    const std::string& resource_id,
+    const std::string& etag,
+    EntryActionCallback callback) {
+  return CancelCallbackOnce();
 }
 
-CancelCallback DummyDriveService::TrashResource(const std::string& resource_id,
-                                                EntryActionCallback callback) {
-  return CancelCallback();
+CancelCallbackOnce DummyDriveService::TrashResource(
+    const std::string& resource_id,
+    EntryActionCallback callback) {
+  return CancelCallbackOnce();
 }
 
 CancelCallbackOnce DummyDriveService::DownloadFile(
@@ -146,19 +148,19 @@
     DownloadActionCallback download_action_callback,
     const GetContentCallback& get_content_callback,
     ProgressCallback progress_callback) {
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
-CancelCallback DummyDriveService::CopyResource(
+CancelCallbackOnce DummyDriveService::CopyResource(
     const std::string& resource_id,
     const std::string& parent_resource_id,
     const std::string& new_title,
     const base::Time& last_modified,
     FileResourceCallback callback) {
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
-CancelCallback DummyDriveService::UpdateResource(
+CancelCallbackOnce DummyDriveService::UpdateResource(
     const std::string& resource_id,
     const std::string& parent_resource_id,
     const std::string& new_title,
@@ -166,21 +168,21 @@
     const base::Time& last_viewed_by_me,
     const google_apis::drive::Properties& properties,
     FileResourceCallback callback) {
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
-CancelCallback DummyDriveService::AddResourceToDirectory(
+CancelCallbackOnce DummyDriveService::AddResourceToDirectory(
     const std::string& parent_resource_id,
     const std::string& resource_id,
     EntryActionCallback callback) {
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
 CancelCallbackOnce DummyDriveService::RemoveResourceFromDirectory(
     const std::string& parent_resource_id,
     const std::string& resource_id,
     EntryActionCallback callback) {
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
 CancelCallbackOnce DummyDriveService::AddNewDirectory(
@@ -191,26 +193,26 @@
   return CancelCallbackOnce();
 }
 
-CancelCallback DummyDriveService::InitiateUploadNewFile(
+CancelCallbackOnce DummyDriveService::InitiateUploadNewFile(
     const std::string& content_type,
     int64_t content_length,
     const std::string& parent_resource_id,
     const std::string& title,
     const UploadNewFileOptions& options,
     InitiateUploadCallback callback) {
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
-CancelCallback DummyDriveService::InitiateUploadExistingFile(
+CancelCallbackOnce DummyDriveService::InitiateUploadExistingFile(
     const std::string& content_type,
     int64_t content_length,
     const std::string& resource_id,
     const UploadExistingFileOptions& options,
     InitiateUploadCallback callback) {
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
-CancelCallback DummyDriveService::ResumeUpload(
+CancelCallbackOnce DummyDriveService::ResumeUpload(
     const GURL& upload_url,
     int64_t start_position,
     int64_t end_position,
@@ -219,17 +221,17 @@
     const base::FilePath& local_file_path,
     UploadRangeCallback callback,
     ProgressCallback progress_callback) {
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
-CancelCallback DummyDriveService::GetUploadStatus(
+CancelCallbackOnce DummyDriveService::GetUploadStatus(
     const GURL& upload_url,
     int64_t content_length,
     UploadRangeCallback callback) {
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
-CancelCallback DummyDriveService::MultipartUploadNewFile(
+CancelCallbackOnce DummyDriveService::MultipartUploadNewFile(
     const std::string& content_type,
     int64_t content_length,
     const std::string& parent_resource_id,
@@ -238,10 +240,10 @@
     const UploadNewFileOptions& options,
     FileResourceCallback callback,
     ProgressCallback progress_callback) {
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
-CancelCallback DummyDriveService::MultipartUploadExistingFile(
+CancelCallbackOnce DummyDriveService::MultipartUploadExistingFile(
     const std::string& content_type,
     int64_t content_length,
     const std::string& resource_id,
@@ -249,15 +251,15 @@
     const UploadExistingFileOptions& options,
     FileResourceCallback callback,
     ProgressCallback progress_callback) {
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
-CancelCallback DummyDriveService::AddPermission(
+CancelCallbackOnce DummyDriveService::AddPermission(
     const std::string& resource_id,
     const std::string& email,
     google_apis::drive::PermissionRole role,
     EntryActionCallback callback) {
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 std::unique_ptr<BatchRequestConfiguratorInterface>
 DummyDriveService::StartBatchRequest() {
diff --git a/components/drive/service/dummy_drive_service.h b/components/drive/service/dummy_drive_service.h
index 42d80a7..744f28e 100644
--- a/components/drive/service/dummy_drive_service.h
+++ b/components/drive/service/dummy_drive_service.h
@@ -48,35 +48,35 @@
       const std::string& title,
       const std::string& directory_resource_id,
       google_apis::FileListCallback callback) override;
-  google_apis::CancelCallback GetChangeList(
+  google_apis::CancelCallbackOnce GetChangeList(
       int64_t start_changestamp,
       google_apis::ChangeListCallback callback) override;
-  google_apis::CancelCallback GetChangeListByToken(
+  google_apis::CancelCallbackOnce GetChangeListByToken(
       const std::string& team_drive_id,
       const std::string& start_page_token,
       google_apis::ChangeListCallback callback) override;
   google_apis::CancelCallbackOnce GetRemainingChangeList(
       const GURL& next_link,
       google_apis::ChangeListCallback callback) override;
-  google_apis::CancelCallback GetRemainingTeamDriveList(
+  google_apis::CancelCallbackOnce GetRemainingTeamDriveList(
       const std::string& page_token,
       google_apis::TeamDriveListCallback callback) override;
   google_apis::CancelCallbackOnce GetRemainingFileList(
       const GURL& next_link,
       google_apis::FileListCallback callback) override;
-  google_apis::CancelCallback GetFileResource(
+  google_apis::CancelCallbackOnce GetFileResource(
       const std::string& resource_id,
       google_apis::FileResourceCallback callback) override;
-  google_apis::CancelCallback GetAboutResource(
+  google_apis::CancelCallbackOnce GetAboutResource(
       google_apis::AboutResourceCallback callback) override;
-  google_apis::CancelCallback GetStartPageToken(
+  google_apis::CancelCallbackOnce GetStartPageToken(
       const std::string& team_drive_id,
       google_apis::StartPageTokenCallback callback) override;
-  google_apis::CancelCallback DeleteResource(
+  google_apis::CancelCallbackOnce DeleteResource(
       const std::string& resource_id,
       const std::string& etag,
       google_apis::EntryActionCallback callback) override;
-  google_apis::CancelCallback TrashResource(
+  google_apis::CancelCallbackOnce TrashResource(
       const std::string& resource_id,
       google_apis::EntryActionCallback callback) override;
   google_apis::CancelCallbackOnce DownloadFile(
@@ -85,13 +85,13 @@
       google_apis::DownloadActionCallback download_action_callback,
       const google_apis::GetContentCallback& get_content_callback,
       google_apis::ProgressCallback progress_callback) override;
-  google_apis::CancelCallback CopyResource(
+  google_apis::CancelCallbackOnce CopyResource(
       const std::string& resource_id,
       const std::string& parent_resource_id,
       const std::string& new_title,
       const base::Time& last_modified,
       google_apis::FileResourceCallback callback) override;
-  google_apis::CancelCallback UpdateResource(
+  google_apis::CancelCallbackOnce UpdateResource(
       const std::string& resource_id,
       const std::string& parent_resource_id,
       const std::string& new_title,
@@ -99,7 +99,7 @@
       const base::Time& last_viewed_by_me,
       const google_apis::drive::Properties& properties,
       google_apis::FileResourceCallback callback) override;
-  google_apis::CancelCallback AddResourceToDirectory(
+  google_apis::CancelCallbackOnce AddResourceToDirectory(
       const std::string& parent_resource_id,
       const std::string& resource_id,
       google_apis::EntryActionCallback callback) override;
@@ -112,20 +112,20 @@
       const std::string& directory_title,
       const AddNewDirectoryOptions& options,
       google_apis::FileResourceCallback callback) override;
-  google_apis::CancelCallback InitiateUploadNewFile(
+  google_apis::CancelCallbackOnce InitiateUploadNewFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& parent_resource_id,
       const std::string& title,
       const UploadNewFileOptions& options,
       google_apis::InitiateUploadCallback callback) override;
-  google_apis::CancelCallback InitiateUploadExistingFile(
+  google_apis::CancelCallbackOnce InitiateUploadExistingFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& resource_id,
       const UploadExistingFileOptions& options,
       google_apis::InitiateUploadCallback callback) override;
-  google_apis::CancelCallback ResumeUpload(
+  google_apis::CancelCallbackOnce ResumeUpload(
       const GURL& upload_url,
       int64_t start_position,
       int64_t end_position,
@@ -134,11 +134,11 @@
       const base::FilePath& local_file_path,
       google_apis::drive::UploadRangeCallback callback,
       google_apis::ProgressCallback progress_callback) override;
-  google_apis::CancelCallback GetUploadStatus(
+  google_apis::CancelCallbackOnce GetUploadStatus(
       const GURL& upload_url,
       int64_t content_length,
       google_apis::drive::UploadRangeCallback callback) override;
-  google_apis::CancelCallback MultipartUploadNewFile(
+  google_apis::CancelCallbackOnce MultipartUploadNewFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& parent_resource_id,
@@ -147,7 +147,7 @@
       const UploadNewFileOptions& options,
       google_apis::FileResourceCallback callback,
       google_apis::ProgressCallback progress_callback) override;
-  google_apis::CancelCallback MultipartUploadExistingFile(
+  google_apis::CancelCallbackOnce MultipartUploadExistingFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& resource_id,
@@ -155,7 +155,7 @@
       const UploadExistingFileOptions& options,
       google_apis::FileResourceCallback callback,
       google_apis::ProgressCallback progress_callback) override;
-  google_apis::CancelCallback AddPermission(
+  google_apis::CancelCallbackOnce AddPermission(
       const std::string& resource_id,
       const std::string& email,
       google_apis::drive::PermissionRole role,
diff --git a/components/drive/service/fake_drive_service.cc b/components/drive/service/fake_drive_service.cc
index 0293f527..0c83660 100644
--- a/components/drive/service/fake_drive_service.cc
+++ b/components/drive/service/fake_drive_service.cc
@@ -38,7 +38,6 @@
 using google_apis::AboutResource;
 using google_apis::AboutResourceCallback;
 using google_apis::AuthStatusCallback;
-using google_apis::CancelCallback;
 using google_apis::CancelCallbackOnce;
 using google_apis::ChangeList;
 using google_apis::ChangeListCallback;
@@ -409,7 +408,7 @@
 
   if (never_return_all_file_list_) {
     ++blocked_file_list_load_count_;
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   GetChangeListInternal(
@@ -453,7 +452,7 @@
       0,              // start offset
       default_max_results_, nullptr,
       base::BindOnce(&FileListCallbackAdapter, std::move(callback)));
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
 CancelCallbackOnce FakeDriveService::SearchByTitle(
@@ -475,8 +474,9 @@
   return CancelCallbackOnce();
 }
 
-CancelCallback FakeDriveService::GetChangeList(int64_t start_changestamp,
-                                               ChangeListCallback callback) {
+CancelCallbackOnce FakeDriveService::GetChangeList(
+    int64_t start_changestamp,
+    ChangeListCallback callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(callback);
 
@@ -487,10 +487,10 @@
                         0,              // start offset
                         default_max_results_, &change_list_load_count_,
                         std::move(callback));
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
-CancelCallback FakeDriveService::GetChangeListByToken(
+CancelCallbackOnce FakeDriveService::GetChangeListByToken(
     const std::string& team_drive_id,
     const std::string& start_page_token,
     ChangeListCallback callback) {
@@ -508,7 +508,7 @@
                         default_max_results_, &change_list_load_count_,
                         std::move(callback));
 
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
 CancelCallbackOnce FakeDriveService::GetRemainingChangeList(
@@ -559,7 +559,7 @@
   return CancelCallbackOnce();
 }
 
-CancelCallback FakeDriveService::GetRemainingTeamDriveList(
+CancelCallbackOnce FakeDriveService::GetRemainingTeamDriveList(
     const std::string& page_token,
     TeamDriveListCallback callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
@@ -572,7 +572,7 @@
   DCHECK(parse_success);
   GetTeamDriveListInternal(start_offset, default_max_results_, nullptr,
                            std::move(callback));
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
 CancelCallbackOnce FakeDriveService::GetRemainingFileList(
@@ -585,7 +585,7 @@
       next_link, base::BindOnce(&FileListCallbackAdapter, std::move(callback)));
 }
 
-CancelCallback FakeDriveService::GetFileResource(
+CancelCallbackOnce FakeDriveService::GetFileResource(
     const std::string& resource_id,
     FileResourceCallback callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
@@ -595,7 +595,7 @@
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), DRIVE_NO_CONNECTION,
                                   std::unique_ptr<FileResource>()));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   EntryInfo* entry = FindEntryByResourceId(resource_id);
@@ -604,16 +604,16 @@
         FROM_HERE, base::BindOnce(std::move(callback), HTTP_SUCCESS,
                                   std::make_unique<FileResource>(
                                       *entry->change_resource.file())));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(std::move(callback), HTTP_NOT_FOUND,
                                 std::unique_ptr<FileResource>()));
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
-CancelCallback FakeDriveService::GetAboutResource(
+CancelCallbackOnce FakeDriveService::GetAboutResource(
     AboutResourceCallback callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(callback);
@@ -623,7 +623,7 @@
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), DRIVE_NO_CONNECTION,
                                   std::move(null)));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   ++about_resource_load_count_;
@@ -632,10 +632,10 @@
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(std::move(callback), HTTP_SUCCESS,
                                 std::move(about_resource)));
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
-CancelCallback FakeDriveService::GetStartPageToken(
+CancelCallbackOnce FakeDriveService::GetStartPageToken(
     const std::string& team_drive_id,
     google_apis::StartPageTokenCallback callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
@@ -646,7 +646,7 @@
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), DRIVE_NO_CONNECTION,
                                   std::move(null)));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   std::unique_ptr<StartPageToken> start_page_token;
@@ -661,46 +661,47 @@
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(std::move(callback), HTTP_SUCCESS,
                                 std::move(start_page_token)));
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
-CancelCallback FakeDriveService::DeleteResource(const std::string& resource_id,
-                                                const std::string& etag,
-                                                EntryActionCallback callback) {
+CancelCallbackOnce FakeDriveService::DeleteResource(
+    const std::string& resource_id,
+    const std::string& etag,
+    EntryActionCallback callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(callback);
 
   if (offline_) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), DRIVE_NO_CONNECTION));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   EntryInfo* entry = FindEntryByResourceId(resource_id);
   if (!entry) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), HTTP_NOT_FOUND));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   ChangeResource* change = &entry->change_resource;
   if (change->is_deleted()) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), HTTP_NOT_FOUND));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   const FileResource* file = change->file();
   if (!etag.empty() && etag != file->etag()) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), HTTP_PRECONDITION));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   if (entry->user_permission != google_apis::drive::PERMISSION_ROLE_OWNER) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), HTTP_FORBIDDEN));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   change->set_deleted(true);
@@ -711,25 +712,26 @@
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(&FakeDriveService::NotifyObservers,
                                 weak_ptr_factory_.GetWeakPtr()));
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
-CancelCallback FakeDriveService::TrashResource(const std::string& resource_id,
-                                               EntryActionCallback callback) {
+CancelCallbackOnce FakeDriveService::TrashResource(
+    const std::string& resource_id,
+    EntryActionCallback callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(callback);
 
   if (offline_) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), DRIVE_NO_CONNECTION));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   EntryInfo* entry = FindEntryByResourceId(resource_id);
   if (!entry) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), HTTP_NOT_FOUND));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   ChangeResource* change = &entry->change_resource;
@@ -737,13 +739,13 @@
   if (change->is_deleted() || file->labels().is_trashed()) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), HTTP_NOT_FOUND));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   if (entry->user_permission != google_apis::drive::PERMISSION_ROLE_OWNER) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), HTTP_FORBIDDEN));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   file->mutable_labels()->set_trashed(true);
@@ -753,7 +755,7 @@
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(&FakeDriveService::NotifyObservers,
                                 weak_ptr_factory_.GetWeakPtr()));
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
 CancelCallbackOnce FakeDriveService::DownloadFile(
@@ -821,7 +823,7 @@
   return google_apis::CancelCallbackOnce();
 }
 
-CancelCallback FakeDriveService::CopyResource(
+CancelCallbackOnce FakeDriveService::CopyResource(
     const std::string& resource_id,
     const std::string& in_parent_resource_id,
     const std::string& new_title,
@@ -834,7 +836,7 @@
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), DRIVE_NO_CONNECTION,
                                   std::unique_ptr<FileResource>()));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   const std::string& parent_resource_id = in_parent_resource_id.empty() ?
@@ -845,7 +847,7 @@
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), HTTP_NOT_FOUND,
                                   std::unique_ptr<FileResource>()));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   // Make a copy and set the new resource ID and the new title.
@@ -897,10 +899,10 @@
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(&FakeDriveService::NotifyObservers,
                                 weak_ptr_factory_.GetWeakPtr()));
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
-CancelCallback FakeDriveService::UpdateResource(
+CancelCallbackOnce FakeDriveService::UpdateResource(
     const std::string& resource_id,
     const std::string& parent_resource_id,
     const std::string& new_title,
@@ -915,7 +917,7 @@
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), DRIVE_NO_CONNECTION,
                                   std::unique_ptr<FileResource>()));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   EntryInfo* entry = FindEntryByResourceId(resource_id);
@@ -923,14 +925,14 @@
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), HTTP_NOT_FOUND,
                                   std::unique_ptr<FileResource>()));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   if (!UserHasWriteAccess(entry->user_permission)) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), HTTP_FORBIDDEN,
                                   std::unique_ptr<FileResource>()));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   ChangeResource* change = &entry->change_resource;
@@ -966,10 +968,10 @@
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(&FakeDriveService::NotifyObservers,
                                 weak_ptr_factory_.GetWeakPtr()));
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
-CancelCallback FakeDriveService::AddResourceToDirectory(
+CancelCallbackOnce FakeDriveService::AddResourceToDirectory(
     const std::string& parent_resource_id,
     const std::string& resource_id,
     EntryActionCallback callback) {
@@ -979,14 +981,14 @@
   if (offline_) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), DRIVE_NO_CONNECTION));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   EntryInfo* entry = FindEntryByResourceId(resource_id);
   if (!entry) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), HTTP_NOT_FOUND));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   ChangeResource* change = &entry->change_resource;
@@ -1004,7 +1006,7 @@
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(&FakeDriveService::NotifyObservers,
                                 weak_ptr_factory_.GetWeakPtr()));
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
 CancelCallbackOnce FakeDriveService::RemoveResourceFromDirectory(
@@ -1058,7 +1060,7 @@
       directory_title, options, std::move(callback));
 }
 
-CancelCallback FakeDriveService::InitiateUploadNewFile(
+CancelCallbackOnce FakeDriveService::InitiateUploadNewFile(
     const std::string& content_type,
     int64_t content_length,
     const std::string& parent_resource_id,
@@ -1072,14 +1074,14 @@
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::BindOnce(std::move(callback), DRIVE_NO_CONNECTION, GURL()));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   if (parent_resource_id != GetRootResourceId() &&
       !entries_.count(parent_resource_id)) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), HTTP_NOT_FOUND, GURL()));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   GURL session_url = GetNewUploadSessionUrl();
@@ -1091,16 +1093,16 @@
                     title);
 
   if (title == "never-sync.txt") {
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(std::move(callback), HTTP_SUCCESS, session_url));
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
-CancelCallback FakeDriveService::InitiateUploadExistingFile(
+CancelCallbackOnce FakeDriveService::InitiateUploadExistingFile(
     const std::string& content_type,
     int64_t content_length,
     const std::string& resource_id,
@@ -1113,20 +1115,20 @@
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::BindOnce(std::move(callback), DRIVE_NO_CONNECTION, GURL()));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   EntryInfo* entry = FindEntryByResourceId(resource_id);
   if (!entry) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), HTTP_NOT_FOUND, GURL()));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   if (!UserHasWriteAccess(entry->user_permission)) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), HTTP_FORBIDDEN, GURL()));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   FileResource* file = entry->change_resource.mutable_file();
@@ -1134,7 +1136,7 @@
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::BindOnce(std::move(callback), HTTP_PRECONDITION, GURL()));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
   // TODO(hashimoto): Update |file|'s metadata with |options|.
 
@@ -1149,18 +1151,19 @@
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(std::move(callback), HTTP_SUCCESS, session_url));
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
-CancelCallback FakeDriveService::GetUploadStatus(const GURL& upload_url,
-                                                 int64_t content_length,
-                                                 UploadRangeCallback callback) {
+CancelCallbackOnce FakeDriveService::GetUploadStatus(
+    const GURL& upload_url,
+    int64_t content_length,
+    UploadRangeCallback callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(callback);
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
-CancelCallback FakeDriveService::ResumeUpload(
+CancelCallbackOnce FakeDriveService::ResumeUpload(
     const GURL& upload_url,
     int64_t start_position,
     int64_t end_position,
@@ -1179,13 +1182,13 @@
   if (offline_) {
     std::move(completion_callback)
         .Run(DRIVE_NO_CONNECTION, std::unique_ptr<FileResource>());
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   if (!upload_sessions_.count(upload_url)) {
     std::move(completion_callback)
         .Run(HTTP_NOT_FOUND, std::unique_ptr<FileResource>());
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   UploadSession* session = &upload_sessions_[upload_url];
@@ -1195,7 +1198,7 @@
   if (session->uploaded_size != start_position) {
     std::move(completion_callback)
         .Run(HTTP_BAD_REQUEST, std::unique_ptr<FileResource>());
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   if (!progress_callback.is_null()) {
@@ -1217,7 +1220,7 @@
     session->uploaded_size = end_position;
     std::move(completion_callback)
         .Run(HTTP_RESUME_INCOMPLETE, std::unique_ptr<FileResource>());
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   std::string content_data;
@@ -1227,7 +1230,7 @@
       session->uploaded_size = end_position;
       std::move(completion_callback)
           .Run(DRIVE_FILE_ERROR, std::unique_ptr<FileResource>());
-      return CancelCallback();
+      return CancelCallbackOnce();
     }
   }
   session->uploaded_size = end_position;
@@ -1246,7 +1249,7 @@
     if (!new_entry) {
       std::move(completion_callback)
           .Run(HTTP_NOT_FOUND, std::unique_ptr<FileResource>());
-      return CancelCallback();
+      return CancelCallbackOnce();
     }
 
     std::move(completion_callback)
@@ -1255,14 +1258,14 @@
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(&FakeDriveService::NotifyObservers,
                                   weak_ptr_factory_.GetWeakPtr()));
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   EntryInfo* entry = FindEntryByResourceId(session->resource_id);
   if (!entry) {
     std::move(completion_callback)
         .Run(HTTP_NOT_FOUND, std::unique_ptr<FileResource>());
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   ChangeResource* change = &entry->change_resource;
@@ -1270,7 +1273,7 @@
   if (file->etag().empty() || session->etag != file->etag()) {
     std::move(completion_callback)
         .Run(HTTP_PRECONDITION, std::unique_ptr<FileResource>());
-    return CancelCallback();
+    return CancelCallbackOnce();
   }
 
   file->set_md5_checksum(base::MD5String(content_data));
@@ -1284,10 +1287,10 @@
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(&FakeDriveService::NotifyObservers,
                                 weak_ptr_factory_.GetWeakPtr()));
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
-CancelCallback FakeDriveService::MultipartUploadNewFile(
+CancelCallbackOnce FakeDriveService::MultipartUploadNewFile(
     const std::string& content_type,
     int64_t content_length,
     const std::string& parent_resource_id,
@@ -1310,10 +1313,10 @@
       title,
       options,
       base::Bind(&CallResumeUpload::Run, base::Owned(call_resume_upload)));
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
-CancelCallback FakeDriveService::MultipartUploadExistingFile(
+CancelCallbackOnce FakeDriveService::MultipartUploadExistingFile(
     const std::string& content_type,
     int64_t content_length,
     const std::string& resource_id,
@@ -1334,7 +1337,7 @@
       resource_id,
       options,
       base::Bind(&CallResumeUpload::Run, base::Owned(call_resume_upload)));
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
 void FakeDriveService::AddNewFile(const std::string& content_type,
@@ -1913,7 +1916,7 @@
               base::NumberToString(next_upload_sequence_number_++));
 }
 
-google_apis::CancelCallback FakeDriveService::AddPermission(
+CancelCallbackOnce FakeDriveService::AddPermission(
     const std::string& resource_id,
     const std::string& email,
     google_apis::drive::PermissionRole role,
@@ -1922,7 +1925,7 @@
   DCHECK(callback);
 
   NOTREACHED();
-  return CancelCallback();
+  return CancelCallbackOnce();
 }
 
 std::unique_ptr<BatchRequestConfiguratorInterface>
diff --git a/components/drive/service/fake_drive_service.h b/components/drive/service/fake_drive_service.h
index f77076a..54a8662 100644
--- a/components/drive/service/fake_drive_service.h
+++ b/components/drive/service/fake_drive_service.h
@@ -150,35 +150,35 @@
       const std::string& title,
       const std::string& directory_resource_id,
       google_apis::FileListCallback callback) override;
-  google_apis::CancelCallback GetChangeList(
+  google_apis::CancelCallbackOnce GetChangeList(
       int64_t start_changestamp,
       google_apis::ChangeListCallback callback) override;
-  google_apis::CancelCallback GetChangeListByToken(
+  google_apis::CancelCallbackOnce GetChangeListByToken(
       const std::string& team_drive_id,
       const std::string& start_page_token,
       google_apis::ChangeListCallback callback) override;
   google_apis::CancelCallbackOnce GetRemainingChangeList(
       const GURL& next_link,
       google_apis::ChangeListCallback callback) override;
-  google_apis::CancelCallback GetRemainingTeamDriveList(
+  google_apis::CancelCallbackOnce GetRemainingTeamDriveList(
       const std::string& page_token,
       google_apis::TeamDriveListCallback callback) override;
   google_apis::CancelCallbackOnce GetRemainingFileList(
       const GURL& next_link,
       google_apis::FileListCallback callback) override;
-  google_apis::CancelCallback GetFileResource(
+  google_apis::CancelCallbackOnce GetFileResource(
       const std::string& resource_id,
       google_apis::FileResourceCallback callback) override;
-  google_apis::CancelCallback GetAboutResource(
+  google_apis::CancelCallbackOnce GetAboutResource(
       google_apis::AboutResourceCallback callback) override;
-  google_apis::CancelCallback GetStartPageToken(
+  google_apis::CancelCallbackOnce GetStartPageToken(
       const std::string& team_drive_id,
       google_apis::StartPageTokenCallback callback) override;
-  google_apis::CancelCallback DeleteResource(
+  google_apis::CancelCallbackOnce DeleteResource(
       const std::string& resource_id,
       const std::string& etag,
       google_apis::EntryActionCallback callback) override;
-  google_apis::CancelCallback TrashResource(
+  google_apis::CancelCallbackOnce TrashResource(
       const std::string& resource_id,
       google_apis::EntryActionCallback callback) override;
   google_apis::CancelCallbackOnce DownloadFile(
@@ -187,13 +187,13 @@
       google_apis::DownloadActionCallback download_action_callback,
       const google_apis::GetContentCallback& get_content_callback,
       google_apis::ProgressCallback progress_callback) override;
-  google_apis::CancelCallback CopyResource(
+  google_apis::CancelCallbackOnce CopyResource(
       const std::string& resource_id,
       const std::string& parent_resource_id,
       const std::string& new_title,
       const base::Time& last_modified,
       google_apis::FileResourceCallback callback) override;
-  google_apis::CancelCallback UpdateResource(
+  google_apis::CancelCallbackOnce UpdateResource(
       const std::string& resource_id,
       const std::string& parent_resource_id,
       const std::string& new_title,
@@ -201,7 +201,7 @@
       const base::Time& last_viewed_by_me,
       const google_apis::drive::Properties& properties,
       google_apis::FileResourceCallback callback) override;
-  google_apis::CancelCallback AddResourceToDirectory(
+  google_apis::CancelCallbackOnce AddResourceToDirectory(
       const std::string& parent_resource_id,
       const std::string& resource_id,
       google_apis::EntryActionCallback callback) override;
@@ -214,20 +214,20 @@
       const std::string& directory_title,
       const AddNewDirectoryOptions& options,
       google_apis::FileResourceCallback callback) override;
-  google_apis::CancelCallback InitiateUploadNewFile(
+  google_apis::CancelCallbackOnce InitiateUploadNewFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& parent_resource_id,
       const std::string& title,
       const UploadNewFileOptions& options,
       google_apis::InitiateUploadCallback callback) override;
-  google_apis::CancelCallback InitiateUploadExistingFile(
+  google_apis::CancelCallbackOnce InitiateUploadExistingFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& resource_id,
       const UploadExistingFileOptions& options,
       google_apis::InitiateUploadCallback callback) override;
-  google_apis::CancelCallback ResumeUpload(
+  google_apis::CancelCallbackOnce ResumeUpload(
       const GURL& upload_url,
       int64_t start_position,
       int64_t end_position,
@@ -236,11 +236,11 @@
       const base::FilePath& local_file_path,
       google_apis::drive::UploadRangeCallback callback,
       google_apis::ProgressCallback progress_callback) override;
-  google_apis::CancelCallback GetUploadStatus(
+  google_apis::CancelCallbackOnce GetUploadStatus(
       const GURL& upload_url,
       int64_t content_length,
       google_apis::drive::UploadRangeCallback callback) override;
-  google_apis::CancelCallback MultipartUploadNewFile(
+  google_apis::CancelCallbackOnce MultipartUploadNewFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& parent_resource_id,
@@ -249,7 +249,7 @@
       const UploadNewFileOptions& options,
       google_apis::FileResourceCallback callback,
       google_apis::ProgressCallback progress_callback) override;
-  google_apis::CancelCallback MultipartUploadExistingFile(
+  google_apis::CancelCallbackOnce MultipartUploadExistingFile(
       const std::string& content_type,
       int64_t content_length,
       const std::string& resource_id,
@@ -257,7 +257,7 @@
       const UploadExistingFileOptions& options,
       google_apis::FileResourceCallback callback,
       google_apis::ProgressCallback progress_callback) override;
-  google_apis::CancelCallback AddPermission(
+  google_apis::CancelCallbackOnce AddPermission(
       const std::string& resource_id,
       const std::string& email,
       google_apis::drive::PermissionRole role,
diff --git a/components/exo/shell_surface.cc b/components/exo/shell_surface.cc
index 6d738eb..071f9f16 100644
--- a/components/exo/shell_surface.cc
+++ b/components/exo/shell_surface.cc
@@ -498,6 +498,10 @@
   return true;
 }
 
+void ShellSurface::SetDecorationMode(SurfaceFrameType type) {
+  OnSetFrame(type);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // ShellSurface, private:
 
diff --git a/components/exo/shell_surface.h b/components/exo/shell_surface.h
index 056114a..3b53ff7 100644
--- a/components/exo/shell_surface.h
+++ b/components/exo/shell_surface.h
@@ -125,6 +125,9 @@
   void SetWidgetBounds(const gfx::Rect& bounds) override;
   bool OnPreWidgetCommit() override;
 
+  // Set xdg-shell decoration mode.
+  void SetDecorationMode(SurfaceFrameType type);
+
  private:
   struct Config;
 
diff --git a/components/exo/wayland/xdg_shell.cc b/components/exo/wayland/xdg_shell.cc
index 07abcf49..4bcd391 100644
--- a/components/exo/wayland/xdg_shell.cc
+++ b/components/exo/wayland/xdg_shell.cc
@@ -159,36 +159,6 @@
   DISALLOW_COPY_AND_ASSIGN(WaylandXdgSurface);
 };
 
-class WaylandXdgToplevelDecoration {
- public:
-  WaylandXdgToplevelDecoration(wl_resource* resource) : resource_(resource) {}
-
-  WaylandXdgToplevelDecoration(const WaylandXdgToplevelDecoration&) = delete;
-  WaylandXdgToplevelDecoration& operator=(const WaylandXdgToplevelDecoration&) =
-      delete;
-
-  uint32_t decoration_mode() const { return default_mode_; }
-  void SetDecorationMode(uint32_t mode) {
-    if (default_mode_ != mode) {
-      default_mode_ = mode;
-      OnConfigure(mode);
-    }
-  }
-
- private:
-  void OnConfigure(uint32_t mode) {
-    switch (mode) {
-      case ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE:
-      case ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE:
-        zxdg_toplevel_decoration_v1_send_configure(resource_, mode);
-        break;
-    }
-  }
-
-  wl_resource* const resource_;
-  uint32_t default_mode_ = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
-};
-
 // Wrapper around shell surface that allows us to handle the case where the
 // xdg surface resource is destroyed before the toplevel resource.
 class WaylandToplevel : public aura::WindowObserver {
@@ -287,6 +257,11 @@
       shell_surface_data_->shell_surface->Minimize();
   }
 
+  void SetDecorationMode(SurfaceFrameType type) {
+    if (shell_surface_data_)
+      shell_surface_data_->shell_surface->SetDecorationMode(type);
+  }
+
  private:
   void OnClose() {
     xdg_toplevel_send_close(resource_);
@@ -425,6 +400,44 @@
     xdg_toplevel_unset_maximized,  xdg_toplevel_set_fullscreen,
     xdg_toplevel_unset_fullscreen, xdg_toplevel_set_minimized};
 
+class WaylandXdgToplevelDecoration {
+ public:
+  WaylandXdgToplevelDecoration(wl_resource* resource,
+                               wl_resource* toplevel_resource)
+      : resource_(resource),
+        top_level_(GetUserDataAs<WaylandToplevel>(toplevel_resource)) {}
+
+  WaylandXdgToplevelDecoration(const WaylandXdgToplevelDecoration&) = delete;
+  WaylandXdgToplevelDecoration& operator=(const WaylandXdgToplevelDecoration&) =
+      delete;
+
+  uint32_t decoration_mode() const { return default_mode_; }
+  void SetDecorationMode(uint32_t mode) {
+    if (default_mode_ != mode) {
+      default_mode_ = mode;
+      OnConfigure(mode);
+    }
+  }
+
+ private:
+  void OnConfigure(uint32_t mode) {
+    switch (mode) {
+      case ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE:
+        top_level_->SetDecorationMode(SurfaceFrameType::NONE);
+        break;
+      case ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE:
+        top_level_->SetDecorationMode(SurfaceFrameType::NORMAL);
+        break;
+    }
+    zxdg_toplevel_decoration_v1_send_configure(resource_, mode);
+  }
+
+  wl_resource* const resource_;
+  WaylandToplevel* top_level_;
+  // Keeps track of the xdg-decoration mode on server side.
+  uint32_t default_mode_ = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
+};
+
 ////////////////////////////////////////////////////////////////////////////////
 // xdg_popup_interface:
 
@@ -733,12 +746,8 @@
     return;
   }
 
-  auto xdg_toplevel_decoration =
-      std::make_unique<WaylandXdgToplevelDecoration>(decoration_resource);
-
-  // Enables client-side decoration
-  xdg_toplevel_decoration->SetDecorationMode(
-      ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE);
+  auto xdg_toplevel_decoration = std::make_unique<WaylandXdgToplevelDecoration>(
+      decoration_resource, toplevel_resource);
 
   SetImplementation(decoration_resource, &toplevel_decoration_impl,
                     std::move(xdg_toplevel_decoration));
diff --git a/components/optimization_guide/optimization_guide_switches.cc b/components/optimization_guide/optimization_guide_switches.cc
index ff032c3..570dff9 100644
--- a/components/optimization_guide/optimization_guide_switches.cc
+++ b/components/optimization_guide/optimization_guide_switches.cc
@@ -66,6 +66,9 @@
 const char kDisableCheckingUserPermissionsForTesting[] =
     "disable-checking-optimization-guide-user-permissions";
 
+const char kDisableModelDownloadVerificationForTesting[] =
+    "disable-model-download-verification";
+
 bool IsHintComponentProcessingDisabled() {
   return base::CommandLine::ForCurrentProcess()->HasSwitch(kHintsProtoOverride);
 }
@@ -149,5 +152,10 @@
   return command_line->HasSwitch(kDisableCheckingUserPermissionsForTesting);
 }
 
+bool ShouldSkipModelDownloadVerificationForTesting() {
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  return command_line->HasSwitch(kDisableModelDownloadVerificationForTesting);
+}
+
 }  // namespace switches
 }  // namespace optimization_guide
diff --git a/components/optimization_guide/optimization_guide_switches.h b/components/optimization_guide/optimization_guide_switches.h
index 6460a34..29d05fd 100644
--- a/components/optimization_guide/optimization_guide_switches.h
+++ b/components/optimization_guide/optimization_guide_switches.h
@@ -29,6 +29,7 @@
 extern const char kPurgeModelAndFeaturesStore[];
 extern const char kDisableFetchingHintsAtNavigationStartForTesting[];
 extern const char kDisableCheckingUserPermissionsForTesting[];
+extern const char kDisableModelDownloadVerificationForTesting[];
 
 // Returns whether the hint component should be processed.
 // Available hint components are only processed if a proto override isn't being
@@ -72,6 +73,9 @@
 // tests.
 bool ShouldOverrideCheckingUserPermissionsToFetchHintsForTesting();
 
+// Returns true if the verification of model downloads should be skipped.
+bool ShouldSkipModelDownloadVerificationForTesting();
+
 }  // namespace switches
 }  // namespace optimization_guide
 
diff --git a/components/payments/content/autofill_payment_app.cc b/components/payments/content/autofill_payment_app.cc
index b5718993..d4c6f50 100644
--- a/components/payments/content/autofill_payment_app.cc
+++ b/components/payments/content/autofill_payment_app.cc
@@ -193,7 +193,8 @@
     GenerateBasicCardResponse();
 }
 
-void AutofillPaymentApp::OnFullCardRequestFailed() {
+void AutofillPaymentApp::OnFullCardRequestFailed(
+    autofill::payments::FullCardRequest::FailureType failure_type) {
   // The user may have cancelled the unmask or something has gone wrong (e.g.,
   // the network request failed). In all cases, reset the |delegate_| so another
   // request can start.
diff --git a/components/payments/content/autofill_payment_app.h b/components/payments/content/autofill_payment_app.h
index 2f6b4df8..cae2824 100644
--- a/components/payments/content/autofill_payment_app.h
+++ b/components/payments/content/autofill_payment_app.h
@@ -64,7 +64,8 @@
       const autofill::payments::FullCardRequest& full_card_request,
       const autofill::CreditCard& card,
       const base::string16& cvc) override;
-  void OnFullCardRequestFailed() override;
+  void OnFullCardRequestFailed(
+      autofill::payments::FullCardRequest::FailureType failure_type) override;
 
   void RecordMissingFieldsForApp() const;
 
diff --git a/components/policy/tools/syntax_check_policy_template_json.py b/components/policy/tools/syntax_check_policy_template_json.py
index 7c8a883..b2dd1d0c 100755
--- a/components/policy/tools/syntax_check_policy_template_json.py
+++ b/components/policy/tools/syntax_check_policy_template_json.py
@@ -182,22 +182,6 @@
                                               if supported_on_to else None)
 
 
-def _PolicyStillSupported(supported_on, current_version):
-  for s in supported_on:
-    _, _, supported_on_to = _GetSupportedVersionPlatformAndRange(s)
-
-    # If supported_on_to isn't given, this policy is still supported.
-    if supported_on_to is None:
-      return True
-
-    # If supported_on_to is equal or greater than the current version, it's
-    # still supported.
-    if current_version <= int(supported_on_to):
-      return True
-
-  return False
-
-
 def _GetPolicyValueType(policy_type):
   if policy_type == 'main':
     return bool
@@ -516,10 +500,16 @@
   def _NeedsDefault(self, policy):
     return policy.get('type') in ('int', 'main', 'string-enum', 'int-enum')
 
-  def _CheckDefault(self, policy):
+  def _CheckDefault(self, policy, current_version):
     if not self._NeedsDefault(policy):
       return
 
+    # If a policy should have a default but it is no longer supported, we can
+    # safely ignore this error.
+    if ('default' not in policy
+        and not self._SupportedPolicy(policy, current_version)):
+      return
+
     # Only validate the default when present.
     # TODO(crbug.com/1139046): Always validate the default for types that
     # should have it.
@@ -559,10 +549,16 @@
     return policy.get('type') in ('main', 'int-enum', 'string-enum',
                                   'string-enum-list')
 
-  def _CheckItems(self, policy):
+  def _CheckItems(self, policy, current_version):
     if not self._NeedsItems(policy):
       return
 
+    # If a policy should have items, but it is no longer supported, we
+    # can safely ignore this error.
+    if 'items' not in policy and not self._SupportedPolicy(
+        policy, current_version):
+      return
+
     # TODO(crbug.com/1139306): Remove this check once all main policies
     # have specified their items field.
     policy_type = policy.get('type')
@@ -684,6 +680,25 @@
                     'be committer emails or file:// paths' %
                     (policy.get('name'), owner))
 
+  def _SupportedPolicy(self, policy, current_version):
+    # If a policy has any future_on platforms, it is still supported.
+    if len(policy.get('future_on', [])) > 0:
+      return True
+
+    for s in policy.get('supported_on', []):
+      _, _, supported_on_to = _GetSupportedVersionPlatformAndRange(s)
+
+      # If supported_on_to isn't given, this policy is still supported.
+      if supported_on_to is None:
+        return True
+
+      # If supported_on_to is equal or greater than the current version, it's
+      # still supported.
+      if current_version <= int(supported_on_to):
+        return True
+
+    return False
+
   def _CheckPolicy(self, policy, is_in_group, policy_ids, deleted_policy_ids,
                    current_version):
     if not isinstance(policy, dict):
@@ -832,7 +847,7 @@
                 'supported version must have a version larger than the '
                 'starting supported version.', 'policy', policy, supported_on)
 
-        if (not _PolicyStillSupported(supported_on, current_version)
+        if (not self._SupportedPolicy(policy, current_version)
             and not policy.get('deprecated', False)):
           self._Error(
               'Policy %s is marked as no longer supported (%s), but isn\'t '
@@ -1029,14 +1044,14 @@
             self._Error(('Example for policy %s does not comply to the ' +
                          'policy\'s validation_schema') % policy.get('name'))
 
-      self._CheckDefault(policy)
+      self._CheckDefault(policy, current_version)
 
       # Statistics.
       self.num_policies += 1
       if is_in_group:
         self.num_policies_in_groups += 1
 
-      self._CheckItems(policy)
+      self._CheckItems(policy, current_version)
 
       if policy_type == 'external':
         # Each policy referencing external data must specify a maximum data
diff --git a/components/printing/browser/print_composite_client.cc b/components/printing/browser/print_composite_client.cc
index 02a7786..a14bba7 100644
--- a/components/printing/browser/print_composite_client.cc
+++ b/components/printing/browser/print_composite_client.cc
@@ -101,6 +101,19 @@
   print_render_frames_.erase(render_frame_host);
 }
 
+PrintCompositeClient::RequestedSubFrame::RequestedSubFrame(
+    int render_process_id,
+    int render_frame_id,
+    int document_cookie,
+    mojom::DidPrintContentParamsPtr params,
+    bool is_live)
+    : render_process_id_(render_process_id),
+      render_frame_id_(render_frame_id),
+      document_cookie_(document_cookie),
+      params_(std::move(params)),
+      is_live_(is_live) {}
+PrintCompositeClient::RequestedSubFrame::~RequestedSubFrame() = default;
+
 void PrintCompositeClient::OnDidPrintFrameContent(
     int render_process_id,
     int render_frame_id,
@@ -121,8 +134,16 @@
     return;
   }
 
-  if (!IsDocumentCookieValid(document_cookie))
+  if (!IsDocumentCookieValid(document_cookie)) {
+    if (!compositor_) {
+      // Queues the subframe information to |requested_subframes_| to handle it
+      // after |compositor_| is created by the main frame.
+      requested_subframes_.insert(std::make_unique<RequestedSubFrame>(
+          render_process_id, render_frame_id, document_cookie,
+          std::move(params), true));
+    }
     return;
+  }
 
   auto* render_frame_host =
       content::RenderFrameHost::FromID(render_process_id, render_frame_id);
@@ -161,8 +182,16 @@
     content::RenderFrameHost* subframe_host) {
   auto params = mojom::PrintFrameContentParams::New(rect, document_cookie);
   if (!subframe_host->IsRenderFrameLive()) {
-    if (!IsDocumentCookieValid(document_cookie))
+    if (!IsDocumentCookieValid(document_cookie)) {
+      if (!compositor_) {
+        // Queues the subframe information to |requested_subframes_| to handle
+        // it after |compositor_| is created by the main frame.
+        requested_subframes_.insert(std::make_unique<RequestedSubFrame>(
+            subframe_host->GetProcess()->GetID(), subframe_host->GetRoutingID(),
+            document_cookie, nullptr, false));
+      }
       return;
+    }
 
     // When the subframe is dead, no need to send message,
     // just notify the service.
@@ -178,14 +207,13 @@
   }
 
   // Send the request to the destination frame.
-  int render_process_id = subframe_host->GetProcess()->GetID();
-  int render_frame_id = subframe_host->GetRoutingID();
   GetPrintRenderFrame(subframe_host)
       ->PrintFrameContent(
           std::move(params),
           base::BindOnce(&PrintCompositeClient::OnDidPrintFrameContent,
-                         weak_ptr_factory_.GetWeakPtr(), render_process_id,
-                         render_frame_id));
+                         weak_ptr_factory_.GetWeakPtr(),
+                         subframe_host->GetProcess()->GetID(),
+                         subframe_host->GetRoutingID()));
   pending_subframes_.insert(subframe_host);
 }
 
@@ -253,6 +281,23 @@
   DCHECK(!GetIsDocumentConcurrentlyComposited(document_cookie));
 
   auto* compositor = CreateCompositeRequest(document_cookie, render_frame_host);
+
+  for (auto& requested : requested_subframes_) {
+    if (!IsDocumentCookieValid(requested->document_cookie_))
+      continue;
+    if (requested->is_live_) {
+      OnDidPrintFrameContent(
+          requested->render_process_id_, requested->render_frame_id_,
+          requested->document_cookie_, std::move(requested->params_));
+    } else {
+      auto* render_frame_host = content::RenderFrameHost::FromID(
+          requested->render_process_id_, requested->render_frame_id_);
+      compositor->NotifyUnavailableSubframe(
+          GenerateFrameGuid(render_frame_host));
+    }
+  }
+  requested_subframes_.clear();
+
   auto region = content.metafile_data_region.Duplicate();
 
   // Since this class owns compositor, compositor will be gone when this class
diff --git a/components/printing/browser/print_composite_client.h b/components/printing/browser/print_composite_client.h
index 40ff2d3..284371d 100644
--- a/components/printing/browser/print_composite_client.h
+++ b/components/printing/browser/print_composite_client.h
@@ -94,6 +94,9 @@
 
  private:
   friend class content::WebContentsUserData<PrintCompositeClient>;
+  FRIEND_TEST_ALL_PREFIXES(PrintBrowserTest,
+                           PrintSubframeContentBeforeCompositeClientCreation);
+
   // Callback functions for getting the replies.
   static void OnDidCompositePageToPdf(
       mojom::PrintCompositor::CompositePageToPdfCallback callback,
@@ -167,6 +170,25 @@
   // Stores the printed subframes for the composited document.
   base::flat_set<content::RenderFrameHost*> printed_subframes_;
 
+  struct RequestedSubFrame {
+    RequestedSubFrame(int render_process_id,
+                      int render_frame_id,
+                      int document_cookie,
+                      mojom::DidPrintContentParamsPtr params,
+                      bool is_live);
+    ~RequestedSubFrame();
+    RequestedSubFrame(const PrintCompositeClient::RequestedSubFrame&) = delete;
+    RequestedSubFrame& operator=(
+        const PrintCompositeClient::RequestedSubFrame&) = delete;
+
+    int render_process_id_;
+    int render_frame_id_;
+    int document_cookie_;
+    mojom::DidPrintContentParamsPtr params_;
+    bool is_live_;
+  };
+  base::flat_set<std::unique_ptr<RequestedSubFrame>> requested_subframes_;
+
   std::string user_agent_;
 
   // Stores a PrintRenderFrame associated remote with the RenderFrameHost used
diff --git a/components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm b/components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm
index 5e5a39c..44a574e 100644
--- a/components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm
+++ b/components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm
@@ -19,10 +19,6 @@
 - (BOOL)hasKeyAppearance;
 - (long long)_resizeDirectionForMouseLocation:(CGPoint)location;
 - (BOOL)_isConsideredOpenForPersistentState;
-
-// Available in later point releases of 10.10. On 10.11+, use the public
-// -performWindowDragWithEvent: instead.
-- (void)beginWindowDragWithEvent:(NSEvent*)event;
 @end
 
 @interface NativeWidgetMacNSWindow () <NSKeyedArchiverDelegate>
@@ -47,13 +43,7 @@
   if ([self.window _resizeDirectionForMouseLocation:event.locationInWindow] !=
       -1)
     return;
-  if (@available(macOS 10.11, *))
-    [self.window performWindowDragWithEvent:event];
-  else if ([self.window
-               respondsToSelector:@selector(beginWindowDragWithEvent:)])
-    [self.window beginWindowDragWithEvent:event];
-  else
-    NOTREACHED();
+  [self.window performWindowDragWithEvent:event];
 }
 @end
 
diff --git a/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.cc b/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.cc
index 9c4b1c7..cc236b1 100644
--- a/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.cc
+++ b/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.cc
@@ -259,7 +259,7 @@
   }
 
   if (is_prefetch) {
-    // Destroy the prefetch with FINAL_STATUS_SAFEBROSWING.
+    // Destroy the prefetch with FINAL_STATUS_SAFE_BROWSING.
     if (resource_type_ == ResourceType::kMainFrame) {
       url_checker_delegate_->MaybeDestroyPrerenderContents(
           web_contents_getter_);
diff --git a/components/scheduling_metrics/DIR_METADATA b/components/scheduling_metrics/DIR_METADATA
new file mode 100644
index 0000000..7291e29
--- /dev/null
+++ b/components/scheduling_metrics/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>Scheduler"
+}
diff --git a/components/scheduling_metrics/OWNERS b/components/scheduling_metrics/OWNERS
index fff52aa..d1d314f 100644
--- a/components/scheduling_metrics/OWNERS
+++ b/components/scheduling_metrics/OWNERS
@@ -10,5 +10,3 @@
 # MON scheduling team
 fdoray@chromium.org
 gab@chromium.org
-
-# COMPONENT: Blink>Scheduler
diff --git a/components/schema_org/DIR_METADATA b/components/schema_org/DIR_METADATA
new file mode 100644
index 0000000..1620260
--- /dev/null
+++ b/components/schema_org/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Blink>DocumentMetadata"
+}
+
+team_email: "media-dev@chromium.org"
diff --git a/components/schema_org/OWNERS b/components/schema_org/OWNERS
index 12cb8c1..65f49a1 100644
--- a/components/schema_org/OWNERS
+++ b/components/schema_org/OWNERS
@@ -1,6 +1,3 @@
 beccahughes@chromium.org
 steimel@chromium.org
 sgbowen@google.com
-
-# COMPONENT: Blink>DocumentMetadata
-# TEAM: media-dev@chromium.org
diff --git a/components/shared_highlighting/DIR_METADATA b/components/shared_highlighting/DIR_METADATA
new file mode 100644
index 0000000..eafcc7d
--- /dev/null
+++ b/components/shared_highlighting/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "UI>Browser>SharedHighlighting"
+}
+
+team_email: "chrome-shared-highlighting@google.com"
diff --git a/components/shared_highlighting/OWNERS b/components/shared_highlighting/OWNERS
index eab70ff..0cee9a5 100644
--- a/components/shared_highlighting/OWNERS
+++ b/components/shared_highlighting/OWNERS
@@ -1,5 +1,2 @@
 sebsg@chromium.org
 seblalancette@chromium.org
-
-# COMPONENT: UI>Browser>SharedHighlighting
-# TEAM: chrome-shared-highlighting@google.com
\ No newline at end of file
diff --git a/components/signin/DIR_METADATA b/components/signin/DIR_METADATA
new file mode 100644
index 0000000..4735e25f
--- /dev/null
+++ b/components/signin/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Services>SignIn"
+}
+
+team_email: "chrome-signin@chromium.org"
diff --git a/components/signin/OWNERS b/components/signin/OWNERS
index 26af5a6..4b57883 100644
--- a/components/signin/OWNERS
+++ b/components/signin/OWNERS
@@ -6,6 +6,3 @@
 
 # For android related change
 per-file *android*=aliceywang@chromium.org
-
-# TEAM: chrome-signin@chromium.org
-# COMPONENT: Services>SignIn
diff --git a/components/signin/core/browser/signin_error_controller_unittest.cc b/components/signin/core/browser/signin_error_controller_unittest.cc
index 4cf9bfc..d428880 100644
--- a/components/signin/core/browser/signin_error_controller_unittest.cc
+++ b/components/signin/core/browser/signin_error_controller_unittest.cc
@@ -137,73 +137,6 @@
   EXPECT_FALSE(error_controller.HasError());
 }
 
-// This test exercises behavior on signin/signout, which is not relevant on
-// ChromeOS.
-#if !BUILDFLAG(IS_CHROMEOS_ASH)
-TEST(SigninErrorControllerTest, AccountTransitionPrimaryAccount) {
-  base::test::TaskEnvironment task_environment;
-  signin::IdentityTestEnvironment identity_test_env;
-  signin::PrimaryAccountMutator* primary_account_mutator =
-      identity_test_env.identity_manager()->GetPrimaryAccountMutator();
-
-  CoreAccountId test_account_id =
-      identity_test_env.MakeAccountAvailable(kTestEmail).account_id;
-  CoreAccountId other_test_account_id =
-      identity_test_env.MakeAccountAvailable(kOtherTestEmail).account_id;
-  SigninErrorController error_controller(
-      SigninErrorController::AccountMode::PRIMARY_ACCOUNT,
-      identity_test_env.identity_manager());
-  ASSERT_FALSE(error_controller.HasError());
-
-  identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
-      test_account_id,
-      GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
-  identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
-      other_test_account_id,
-      GoogleServiceAuthError(GoogleServiceAuthError::NONE));
-  ASSERT_FALSE(error_controller.HasError());  // No primary account.
-
-  // Set the primary account.
-  identity_test_env.SetPrimaryAccount(kOtherTestEmail);
-
-  ASSERT_FALSE(error_controller.HasError());  // Error is on secondary.
-
-  // Change the primary account to the account with an error and check that the
-  // error controller updates its error status accordingly.
-  primary_account_mutator->ClearPrimaryAccount(
-      signin::PrimaryAccountMutator::ClearAccountsAction::kKeepAll,
-      signin_metrics::FORCE_SIGNOUT_ALWAYS_ALLOWED_FOR_TEST,
-      signin_metrics::SignoutDelete::IGNORE_METRIC);
-  identity_test_env.SetPrimaryAccount(kTestEmail);
-  ASSERT_TRUE(error_controller.HasError());
-  ASSERT_EQ(test_account_id, error_controller.error_account_id());
-
-  identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
-      other_test_account_id,
-      GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
-  ASSERT_TRUE(error_controller.HasError());
-  ASSERT_EQ(test_account_id, error_controller.error_account_id());
-
-  // Change the primary account again and check that the error controller
-  // updates its error status accordingly.
-  primary_account_mutator->ClearPrimaryAccount(
-      signin::PrimaryAccountMutator::ClearAccountsAction::kKeepAll,
-      signin_metrics::FORCE_SIGNOUT_ALWAYS_ALLOWED_FOR_TEST,
-      signin_metrics::SignoutDelete::IGNORE_METRIC);
-  identity_test_env.SetPrimaryAccount(kOtherTestEmail);
-  ASSERT_TRUE(error_controller.HasError());
-  ASSERT_EQ(other_test_account_id, error_controller.error_account_id());
-
-  // Sign out and check that that the error controller updates its error status
-  // accordingly.
-  primary_account_mutator->ClearPrimaryAccount(
-      signin::PrimaryAccountMutator::ClearAccountsAction::kKeepAll,
-      signin_metrics::FORCE_SIGNOUT_ALWAYS_ALLOWED_FOR_TEST,
-      signin_metrics::SignoutDelete::IGNORE_METRIC);
-  ASSERT_FALSE(error_controller.HasError());
-}
-#endif
-
 // Verify that SigninErrorController handles errors properly.
 TEST(SigninErrorControllerTest, AuthStatusEnumerateAllErrors) {
   base::test::TaskEnvironment task_environment;
diff --git a/components/signin/internal/identity_manager/primary_account_manager.cc b/components/signin/internal/identity_manager/primary_account_manager.cc
index 657c94a..d7d25cb 100644
--- a/components/signin/internal/identity_manager/primary_account_manager.cc
+++ b/components/signin/internal/identity_manager/primary_account_manager.cc
@@ -363,6 +363,7 @@
   if (HasPrimaryAccount(signin::ConsentLevel::kSync))
     SetPrimaryAccountInternal(account_info, /*consented_to_sync=*/false);
 
+  DCHECK(!HasPrimaryAccount(signin::ConsentLevel::kSync));
   // Revoke all tokens before sending signed_out notification, because there
   // may be components that don't listen for token service events when the
   // profile is not connected to an account.
diff --git a/components/signin/internal/identity_manager/primary_account_manager.h b/components/signin/internal/identity_manager/primary_account_manager.h
index baaac24..9d502412 100644
--- a/components/signin/internal/identity_manager/primary_account_manager.h
+++ b/components/signin/internal/identity_manager/primary_account_manager.h
@@ -139,6 +139,9 @@
   // Signs a user out, removing the preference, erasing all keys
   // associated with the authenticated user, and canceling all auth in progress.
   // Does not remove the accounts from the token service.
+  //
+  // TODO(msarda): This method is only called from within the IdentityManager
+  // and from tests and should be removed.
   void SignOutAndKeepAllAccounts(
       signin_metrics::ProfileSignout signout_source_metric,
       signin_metrics::SignoutDelete signout_delete_metric);
diff --git a/components/signin/internal/identity_manager/primary_account_mutator_impl.cc b/components/signin/internal/identity_manager/primary_account_mutator_impl.cc
index 733f5316..db1a06c 100644
--- a/components/signin/internal/identity_manager/primary_account_mutator_impl.cc
+++ b/components/signin/internal/identity_manager/primary_account_mutator_impl.cc
@@ -87,10 +87,6 @@
     case PrimaryAccountMutator::ClearAccountsAction::kDefault:
       primary_account_manager_->SignOut(source_metric, delete_metric);
       break;
-    case PrimaryAccountMutator::ClearAccountsAction::kKeepAll:
-      primary_account_manager_->SignOutAndKeepAllAccounts(source_metric,
-                                                          delete_metric);
-      break;
     case PrimaryAccountMutator::ClearAccountsAction::kRemoveAll:
       primary_account_manager_->SignOutAndRemoveAllAccounts(source_metric,
                                                             delete_metric);
diff --git a/components/signin/ios/DIR_METADATA b/components/signin/ios/DIR_METADATA
new file mode 100644
index 0000000..5fad689
--- /dev/null
+++ b/components/signin/ios/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Services>SignIn"
+}
diff --git a/components/signin/ios/OWNERS b/components/signin/ios/OWNERS
index 04f4beaa..6d56d2f 100644
--- a/components/signin/ios/OWNERS
+++ b/components/signin/ios/OWNERS
@@ -1,5 +1,3 @@
 fernandex@chromium.org
 jlebel@chromium.org
 msarda@chromium.org
-
-# COMPONENT: Services>SignIn
diff --git a/components/signin/public/identity_manager/primary_account_mutator.h b/components/signin/public/identity_manager/primary_account_mutator.h
index feb55a4..14d0e3f 100644
--- a/components/signin/public/identity_manager/primary_account_mutator.h
+++ b/components/signin/public/identity_manager/primary_account_mutator.h
@@ -33,7 +33,6 @@
   // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.signin.identitymanager
   enum class ClearAccountsAction {
     kDefault,    // Default action based on internal policy.
-    kKeepAll,    // Keep all accounts.
     kRemoveAll,  // Remove all accounts.
   };
 
diff --git a/components/signin/public/identity_manager/primary_account_mutator_unittest.cc b/components/signin/public/identity_manager/primary_account_mutator_unittest.cc
index 136ff2b..7eb1b5f 100644
--- a/components/signin/public/identity_manager/primary_account_mutator_unittest.cc
+++ b/components/signin/public/identity_manager/primary_account_mutator_unittest.cc
@@ -437,18 +437,6 @@
       other_account_info.account_id));
 }
 
-// Test that ClearPrimaryAccount(...) with ClearAccountTokensAction::kKeepAll
-// keep all tokens, independently of the account consistency method.
-TEST_F(PrimaryAccountMutatorTest, ClearPrimaryAccount_KeepAll) {
-  for (signin::AccountConsistencyMethod account_consistency_method :
-       kTestedAccountConsistencyMethods) {
-    RunClearPrimaryAccountTest(
-        account_consistency_method,
-        signin::PrimaryAccountMutator::ClearAccountsAction::kKeepAll,
-        RemoveAccountExpectation::kKeepAll);
-  }
-}
-
 // Test that ClearPrimaryAccount(...) with ClearAccountTokensAction::kRemoveAll
 // remove all tokens, independently of the account consistency method.
 TEST_F(PrimaryAccountMutatorTest, ClearPrimaryAccount_RemoveAll) {
diff --git a/components/site_isolation/DIR_METADATA b/components/site_isolation/DIR_METADATA
new file mode 100644
index 0000000..1ffb19b
--- /dev/null
+++ b/components/site_isolation/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>Sandbox>SiteIsolation"
+}
diff --git a/components/site_isolation/OWNERS b/components/site_isolation/OWNERS
index ccf5c29..36c7e5a 100644
--- a/components/site_isolation/OWNERS
+++ b/components/site_isolation/OWNERS
@@ -2,5 +2,3 @@
 creis@chromium.org
 lukasza@chromium.org
 nasko@chromium.org
-
-# COMPONENT: Internals>Sandbox>SiteIsolation
diff --git a/components/soda/DIR_METADATA b/components/soda/DIR_METADATA
new file mode 100644
index 0000000..6667e7f
--- /dev/null
+++ b/components/soda/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>Media"
+}
diff --git a/components/soda/OWNERS b/components/soda/OWNERS
index d21dfa0..9d6ce60 100644
--- a/components/soda/OWNERS
+++ b/components/soda/OWNERS
@@ -1,4 +1,3 @@
-# COMPONENT: Internals>Media
 
 evliu@google.com
 beccahughes@chromium.org
diff --git a/components/spellcheck/DIR_METADATA b/components/spellcheck/DIR_METADATA
new file mode 100644
index 0000000..49408cf
--- /dev/null
+++ b/components/spellcheck/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "UI>Browser>Spellcheck"
+}
+
+team_email: "language@chromium.org"
diff --git a/components/spellcheck/OWNERS b/components/spellcheck/OWNERS
index 3d17b34..03f054d 100644
--- a/components/spellcheck/OWNERS
+++ b/components/spellcheck/OWNERS
@@ -9,6 +9,3 @@
 
 # Android, component, refactoring
 timvolodine@chromium.org
-
-# TEAM: language@chromium.org
-# COMPONENT: UI>Browser>Spellcheck
diff --git a/components/sqlite_proto/DIR_METADATA b/components/sqlite_proto/DIR_METADATA
new file mode 100644
index 0000000..c9091f0
--- /dev/null
+++ b/components/sqlite_proto/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>Storage"
+}
diff --git a/components/sqlite_proto/OWNERS b/components/sqlite_proto/OWNERS
index f8dc556..4dc72e3d 100644
--- a/components/sqlite_proto/OWNERS
+++ b/components/sqlite_proto/OWNERS
@@ -1,4 +1,3 @@
-# COMPONENT: Internals>Storage
 pasko@chromium.org
 lizeb@chromium.org
 alexilin@chromium.org
diff --git a/components/ssl_errors/DIR_METADATA b/components/ssl_errors/DIR_METADATA
new file mode 100644
index 0000000..cd27c405
--- /dev/null
+++ b/components/ssl_errors/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "UI>Browser>Interstitials"
+}
+
+team_email: "security-enamel@chromium.org"
diff --git a/components/ssl_errors/OWNERS b/components/ssl_errors/OWNERS
index 62bf9b3..756eae9 100644
--- a/components/ssl_errors/OWNERS
+++ b/components/ssl_errors/OWNERS
@@ -4,6 +4,3 @@
 felt@chromium.org
 meacer@chromium.org
 rsleevi@chromium.org
-
-# TEAM: security-enamel@chromium.org
-# COMPONENT: UI>Browser>Interstitials
diff --git a/components/ssl_errors_strings_grdp/DIR_METADATA b/components/ssl_errors_strings_grdp/DIR_METADATA
new file mode 100644
index 0000000..b302215
--- /dev/null
+++ b/components/ssl_errors_strings_grdp/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>Interstitials"
+}
diff --git a/components/ssl_errors_strings_grdp/OWNERS b/components/ssl_errors_strings_grdp/OWNERS
index 43af85e..877ebf5a 100644
--- a/components/ssl_errors_strings_grdp/OWNERS
+++ b/components/ssl_errors_strings_grdp/OWNERS
@@ -1,2 +1 @@
 file://components/ssl_errors/OWNERS
-# COMPONENT: UI>Browser>Interstitials
diff --git a/components/startup_metric_utils/DIR_METADATA b/components/startup_metric_utils/DIR_METADATA
new file mode 100644
index 0000000..21c44628
--- /dev/null
+++ b/components/startup_metric_utils/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Internals>Metrics"
+}
+
+team_email: "catan-team@chromium.org"
diff --git a/components/startup_metric_utils/OWNERS b/components/startup_metric_utils/OWNERS
index 32d1ee3c..711005f 100644
--- a/components/startup_metric_utils/OWNERS
+++ b/components/startup_metric_utils/OWNERS
@@ -2,5 +2,3 @@
 
 # To increase bus factor but prefer above OWNERS :).
 gab@chromium.org
-# COMPONENT: Internals>Metrics
-# TEAM: catan-team@chromium.org
diff --git a/components/storage_monitor/DIR_METADATA b/components/storage_monitor/DIR_METADATA
new file mode 100644
index 0000000..5b8d7cd
--- /dev/null
+++ b/components/storage_monitor/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Platform>Apps>FileManager"
+}
diff --git a/components/storage_monitor/OWNERS b/components/storage_monitor/OWNERS
index ff7f764..ed5b39e3 100644
--- a/components/storage_monitor/OWNERS
+++ b/components/storage_monitor/OWNERS
@@ -1,3 +1,2 @@
 thestig@chromium.org
 tommycli@chromium.org
-# COMPONENT: Platform>Apps>FileManager
diff --git a/components/strictmode/DIR_METADATA b/components/strictmode/DIR_METADATA
new file mode 100644
index 0000000..a750913
--- /dev/null
+++ b/components/strictmode/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Build"
+}
diff --git a/components/strictmode/OWNERS b/components/strictmode/OWNERS
index 29db243..0d5a3f25 100644
--- a/components/strictmode/OWNERS
+++ b/components/strictmode/OWNERS
@@ -1,3 +1 @@
 file://build/config/android/OWNERS
-
-# COMPONENT: Build
diff --git a/components/strings/DIR_METADATA b/components/strings/DIR_METADATA
new file mode 100644
index 0000000..14b5edb
--- /dev/null
+++ b/components/strings/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals"
+}
diff --git a/components/strings/OWNERS b/components/strings/OWNERS
index d41af37..2f13f5b 100644
--- a/components/strings/OWNERS
+++ b/components/strings/OWNERS
@@ -3,5 +3,3 @@
 # be discussed with blink-api-owners-discuss@ first or go through the
 # official Blink launch process.
 per-file components_locale_settings_*.xtb=file://third_party/blink/API_OWNERS
-
-# COMPONENT: Internals
diff --git a/components/subresource_filter/DIR_METADATA b/components/subresource_filter/DIR_METADATA
new file mode 100644
index 0000000..352eefc
--- /dev/null
+++ b/components/subresource_filter/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>AdFilter"
+}
diff --git a/components/subresource_filter/OWNERS b/components/subresource_filter/OWNERS
index 090edda5..4284fde4 100644
--- a/components/subresource_filter/OWNERS
+++ b/components/subresource_filter/OWNERS
@@ -1,4 +1,2 @@
 csharrison@chromium.org
 jkarlin@chromium.org
-
-# COMPONENT: UI>Browser>AdFilter
diff --git a/components/suggestions/DIR_METADATA b/components/suggestions/DIR_METADATA
new file mode 100644
index 0000000..1ee6aef
--- /dev/null
+++ b/components/suggestions/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "UI>Browser>NewTabPage"
+}
+
+team_email: "ntp-dev@chromium.org"
diff --git a/components/suggestions/OWNERS b/components/suggestions/OWNERS
index e3a7435..2bbc81a 100644
--- a/components/suggestions/OWNERS
+++ b/components/suggestions/OWNERS
@@ -1,6 +1,3 @@
 mahmadi@chromium.org
 tiborg@chromium.org
 treib@chromium.org
-
-# TEAM: ntp-dev@chromium.org
-# COMPONENT: UI>Browser>NewTabPage
diff --git a/components/vector_icons/BUILD.gn b/components/vector_icons/BUILD.gn
index c5e534c..9eb282e 100644
--- a/components/vector_icons/BUILD.gn
+++ b/components/vector_icons/BUILD.gn
@@ -46,6 +46,8 @@
     "insert_drive_file_outline.icon",
     "launch.icon",
     "lightbulb_outline.icon",
+    "live_caption_off.icon",
+    "live_caption_on.icon",
     "location_on.icon",
     "lock.icon",
     "media_next_track.icon",
diff --git a/components/vector_icons/live_caption_off.icon b/components/vector_icons/live_caption_off.icon
new file mode 100644
index 0000000..7281f9794
--- /dev/null
+++ b/components/vector_icons/live_caption_off.icon
@@ -0,0 +1,56 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 3.5f, 4,
+H_LINE_TO, 4,
+R_LINE_TO, 2, 2,
+H_LINE_TO, 4,
+R_V_LINE_TO, 8,
+R_H_LINE_TO, 10,
+R_LINE_TO, 2, 2,
+H_LINE_TO, 3.5f,
+ARC_TO, 1.5f, 1.5f, 0, 0, 1, 2, 14.5f,
+R_V_LINE_TO, -9,
+ARC_TO, 1.5f, 1.5f, 0, 0, 1, 3.5f, 4,
+CLOSE,
+MOVE_TO, 9, 10,
+V_LINE_TO, 9,
+R_LINE_TO, 1, 1,
+H_LINE_TO, 9,
+CLOSE,
+R_MOVE_TO, 6, -2,
+R_H_LINE_TO, -4.17f,
+R_LINE_TO, 2, 2,
+H_LINE_TO, 15,
+V_LINE_TO, 8,
+CLOSE,
+R_MOVE_TO, 1, -2,
+R_V_LINE_TO, 7.17f,
+R_LINE_TO, 1.89f, 1.89f,
+R_CUBIC_TO, 0.07f, -0.17f, 0.11f, -0.36f, 0.11f, -0.56f,
+R_V_LINE_TO, -9,
+ARC_TO, 1.5f, 1.5f, 0, 0, 0, 16.5f, 4,
+H_LINE_TO, 6.83f,
+R_LINE_TO, 2, 2,
+H_LINE_TO, 16,
+CLOSE,
+MOVE_TO, 5, 8,
+R_H_LINE_TO, 3,
+R_V_LINE_TO, 2,
+H_LINE_TO, 5,
+V_LINE_TO, 8,
+CLOSE,
+R_MOVE_TO, 6, 3,
+R_V_LINE_TO, 2,
+H_LINE_TO, 5,
+R_V_LINE_TO, -2,
+R_H_LINE_TO, 6,
+CLOSE,
+NEW_PATH,
+MOVE_TO, 1, 3,
+R_LINE_TO, 1.41f, -1.41f,
+R_LINE_TO, 15.56f, 15.56f,
+R_LINE_TO, -1.41f, 1.41f,
+CLOSE
diff --git a/components/vector_icons/live_caption_on.icon b/components/vector_icons/live_caption_on.icon
new file mode 100644
index 0000000..28ea861
--- /dev/null
+++ b/components/vector_icons/live_caption_on.icon
@@ -0,0 +1,45 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 2, 5.5f,
+ARC_TO, 1.5f, 1.5f, 0, 0, 1, 3.5f, 4,
+R_H_LINE_TO, 13,
+ARC_TO, 1.5f, 1.5f, 0, 0, 1, 18, 5.5f,
+R_V_LINE_TO, 9,
+R_ARC_TO, 1.5f, 1.5f, 0, 0, 1, -1.5f, 1.5f,
+R_H_LINE_TO, -13,
+ARC_TO, 1.5f, 1.5f, 0, 0, 1, 2, 14.5f,
+R_V_LINE_TO, -9,
+CLOSE,
+MOVE_TO, 4, 6,
+R_H_LINE_TO, 12,
+R_V_LINE_TO, 8,
+H_LINE_TO, 4,
+V_LINE_TO, 6,
+CLOSE,
+R_MOVE_TO, 1, 2,
+R_H_LINE_TO, 4,
+R_V_LINE_TO, 2,
+H_LINE_TO, 5,
+V_LINE_TO, 8,
+CLOSE,
+R_MOVE_TO, 0, 3,
+R_H_LINE_TO, 7,
+R_V_LINE_TO, 2,
+H_LINE_TO, 5,
+R_V_LINE_TO, -2,
+CLOSE,
+R_MOVE_TO, 10, 0,
+R_H_LINE_TO, -2,
+R_V_LINE_TO, 2,
+R_H_LINE_TO, 2,
+R_V_LINE_TO, -2,
+CLOSE,
+R_MOVE_TO, -5, -3,
+R_H_LINE_TO, 5,
+R_V_LINE_TO, 2,
+R_H_LINE_TO, -5,
+V_LINE_TO, 8,
+CLOSE
diff --git a/components/viz/DIR_METADATA b/components/viz/DIR_METADATA
new file mode 100644
index 0000000..f7e4412
--- /dev/null
+++ b/components/viz/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Internals>Compositing"
+}
+
+team_email: "graphics-dev@chromium.org"
diff --git a/components/viz/OWNERS b/components/viz/OWNERS
index b9559dfa..13c6cfe 100644
--- a/components/viz/OWNERS
+++ b/components/viz/OWNERS
@@ -54,6 +54,3 @@
 danakj@chromium.org
 vmpstr@chromium.org
 kylechar@chromium.org
-
-# TEAM: graphics-dev@chromium.org
-# COMPONENT: Internals>Compositing
diff --git a/components/viz/common/BUILD.gn b/components/viz/common/BUILD.gn
index 55a38b9d..8190ffb 100644
--- a/components/viz/common/BUILD.gn
+++ b/components/viz/common/BUILD.gn
@@ -196,6 +196,8 @@
     "quads/compositor_frame.h",
     "quads/compositor_frame_metadata.cc",
     "quads/compositor_frame_metadata.h",
+    "quads/compositor_frame_transition_directive.cc",
+    "quads/compositor_frame_transition_directive.h",
     "quads/compositor_render_pass.cc",
     "quads/compositor_render_pass.h",
     "quads/compositor_render_pass_draw_quad.cc",
@@ -353,6 +355,7 @@
     "frame_sinks/copy_output_util_unittest.cc",
     "frame_sinks/delay_based_time_source_unittest.cc",
     "gpu/context_cache_controller_unittest.cc",
+    "quads/compositor_frame_transition_directive_unittest.cc",
     "quads/compositor_render_pass_unittest.cc",
     "quads/draw_quad_unittest.cc",
     "quads/render_pass_io_unittest.cc",
diff --git a/components/viz/common/gpu/metal_api_proxy.h b/components/viz/common/gpu/metal_api_proxy.h
index c32a55c..7d717a2 100644
--- a/components/viz/common/gpu/metal_api_proxy.h
+++ b/components/viz/common/gpu/metal_api_proxy.h
@@ -9,7 +9,6 @@
 #include <string>
 
 #import <Metal/Metal.h>
-#include <os/availability.h>
 
 #include "base/mac/scoped_nsobject.h"
 
@@ -17,12 +16,11 @@
 class ProgressReporter;
 }  // namespace gl
 
-class API_AVAILABLE(macos(10.11)) MTLLibraryCache;
+class MTLLibraryCache;
 
 // The MTLDeviceProxy wraps all calls to an MTLDevice. It reports progress
 // to the GPU watchdog to prevent the watchdog from killing the GPU process
 // when progress is being made.
-API_AVAILABLE(macos(10.11))
 @interface MTLDeviceProxy : NSObject <MTLDevice> {
   base::scoped_nsprotocol<id<MTLDevice>> _device;
 
diff --git a/components/viz/common/gpu/metal_api_proxy.mm b/components/viz/common/gpu/metal_api_proxy.mm
index a6df2c7..e8e73a18 100644
--- a/components/viz/common/gpu/metal_api_proxy.mm
+++ b/components/viz/common/gpu/metal_api_proxy.mm
@@ -29,8 +29,7 @@
 // newRenderPipelineStateWithDescriptor:]. The completion handler may be called
 // on another thread, so all members are protected by a lock. Accessed via
 // scoped_refptr to ensure that it exists until its last accessor is gone.
-class API_AVAILABLE(macos(10.11)) AsyncMetalState
-    : public base::RefCountedThreadSafe<AsyncMetalState> {
+class AsyncMetalState : public base::RefCountedThreadSafe<AsyncMetalState> {
  public:
   AsyncMetalState() : condition_variable(&lock) {}
 
@@ -52,12 +51,11 @@
   ~AsyncMetalState() { DCHECK(has_result); }
 };
 
-id<MTLLibrary> API_AVAILABLE(macos(10.11))
-    NewLibraryWithRetry(id<MTLDevice> device,
-                        NSString* source,
-                        MTLCompileOptions* options,
-                        __autoreleasing NSError** error,
-                        gl::ProgressReporter* progress_reporter) {
+id<MTLLibrary> NewLibraryWithRetry(id<MTLDevice> device,
+                                   NSString* source,
+                                   MTLCompileOptions* options,
+                                   __autoreleasing NSError** error,
+                                   gl::ProgressReporter* progress_reporter) {
   SCOPED_UMA_HISTOGRAM_TIMER("Gpu.MetalProxy.NewLibraryTime");
   const base::TimeTicks start_time = base::TimeTicks::Now();
   auto state = base::MakeRefCounted<AsyncMetalState>();
@@ -99,11 +97,11 @@
   }
 }
 
-id<MTLRenderPipelineState> API_AVAILABLE(macos(10.11))
-    NewRenderPipelineStateWithRetry(id<MTLDevice> device,
-                                    MTLRenderPipelineDescriptor* descriptor,
-                                    __autoreleasing NSError** error,
-                                    gl::ProgressReporter* progress_reporter) {
+id<MTLRenderPipelineState> NewRenderPipelineStateWithRetry(
+    id<MTLDevice> device,
+    MTLRenderPipelineDescriptor* descriptor,
+    __autoreleasing NSError** error,
+    gl::ProgressReporter* progress_reporter) {
   // This function is almost-identical to the above NewLibraryWithRetry. See
   // comments in that function.
   SCOPED_UMA_HISTOGRAM_TIMER("Gpu.MetalProxy.NewRenderPipelineStateTime");
@@ -147,7 +145,7 @@
 // to hangs. Should this significantly help the situation, a more robust (and
 // not indefinitely-growing) cache will be added either here or in Skia.
 // https://crbug.com/974219
-class API_AVAILABLE(macos(10.11)) MTLLibraryCache {
+class MTLLibraryCache {
  public:
   MTLLibraryCache() = default;
   ~MTLLibraryCache() = default;
diff --git a/components/viz/common/gpu/metal_context_provider.mm b/components/viz/common/gpu/metal_context_provider.mm
index f5a0bacb..5ffc304 100644
--- a/components/viz/common/gpu/metal_context_provider.mm
+++ b/components/viz/common/gpu/metal_context_provider.mm
@@ -23,8 +23,7 @@
 
 namespace {
 
-struct API_AVAILABLE(macos(10.11)) MetalContextProviderImpl
-    : public MetalContextProvider {
+struct MetalContextProviderImpl : public MetalContextProvider {
  public:
   explicit MetalContextProviderImpl(id<MTLDevice> device,
                                     const GrContextOptions& context_options) {
@@ -59,20 +58,15 @@
 // static
 std::unique_ptr<MetalContextProvider> MetalContextProvider::Create(
     const GrContextOptions& context_options) {
-  if (@available(macOS 10.11, *)) {
-    // First attempt to find a low power device to use.
-    base::scoped_nsprotocol<id<MTLDevice>> device_to_use(
-        metal::CreateDefaultDevice());
-    if (!device_to_use) {
-      DLOG(ERROR) << "Failed to find MTLDevice.";
-      return nullptr;
-    }
-    return std::make_unique<MetalContextProviderImpl>(device_to_use.get(),
-                                                      context_options);
+  // First attempt to find a low power device to use.
+  base::scoped_nsprotocol<id<MTLDevice>> device_to_use(
+      metal::CreateDefaultDevice());
+  if (!device_to_use) {
+    DLOG(ERROR) << "Failed to find MTLDevice.";
+    return nullptr;
   }
-  // If no device was found, or if the macOS version is too old for Metal,
-  // return no context provider.
-  return nullptr;
+  return std::make_unique<MetalContextProviderImpl>(device_to_use.get(),
+                                                    context_options);
 }
 
 }  // namespace viz
diff --git a/components/viz/common/quads/compositor_frame_transition_directive.cc b/components/viz/common/quads/compositor_frame_transition_directive.cc
new file mode 100644
index 0000000..4fcf676b
--- /dev/null
+++ b/components/viz/common/quads/compositor_frame_transition_directive.cc
@@ -0,0 +1,25 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/viz/common/quads/compositor_frame_transition_directive.h"
+
+#include "base/time/time.h"
+
+namespace viz {
+
+constexpr base::TimeDelta CompositorFrameTransitionDirective::kMaxDuration;
+
+CompositorFrameTransitionDirective::CompositorFrameTransitionDirective(
+    uint32_t sequence_id,
+    Type type,
+    Effect effect,
+    base::TimeDelta duration)
+    : sequence_id_(sequence_id),
+      type_(type),
+      effect_(effect),
+      duration_(duration) {
+  DCHECK_LE(duration_, kMaxDuration);
+}
+
+}  // namespace viz
diff --git a/components/viz/common/quads/compositor_frame_transition_directive.h b/components/viz/common/quads/compositor_frame_transition_directive.h
new file mode 100644
index 0000000..26a7311
--- /dev/null
+++ b/components/viz/common/quads/compositor_frame_transition_directive.h
@@ -0,0 +1,82 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_VIZ_COMMON_QUADS_COMPOSITOR_FRAME_TRANSITION_DIRECTIVE_H_
+#define COMPONENTS_VIZ_COMMON_QUADS_COMPOSITOR_FRAME_TRANSITION_DIRECTIVE_H_
+
+#include "base/time/time.h"
+#include "components/viz/common/viz_common_export.h"
+
+namespace viz {
+
+// This is a transition directive that can be associcated with a compositor
+// frame. The intent is to be able to animate a compositor frame into the right
+// place instead of simply drawing the final result at the final destination.
+// This is used by a JavaScript-exposed document transitions API. See
+// third_party/blink/renderer/core/document_transition/README.md for more
+// information.
+class VIZ_COMMON_EXPORT CompositorFrameTransitionDirective {
+ public:
+  // What is the directive?
+  // - Save means that the currently submitted frame will be used in the future
+  //   as the source frame of the animation.
+  // - Animate means that this frame should be used as a (new) destination frame
+  //   of the animation, using the previously saved frame as the source.
+  enum class Type { kSave, kAnimate };
+
+  // The type of an effect that should be used in the animation.
+  enum class Effect {
+    kNone,
+    kCoverDown,
+    kCoverLeft,
+    kCoverRight,
+    kCoverUp,
+    kExplode,
+    kFade,
+    kImplode,
+    kRevealDown,
+    kRevealLeft,
+    kRevealRight,
+    kRevealUp
+  };
+
+  // This is the maximum allowable transition duration.
+  static constexpr base::TimeDelta kMaxDuration =
+      base::TimeDelta::FromMilliseconds(500);
+
+  // Constructs a new directive. Note that if type is `kSave`, the effect and
+  // duration should be specified for a desired effect. These are ignored for
+  // the `kAnimate` type.
+  CompositorFrameTransitionDirective(uint32_t sequence_id,
+                                     Type type,
+                                     Effect effect = Effect::kNone,
+                                     base::TimeDelta duration = {});
+
+  // A monotonically increasing sequence_id for a given communication channel
+  // (i.e. surface). This is used to distinguish new directives from directives
+  // that have already been processed.
+  uint32_t sequence_id() const { return sequence_id_; }
+
+  // The type of this directive.
+  Type type() const { return type_; }
+
+  // The duration of the animation. Note that this is at most kMaxDuration.
+  base::TimeDelta duration() const { return duration_; }
+
+  // The effect for the transition.
+  Effect effect() const { return effect_; }
+
+ private:
+  uint32_t sequence_id_;
+
+  Type type_;
+
+  Effect effect_;
+
+  base::TimeDelta duration_;
+};
+
+}  // namespace viz
+
+#endif  // COMPONENTS_VIZ_COMMON_QUADS_COMPOSITOR_FRAME_TRANSITION_DIRECTIVE_H_
diff --git a/components/viz/common/quads/compositor_frame_transition_directive_unittest.cc b/components/viz/common/quads/compositor_frame_transition_directive_unittest.cc
new file mode 100644
index 0000000..1df5f7bd
--- /dev/null
+++ b/components/viz/common/quads/compositor_frame_transition_directive_unittest.cc
@@ -0,0 +1,32 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/viz/common/quads/compositor_frame_transition_directive.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace viz {
+namespace {
+
+using Effect = CompositorFrameTransitionDirective::Effect;
+using Type = CompositorFrameTransitionDirective::Type;
+
+TEST(CompositorFrameTransitionDirective, GettersReflectParameters) {
+  CompositorFrameTransitionDirective save_directive(
+      1u, Type::kSave, Effect::kCoverLeft,
+      base::TimeDelta::FromMilliseconds(100));
+
+  EXPECT_EQ(1u, save_directive.sequence_id());
+  EXPECT_EQ(Type::kSave, save_directive.type());
+  EXPECT_EQ(Effect::kCoverLeft, save_directive.effect());
+  EXPECT_EQ(base::TimeDelta::FromMilliseconds(100), save_directive.duration());
+
+  CompositorFrameTransitionDirective animate_directive(2, Type::kAnimate);
+
+  EXPECT_EQ(2u, animate_directive.sequence_id());
+  EXPECT_EQ(Type::kAnimate, animate_directive.type());
+}
+
+}  // namespace
+}  // namespace viz
diff --git a/components/viz/common/resources/resource_format_utils_mac.mm b/components/viz/common/resources/resource_format_utils_mac.mm
index 5a095e7..41091d71 100644
--- a/components/viz/common/resources/resource_format_utils_mac.mm
+++ b/components/viz/common/resources/resource_format_utils_mac.mm
@@ -11,30 +11,27 @@
 namespace viz {
 
 unsigned int ToMTLPixelFormat(ResourceFormat format) {
-  if (@available(macOS 10.11, *)) {
-    MTLPixelFormat mtl_pixel_format = MTLPixelFormatInvalid;
-    switch (format) {
-      case RED_8:
-      case ALPHA_8:
-      case LUMINANCE_8:
-        mtl_pixel_format = MTLPixelFormatR8Unorm;
-        break;
-      case RG_88:
-        mtl_pixel_format = MTLPixelFormatRG8Unorm;
-        break;
-      case RGBA_8888:
-        mtl_pixel_format = MTLPixelFormatRGBA8Unorm;
-        break;
-      case BGRA_8888:
-        mtl_pixel_format = MTLPixelFormatBGRA8Unorm;
-        break;
-      default:
-        DLOG(ERROR) << "Invalid Metal pixel format.";
-        break;
-    }
-    return static_cast<unsigned int>(mtl_pixel_format);
+  MTLPixelFormat mtl_pixel_format = MTLPixelFormatInvalid;
+  switch (format) {
+    case RED_8:
+    case ALPHA_8:
+    case LUMINANCE_8:
+      mtl_pixel_format = MTLPixelFormatR8Unorm;
+      break;
+    case RG_88:
+      mtl_pixel_format = MTLPixelFormatRG8Unorm;
+      break;
+    case RGBA_8888:
+      mtl_pixel_format = MTLPixelFormatRGBA8Unorm;
+      break;
+    case BGRA_8888:
+      mtl_pixel_format = MTLPixelFormatBGRA8Unorm;
+      break;
+    default:
+      DLOG(ERROR) << "Invalid Metal pixel format.";
+      break;
   }
-  return 0;
+  return static_cast<unsigned int>(mtl_pixel_format);
 }
 
 }  // namespace viz
diff --git a/components/viz/service/frame_sinks/video_capture/DIR_METADATA b/components/viz/service/frame_sinks/video_capture/DIR_METADATA
new file mode 100644
index 0000000..d0f2f68a
--- /dev/null
+++ b/components/viz/service/frame_sinks/video_capture/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>Media>ScreenCapture"
+}
diff --git a/components/viz/service/frame_sinks/video_capture/OWNERS b/components/viz/service/frame_sinks/video_capture/OWNERS
index 12fd84a..90320c9 100644
--- a/components/viz/service/frame_sinks/video_capture/OWNERS
+++ b/components/viz/service/frame_sinks/video_capture/OWNERS
@@ -1,4 +1,2 @@
 miu@chromium.org
 mfoltz@chromium.org
-
-# COMPONENT: Internals>Media>ScreenCapture
diff --git a/components/viz/service/gl/DIR_METADATA b/components/viz/service/gl/DIR_METADATA
new file mode 100644
index 0000000..d7359ed
--- /dev/null
+++ b/components/viz/service/gl/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>GPU>Internals"
+}
diff --git a/components/viz/service/gl/OWNERS b/components/viz/service/gl/OWNERS
index 2a2fdb63..f18fedb 100644
--- a/components/viz/service/gl/OWNERS
+++ b/components/viz/service/gl/OWNERS
@@ -1,4 +1,2 @@
 kbr@chromium.org
 file://gpu/OWNERS
-
-# COMPONENT: Internals>GPU>Internals
diff --git a/components/web_cache/DIR_METADATA b/components/web_cache/DIR_METADATA
new file mode 100644
index 0000000..14b5edb
--- /dev/null
+++ b/components/web_cache/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals"
+}
diff --git a/components/web_cache/OWNERS b/components/web_cache/OWNERS
index e8a333cd..3463baf5 100644
--- a/components/web_cache/OWNERS
+++ b/components/web_cache/OWNERS
@@ -3,4 +3,3 @@
 sky@chromium.org
 thakis@chromium.org
 thestig@chromium.org
-# COMPONENT: Internals
diff --git a/components/web_modal/DIR_METADATA b/components/web_modal/DIR_METADATA
new file mode 100644
index 0000000..69976b6
--- /dev/null
+++ b/components/web_modal/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>Core"
+}
diff --git a/components/web_modal/OWNERS b/components/web_modal/OWNERS
index f8ca2ec..12a9b09 100644
--- a/components/web_modal/OWNERS
+++ b/components/web_modal/OWNERS
@@ -1,2 +1 @@
 wittman@chromium.org
-# COMPONENT: UI>Browser>Core
diff --git a/components/web_package/DIR_METADATA b/components/web_package/DIR_METADATA
new file mode 100644
index 0000000..2352b85e
--- /dev/null
+++ b/components/web_package/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Blink>Loader>WebPackaging"
+}
+
+team_email: "webpackage-dev@chromium.org"
diff --git a/components/web_package/OWNERS b/components/web_package/OWNERS
index 25537e1..0addbbd1 100644
--- a/components/web_package/OWNERS
+++ b/components/web_package/OWNERS
@@ -1,6 +1,3 @@
 horo@chromium.org
 kinuko@chromium.org
 ksakamoto@chromium.org
-
-# COMPONENT: Blink>Loader>WebPackaging
-# TEAM: webpackage-dev@chromium.org
diff --git a/components/web_resource/DIR_METADATA b/components/web_resource/DIR_METADATA
new file mode 100644
index 0000000..d08126ac
--- /dev/null
+++ b/components/web_resource/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Shell"
+}
diff --git a/components/web_resource/OWNERS b/components/web_resource/OWNERS
index d029a52..d0a6461 100644
--- a/components/web_resource/OWNERS
+++ b/components/web_resource/OWNERS
@@ -4,4 +4,3 @@
 # For ResourceRequestAllowedNotifier and EulaAcceptedNotifier:
 per-file eula_accepted_notifier*=file://components/variations/OWNERS
 per-file resource_request_allowed_notifier*=file://components/variations/OWNERS
-# COMPONENT: UI>Shell
diff --git a/components/webapk/DIR_METADATA b/components/webapk/DIR_METADATA
new file mode 100644
index 0000000..1a508bb4
--- /dev/null
+++ b/components/webapk/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Mobile>WebAPKs"
+}
+
+team_email: "webapk-team@chromium.org"
diff --git a/components/webapk/OWNERS b/components/webapk/OWNERS
index 195458c..b7e271d 100644
--- a/components/webapk/OWNERS
+++ b/components/webapk/OWNERS
@@ -1,6 +1,3 @@
 hanxi@chromium.org
 pkotwicz@chromium.org
 yfriedman@chromium.org
-
-# TEAM: webapk-team@chromium.org
-# COMPONENT: Mobile>WebAPKs
diff --git a/components/webcrypto/DIR_METADATA b/components/webcrypto/DIR_METADATA
new file mode 100644
index 0000000..86d9592
--- /dev/null
+++ b/components/webcrypto/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>WebCrypto"
+}
diff --git a/components/webcrypto/OWNERS b/components/webcrypto/OWNERS
index 36ea0ea..81033345 100644
--- a/components/webcrypto/OWNERS
+++ b/components/webcrypto/OWNERS
@@ -1,3 +1 @@
 rsleevi@chromium.org
-
-# COMPONENT: Blink>WebCrypto
diff --git a/components/webdata/DIR_METADATA b/components/webdata/DIR_METADATA
new file mode 100644
index 0000000..d9fe49da
--- /dev/null
+++ b/components/webdata/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Internals"
+}
+
+team_email: "chromium-reviews@chromium.org"
diff --git a/components/webdata/OWNERS b/components/webdata/OWNERS
index 7aa99e6..1310ba4c 100644
--- a/components/webdata/OWNERS
+++ b/components/webdata/OWNERS
@@ -3,6 +3,3 @@
 
 # For sqlite stuff:
 pwnall@chromium.org
-
-# COMPONENT: Internals
-# TEAM: chromium-reviews@chromium.org
diff --git a/components/webdata_services/DIR_METADATA b/components/webdata_services/DIR_METADATA
new file mode 100644
index 0000000..d9fe49da
--- /dev/null
+++ b/components/webdata_services/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Internals"
+}
+
+team_email: "chromium-reviews@chromium.org"
diff --git a/components/webdata_services/OWNERS b/components/webdata_services/OWNERS
index 7aa99e6..1310ba4c 100644
--- a/components/webdata_services/OWNERS
+++ b/components/webdata_services/OWNERS
@@ -3,6 +3,3 @@
 
 # For sqlite stuff:
 pwnall@chromium.org
-
-# COMPONENT: Internals
-# TEAM: chromium-reviews@chromium.org
diff --git a/components/webrtc/DIR_METADATA b/components/webrtc/DIR_METADATA
new file mode 100644
index 0000000..66cc019
--- /dev/null
+++ b/components/webrtc/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>WebRTC"
+}
diff --git a/components/webrtc/OWNERS b/components/webrtc/OWNERS
index 48b19446..a129378 100644
--- a/components/webrtc/OWNERS
+++ b/components/webrtc/OWNERS
@@ -1,3 +1 @@
 file://third_party/blink/public/platform/modules/webrtc/OWNERS
-
-# COMPONENT: Blink>WebRTC
diff --git a/components/webrtc_logging/DIR_METADATA b/components/webrtc_logging/DIR_METADATA
new file mode 100644
index 0000000..44125f6
--- /dev/null
+++ b/components/webrtc_logging/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Blink>WebRTC>Tools"
+}
+
+team_email: "webrtc-dev@chromium.org"
diff --git a/components/webrtc_logging/OWNERS b/components/webrtc_logging/OWNERS
index 2046f22..b88212c 100644
--- a/components/webrtc_logging/OWNERS
+++ b/components/webrtc_logging/OWNERS
@@ -1,5 +1,2 @@
 grunell@chromium.org
 tommi@chromium.org
-
-# COMPONENT: Blink>WebRTC>Tools
-# TEAM: webrtc-dev@chromium.org
diff --git a/components/webxr/DIR_METADATA b/components/webxr/DIR_METADATA
new file mode 100644
index 0000000..743074be
--- /dev/null
+++ b/components/webxr/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Internals>XR"
+}
+
+team_email: "xr-dev@chromium.org"
diff --git a/components/webxr/OWNERS b/components/webxr/OWNERS
index ef5e626..2310121 100644
--- a/components/webxr/OWNERS
+++ b/components/webxr/OWNERS
@@ -1,5 +1,2 @@
 alcooper@chromium.org
 bialpio@chromium.org
-
-# TEAM: xr-dev@chromium.org
-# COMPONENT: Internals>XR
diff --git a/components/webxr_strings_grdp/DIR_METADATA b/components/webxr_strings_grdp/DIR_METADATA
new file mode 100644
index 0000000..d62bf7a
--- /dev/null
+++ b/components/webxr_strings_grdp/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>XR"
+}
diff --git a/components/webxr_strings_grdp/OWNERS b/components/webxr_strings_grdp/OWNERS
index 8c91bd7..d95d28c 100644
--- a/components/webxr_strings_grdp/OWNERS
+++ b/components/webxr_strings_grdp/OWNERS
@@ -1,2 +1 @@
 file://components/webxr/OWNERS
-# COMPONENT: Internals>XR
diff --git a/components/wifi/DIR_METADATA b/components/wifi/DIR_METADATA
new file mode 100644
index 0000000..709d8280
--- /dev/null
+++ b/components/wifi/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Internals>Network"
+}
+
+team_email: "net-dev@chromium.org"
diff --git a/components/wifi/OWNERS b/components/wifi/OWNERS
index 7e5ec6e..fb59c70 100644
--- a/components/wifi/OWNERS
+++ b/components/wifi/OWNERS
@@ -1,3 +1 @@
 file://net/OWNERS
-# COMPONENT: Internals>Network
-# TEAM: net-dev@chromium.org
diff --git a/components/zoom/DIR_METADATA b/components/zoom/DIR_METADATA
new file mode 100644
index 0000000..3ad212d
--- /dev/null
+++ b/components/zoom/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>Zoom"
+}
diff --git a/components/zoom/OWNERS b/components/zoom/OWNERS
index fd016d7..9e07757 100644
--- a/components/zoom/OWNERS
+++ b/components/zoom/OWNERS
@@ -1,3 +1 @@
 wjmaclean@chromium.org
-
-# COMPONENT: UI>Browser>Zoom
diff --git a/components/zucchini/DIR_METADATA b/components/zucchini/DIR_METADATA
new file mode 100644
index 0000000..03fc466
--- /dev/null
+++ b/components/zucchini/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>Installer>Diff"
+}
diff --git a/components/zucchini/OWNERS b/components/zucchini/OWNERS
index 06b665e4..1eb740b 100644
--- a/components/zucchini/OWNERS
+++ b/components/zucchini/OWNERS
@@ -2,5 +2,3 @@
 huangs@chromium.org
 grt@chromium.org
 wfh@chromium.org
-
-# COMPONENT: Internals>Installer>Diff
diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc
index aa611448..c0823fa 100644
--- a/content/app/content_main_runner_impl.cc
+++ b/content/app/content_main_runner_impl.cc
@@ -170,6 +170,10 @@
 #include "content/common/android/cpu_affinity.h"
 #endif
 
+#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
+#include "base/allocator/partition_allocator/thread_cache.h"
+#endif
+
 namespace content {
 extern int GpuMain(const content::MainFunctionParams&);
 #if BUILDFLAG(ENABLE_PLUGINS)
@@ -1009,6 +1013,10 @@
   // Enable PCScan once we are certain that FeatureList was initialized.
   EnablePCScanForMallocPartitionsIfNeeded();
 
+#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
+  base::internal::ThreadCacheRegistry::Instance().StartPeriodicPurge();
+#endif
+
   if (should_start_minimal_browser) {
     DVLOG(0) << "Chrome is running in minimal browser mode.";
     return -1;
diff --git a/content/browser/file_system_access/file_system_chooser.cc b/content/browser/file_system_access/file_system_chooser.cc
index 95dbf69..41f7297 100644
--- a/content/browser/file_system_access/file_system_chooser.cc
+++ b/content/browser/file_system_access/file_system_chooser.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
+#include "base/i18n/file_util_icu.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
@@ -47,6 +48,51 @@
       "NativeFileSystemAPI.FileChooserResult." + TypeToString(type), count);
 }
 
+// Similar to base::FilePath::FinalExtension, but operates with the
+// understanding that the StringType passed in is an extension, not a path.
+// Returns the last extension without a leading ".".
+base::FilePath::StringType GetLastExtension(
+    const base::FilePath::StringType& extension) {
+  auto last_separator = extension.rfind(base::FilePath::kExtensionSeparator);
+  return (last_separator != base::FilePath::StringType::npos)
+             ? extension.substr(last_separator + 1)
+             : extension;
+}
+
+// Returns whether the specified extension receives special handling by the
+// Windows shell.
+bool IsShellIntegratedExtension(const base::FilePath::StringType& extension) {
+  // TODO(https://crbug.com/1154757): Figure out some way to unify this with
+  // net::IsSafePortablePathComponent, with the result probably ending up in
+  // base/i18n/file_util_icu.h.
+  base::FilePath::StringType extension_lower = base::ToLowerASCII(extension);
+
+  // .lnk files may be used to execute arbitrary code (see
+  // https://nvd.nist.gov/vuln/detail/CVE-2010-2568). .local files are used by
+  // Windows to determine which DLLs to load for an application.
+  if ((extension_lower == FILE_PATH_LITERAL("local")) ||
+      (extension_lower == FILE_PATH_LITERAL("lnk")))
+    return true;
+
+  // Setting a file's extension to a CLSID may conceal its actual file type on
+  // some Windows versions (see https://nvd.nist.gov/vuln/detail/CVE-2004-0420).
+  if (!extension_lower.empty() &&
+      (extension_lower.front() == FILE_PATH_LITERAL('{')) &&
+      (extension_lower.back() == FILE_PATH_LITERAL('}')))
+    return true;
+  return false;
+}
+
+// Extension validation primarily takes place in the renderer. This checks for a
+// subset of invalid extensions in the event the renderer is compromised.
+bool IsInvalidExtension(base::FilePath::StringType& extension) {
+  std::string component8 = base::FilePath(extension).AsUTF8Unsafe();
+  auto extension16 = base::UTF8ToUTF16(component8.c_str());
+
+  return !base::i18n::IsFilenameLegal(extension16) ||
+         IsShellIntegratedExtension(GetLastExtension(extension));
+}
+
 // Converts the accepted mime types and extensions from |option| into a list
 // of just extensions to be passed to the file dialog implementation.
 // The returned list will start with all the explicit website provided
@@ -67,7 +113,8 @@
 #else
     extension = extension_string;
 #endif
-    if (extension_set.insert(extension).second) {
+    if (extension_set.insert(extension).second &&
+        !IsInvalidExtension(extension)) {
       extensions->push_back(std::move(extension));
     }
   }
@@ -76,7 +123,8 @@
     base::FilePath::StringType preferred_extension;
     if (net::GetPreferredExtensionForMimeType(mime_type,
                                               &preferred_extension)) {
-      if (extension_set.insert(preferred_extension).second) {
+      if (extension_set.insert(preferred_extension).second &&
+          !IsInvalidExtension(preferred_extension)) {
         extensions->push_back(std::move(preferred_extension));
       }
     }
@@ -86,7 +134,8 @@
     if (inner.empty())
       continue;
     for (auto& extension : inner) {
-      if (extension_set.insert(extension).second) {
+      if (extension_set.insert(extension).second &&
+          !IsInvalidExtension(extension)) {
         extensions->push_back(std::move(extension));
       }
     }
diff --git a/content/browser/file_system_access/file_system_chooser_browsertest.cc b/content/browser/file_system_access/file_system_chooser_browsertest.cc
index 7aaf0f65..8d35646 100644
--- a/content/browser/file_system_access/file_system_chooser_browsertest.cc
+++ b/content/browser/file_system_access/file_system_chooser_browsertest.cc
@@ -37,6 +37,8 @@
 using blink::mojom::PermissionStatus;
 using SensitiveDirectoryResult =
     NativeFileSystemPermissionContext::SensitiveDirectoryResult;
+using PathInfo = NativeFileSystemPermissionContext::PathInfo;
+using PathType = NativeFileSystemPermissionContext::PathType;
 
 static constexpr char kTestMountPoint[] = "testfs";
 
@@ -484,20 +486,17 @@
       .WillOnce(testing::Return(true));
 
   EXPECT_CALL(permission_context, GetLastPickedDirectory(origin))
-      .WillOnce(testing::Return(NativeFileSystemPermissionContext::PathInfo()));
+      .WillOnce(testing::Return(PathInfo()));
   EXPECT_CALL(permission_context, GetDefaultDirectory())
-      .WillOnce(testing::Return(NativeFileSystemPermissionContext::PathInfo()));
+      .WillOnce(testing::Return(PathInfo()));
   EXPECT_CALL(permission_context,
-              SetLastPickedDirectory(
-                  origin, test_dir,
-                  NativeFileSystemPermissionContext::PathType::kLocal));
+              SetLastPickedDirectory(origin, test_dir, PathType::kLocal));
 
-  EXPECT_CALL(
-      permission_context,
-      ConfirmSensitiveDirectoryAccess_(
-          origin, NativeFileSystemPermissionContext::PathType::kLocal, test_dir,
-          NativeFileSystemPermissionContext::HandleType::kDirectory, frame_id,
-          testing::_))
+  EXPECT_CALL(permission_context,
+              ConfirmSensitiveDirectoryAccess_(
+                  origin, PathType::kLocal, test_dir,
+                  NativeFileSystemPermissionContext::HandleType::kDirectory,
+                  frame_id, testing::_))
       .WillOnce(RunOnceCallback<5>(SensitiveDirectoryResult::kAllowed));
 
   EXPECT_CALL(permission_context,
@@ -560,16 +559,15 @@
       .WillOnce(testing::Return(true));
 
   EXPECT_CALL(permission_context, GetLastPickedDirectory(origin))
-      .WillOnce(testing::Return(NativeFileSystemPermissionContext::PathInfo()));
+      .WillOnce(testing::Return(PathInfo()));
   EXPECT_CALL(permission_context, GetDefaultDirectory())
-      .WillOnce(testing::Return(NativeFileSystemPermissionContext::PathInfo()));
+      .WillOnce(testing::Return(PathInfo()));
 
-  EXPECT_CALL(
-      permission_context,
-      ConfirmSensitiveDirectoryAccess_(
-          origin, NativeFileSystemPermissionContext::PathType::kLocal,
-          test_file, NativeFileSystemPermissionContext::HandleType::kFile,
-          frame_id, testing::_))
+  EXPECT_CALL(permission_context,
+              ConfirmSensitiveDirectoryAccess_(
+                  origin, PathType::kLocal, test_file,
+                  NativeFileSystemPermissionContext::HandleType::kFile,
+                  frame_id, testing::_))
       .WillOnce(RunOnceCallback<5>(SensitiveDirectoryResult::kAbort));
 
   ASSERT_TRUE(
@@ -621,16 +619,15 @@
       .WillOnce(testing::Return(true));
 
   EXPECT_CALL(permission_context, GetLastPickedDirectory(origin))
-      .WillOnce(testing::Return(NativeFileSystemPermissionContext::PathInfo()));
+      .WillOnce(testing::Return(PathInfo()));
   EXPECT_CALL(permission_context, GetDefaultDirectory())
-      .WillOnce(testing::Return(NativeFileSystemPermissionContext::PathInfo()));
+      .WillOnce(testing::Return(PathInfo()));
 
-  EXPECT_CALL(
-      permission_context,
-      ConfirmSensitiveDirectoryAccess_(
-          origin, NativeFileSystemPermissionContext::PathType::kLocal,
-          test_file, NativeFileSystemPermissionContext::HandleType::kFile,
-          frame_id, testing::_))
+  EXPECT_CALL(permission_context,
+              ConfirmSensitiveDirectoryAccess_(
+                  origin, PathType::kLocal, test_file,
+                  NativeFileSystemPermissionContext::HandleType::kFile,
+                  frame_id, testing::_))
       .WillOnce(RunOnceCallback<5>(SensitiveDirectoryResult::kAbort));
 
   ASSERT_TRUE(
@@ -707,4 +704,341 @@
       "NativeFileSystem"));
 }
 
+IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest,
+                       OpenDirectory_LastPickedDirExists) {
+  base::FilePath test_dir = CreateTestDir();
+
+  SelectFileDialogParams dialog_params;
+  ui::SelectFileDialog::SetFactory(
+      new FakeSelectFileDialogFactory({test_dir}, &dialog_params));
+
+  testing::StrictMock<MockNativeFileSystemPermissionContext> permission_context;
+  static_cast<NativeFileSystemManagerImpl*>(
+      BrowserContext::GetStoragePartition(
+          shell()->web_contents()->GetBrowserContext(),
+          shell()->web_contents()->GetSiteInstance())
+          ->GetNativeFileSystemEntryFactory())
+      ->SetPermissionContextForTesting(&permission_context);
+
+  auto read_grant = base::MakeRefCounted<
+      testing::StrictMock<MockNativeFileSystemPermissionGrant>>();
+  auto write_grant = base::MakeRefCounted<FixedNativeFileSystemPermissionGrant>(
+      PermissionStatus::GRANTED, base::FilePath());
+
+  auto origin =
+      url::Origin::Create(embedded_test_server()->GetURL("/title1.html"));
+  auto frame_id = GlobalFrameRoutingId(
+      shell()->web_contents()->GetMainFrame()->GetProcess()->GetID(),
+      shell()->web_contents()->GetMainFrame()->GetRoutingID());
+  EXPECT_CALL(permission_context, CanObtainReadPermission(origin))
+      .WillOnce(testing::Return(true));
+
+  // The last picked directory exists, so do not call GetDefaultDirectory.
+  PathInfo good_dir_info;
+  good_dir_info.path = temp_dir_.GetPath();
+
+  EXPECT_CALL(permission_context, GetLastPickedDirectory(origin))
+      .WillOnce(testing::Return(good_dir_info));
+  EXPECT_CALL(permission_context,
+              SetLastPickedDirectory(origin, test_dir, PathType::kLocal));
+
+  EXPECT_CALL(permission_context,
+              ConfirmSensitiveDirectoryAccess_(
+                  origin, PathType::kLocal, test_dir,
+                  NativeFileSystemPermissionContext::HandleType::kDirectory,
+                  frame_id, testing::_))
+      .WillOnce(RunOnceCallback<5>(SensitiveDirectoryResult::kAllowed));
+
+  EXPECT_CALL(permission_context,
+              GetReadPermissionGrant(
+                  origin, test_dir,
+                  NativeFileSystemPermissionContext::HandleType::kDirectory,
+                  NativeFileSystemPermissionContext::UserAction::kOpen))
+      .WillOnce(testing::Return(read_grant));
+  EXPECT_CALL(permission_context,
+              GetWritePermissionGrant(
+                  origin, test_dir,
+                  NativeFileSystemPermissionContext::HandleType::kDirectory,
+                  NativeFileSystemPermissionContext::UserAction::kOpen))
+      .WillOnce(testing::Return(write_grant));
+
+  EXPECT_CALL(
+      *read_grant,
+      RequestPermission_(
+          frame_id,
+          NativeFileSystemPermissionGrant::UserActivationState::kNotRequired,
+          testing::_))
+      .WillOnce(RunOnceCallback<2>(NativeFileSystemPermissionGrant::
+                                       PermissionRequestOutcome::kUserGranted));
+  EXPECT_CALL(*read_grant, GetStatus())
+      .WillRepeatedly(testing::Return(PermissionStatus::GRANTED));
+
+  ASSERT_TRUE(
+      NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
+  EXPECT_EQ(test_dir.BaseName().AsUTF8Unsafe(),
+            EvalJs(shell(),
+                   "(async () => {"
+                   "  let e = await self.showDirectoryPicker();"
+                   "  self.selected_entry = e;"
+                   "  return e.name; })()"));
+  EXPECT_EQ(ui::SelectFileDialog::SELECT_FOLDER, dialog_params.type);
+  EXPECT_EQ(good_dir_info.path, dialog_params.default_path);
+}
+
+IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest,
+                       OpenDirectory_LastPickedDirNotExists) {
+  base::FilePath test_dir = CreateTestDir();
+
+  SelectFileDialogParams dialog_params;
+  ui::SelectFileDialog::SetFactory(
+      new FakeSelectFileDialogFactory({test_dir}, &dialog_params));
+
+  testing::StrictMock<MockNativeFileSystemPermissionContext> permission_context;
+  static_cast<NativeFileSystemManagerImpl*>(
+      BrowserContext::GetStoragePartition(
+          shell()->web_contents()->GetBrowserContext(),
+          shell()->web_contents()->GetSiteInstance())
+          ->GetNativeFileSystemEntryFactory())
+      ->SetPermissionContextForTesting(&permission_context);
+
+  auto read_grant = base::MakeRefCounted<
+      testing::StrictMock<MockNativeFileSystemPermissionGrant>>();
+  auto write_grant = base::MakeRefCounted<FixedNativeFileSystemPermissionGrant>(
+      PermissionStatus::GRANTED, base::FilePath());
+
+  auto origin =
+      url::Origin::Create(embedded_test_server()->GetURL("/title1.html"));
+  auto frame_id = GlobalFrameRoutingId(
+      shell()->web_contents()->GetMainFrame()->GetProcess()->GetID(),
+      shell()->web_contents()->GetMainFrame()->GetRoutingID());
+  EXPECT_CALL(permission_context, CanObtainReadPermission(origin))
+      .WillOnce(testing::Return(true));
+
+  // The last picked directory no longer exists, so resort to showing the
+  // default directory, then set the test_file's dir as last picked.
+  PathInfo bad_dir_info;
+  bad_dir_info.path = temp_dir_.GetPath().AppendASCII("nonexistent");
+  PathInfo default_dir_info;
+  default_dir_info.path = temp_dir_.GetPath().AppendASCII("default");
+
+  EXPECT_CALL(permission_context, GetLastPickedDirectory(origin))
+      .WillOnce(testing::Return(bad_dir_info));
+  EXPECT_CALL(permission_context, GetDefaultDirectory())
+      .WillOnce(testing::Return(default_dir_info));
+  EXPECT_CALL(permission_context,
+              SetLastPickedDirectory(origin, test_dir, PathType::kLocal));
+
+  EXPECT_CALL(permission_context,
+              ConfirmSensitiveDirectoryAccess_(
+                  origin, PathType::kLocal, test_dir,
+                  NativeFileSystemPermissionContext::HandleType::kDirectory,
+                  frame_id, testing::_))
+      .WillOnce(RunOnceCallback<5>(SensitiveDirectoryResult::kAllowed));
+
+  EXPECT_CALL(permission_context,
+              GetReadPermissionGrant(
+                  origin, test_dir,
+                  NativeFileSystemPermissionContext::HandleType::kDirectory,
+                  NativeFileSystemPermissionContext::UserAction::kOpen))
+      .WillOnce(testing::Return(read_grant));
+  EXPECT_CALL(permission_context,
+              GetWritePermissionGrant(
+                  origin, test_dir,
+                  NativeFileSystemPermissionContext::HandleType::kDirectory,
+                  NativeFileSystemPermissionContext::UserAction::kOpen))
+      .WillOnce(testing::Return(write_grant));
+
+  EXPECT_CALL(
+      *read_grant,
+      RequestPermission_(
+          frame_id,
+          NativeFileSystemPermissionGrant::UserActivationState::kNotRequired,
+          testing::_))
+      .WillOnce(RunOnceCallback<2>(NativeFileSystemPermissionGrant::
+                                       PermissionRequestOutcome::kUserGranted));
+  EXPECT_CALL(*read_grant, GetStatus())
+      .WillRepeatedly(testing::Return(PermissionStatus::GRANTED));
+
+  ASSERT_TRUE(
+      NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
+  EXPECT_EQ(test_dir.BaseName().AsUTF8Unsafe(),
+            EvalJs(shell(),
+                   "(async () => {"
+                   "  let e = await self.showDirectoryPicker();"
+                   "  self.selected_entry = e;"
+                   "  return e.name; })()"));
+  EXPECT_EQ(ui::SelectFileDialog::SELECT_FOLDER, dialog_params.type);
+  EXPECT_EQ(default_dir_info.path, dialog_params.default_path);
+}
+
+IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest,
+                       OpenDirectory_LastPickedDirExistsExternal) {
+  base::FilePath test_dir = CreateTestDir();
+
+  SelectFileDialogParams dialog_params;
+  ui::SelectFileDialog::SetFactory(
+      new FakeSelectFileDialogFactory({test_dir}, &dialog_params));
+
+  testing::StrictMock<MockNativeFileSystemPermissionContext> permission_context;
+  static_cast<NativeFileSystemManagerImpl*>(
+      BrowserContext::GetStoragePartition(
+          shell()->web_contents()->GetBrowserContext(),
+          shell()->web_contents()->GetSiteInstance())
+          ->GetNativeFileSystemEntryFactory())
+      ->SetPermissionContextForTesting(&permission_context);
+
+  auto read_grant = base::MakeRefCounted<
+      testing::StrictMock<MockNativeFileSystemPermissionGrant>>();
+  auto write_grant = base::MakeRefCounted<FixedNativeFileSystemPermissionGrant>(
+      PermissionStatus::GRANTED, base::FilePath());
+
+  auto origin =
+      url::Origin::Create(embedded_test_server()->GetURL("/title1.html"));
+  auto frame_id = GlobalFrameRoutingId(
+      shell()->web_contents()->GetMainFrame()->GetProcess()->GetID(),
+      shell()->web_contents()->GetMainFrame()->GetRoutingID());
+  EXPECT_CALL(permission_context, CanObtainReadPermission(origin))
+      .WillOnce(testing::Return(true));
+
+  // The last picked directory exists, so do not call GetDefaultDirectory.
+  PathInfo good_dir_info;
+  good_dir_info.path = base::FilePath::FromUTF8Unsafe(kTestMountPoint);
+  good_dir_info.type = PathType::kExternal;
+
+  EXPECT_CALL(permission_context, GetLastPickedDirectory(origin))
+      .WillOnce(testing::Return(good_dir_info));
+  EXPECT_CALL(permission_context,
+              SetLastPickedDirectory(origin, test_dir, PathType::kLocal));
+
+  EXPECT_CALL(permission_context,
+              ConfirmSensitiveDirectoryAccess_(
+                  origin, PathType::kLocal, test_dir,
+                  NativeFileSystemPermissionContext::HandleType::kDirectory,
+                  frame_id, testing::_))
+      .WillOnce(RunOnceCallback<5>(SensitiveDirectoryResult::kAllowed));
+
+  EXPECT_CALL(permission_context,
+              GetReadPermissionGrant(
+                  origin, test_dir,
+                  NativeFileSystemPermissionContext::HandleType::kDirectory,
+                  NativeFileSystemPermissionContext::UserAction::kOpen))
+      .WillOnce(testing::Return(read_grant));
+  EXPECT_CALL(permission_context,
+              GetWritePermissionGrant(
+                  origin, test_dir,
+                  NativeFileSystemPermissionContext::HandleType::kDirectory,
+                  NativeFileSystemPermissionContext::UserAction::kOpen))
+      .WillOnce(testing::Return(write_grant));
+
+  EXPECT_CALL(
+      *read_grant,
+      RequestPermission_(
+          frame_id,
+          NativeFileSystemPermissionGrant::UserActivationState::kNotRequired,
+          testing::_))
+      .WillOnce(RunOnceCallback<2>(NativeFileSystemPermissionGrant::
+                                       PermissionRequestOutcome::kUserGranted));
+  EXPECT_CALL(*read_grant, GetStatus())
+      .WillRepeatedly(testing::Return(PermissionStatus::GRANTED));
+
+  ASSERT_TRUE(
+      NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
+  EXPECT_EQ(test_dir.BaseName().AsUTF8Unsafe(),
+            EvalJs(shell(),
+                   "(async () => {"
+                   "  let e = await self.showDirectoryPicker();"
+                   "  self.selected_entry = e;"
+                   "  return e.name; })()"));
+  EXPECT_EQ(ui::SelectFileDialog::SELECT_FOLDER, dialog_params.type);
+  // temp_dir_.GetPath() maps to kTestMountPoint.
+  EXPECT_EQ(temp_dir_.GetPath(), dialog_params.default_path);
+}
+
+IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest,
+                       OpenDirectory_LastPickedDirNotExistsExternal) {
+  base::FilePath test_dir = CreateTestDir();
+
+  SelectFileDialogParams dialog_params;
+  ui::SelectFileDialog::SetFactory(
+      new FakeSelectFileDialogFactory({test_dir}, &dialog_params));
+
+  testing::StrictMock<MockNativeFileSystemPermissionContext> permission_context;
+  static_cast<NativeFileSystemManagerImpl*>(
+      BrowserContext::GetStoragePartition(
+          shell()->web_contents()->GetBrowserContext(),
+          shell()->web_contents()->GetSiteInstance())
+          ->GetNativeFileSystemEntryFactory())
+      ->SetPermissionContextForTesting(&permission_context);
+
+  auto read_grant = base::MakeRefCounted<
+      testing::StrictMock<MockNativeFileSystemPermissionGrant>>();
+  auto write_grant = base::MakeRefCounted<FixedNativeFileSystemPermissionGrant>(
+      PermissionStatus::GRANTED, base::FilePath());
+
+  auto origin =
+      url::Origin::Create(embedded_test_server()->GetURL("/title1.html"));
+  auto frame_id = GlobalFrameRoutingId(
+      shell()->web_contents()->GetMainFrame()->GetProcess()->GetID(),
+      shell()->web_contents()->GetMainFrame()->GetRoutingID());
+  EXPECT_CALL(permission_context, CanObtainReadPermission(origin))
+      .WillOnce(testing::Return(true));
+
+  // The last picked directory no longer exists, so resort to showing the
+  // default directory, then set the test_file's dir as last picked.
+  PathInfo bad_dir_info;
+  bad_dir_info.path = base::FilePath::FromUTF8Unsafe(kTestMountPoint)
+                          .AppendASCII("nonexistent");
+  PathInfo default_dir_info;
+  default_dir_info.path = temp_dir_.GetPath().AppendASCII("default");
+
+  EXPECT_CALL(permission_context, GetLastPickedDirectory(origin))
+      .WillOnce(testing::Return(bad_dir_info));
+  EXPECT_CALL(permission_context, GetDefaultDirectory())
+      .WillOnce(testing::Return(default_dir_info));
+  EXPECT_CALL(permission_context,
+              SetLastPickedDirectory(origin, test_dir, PathType::kLocal));
+
+  EXPECT_CALL(permission_context,
+              ConfirmSensitiveDirectoryAccess_(
+                  origin, PathType::kLocal, test_dir,
+                  NativeFileSystemPermissionContext::HandleType::kDirectory,
+                  frame_id, testing::_))
+      .WillOnce(RunOnceCallback<5>(SensitiveDirectoryResult::kAllowed));
+
+  EXPECT_CALL(permission_context,
+              GetReadPermissionGrant(
+                  origin, test_dir,
+                  NativeFileSystemPermissionContext::HandleType::kDirectory,
+                  NativeFileSystemPermissionContext::UserAction::kOpen))
+      .WillOnce(testing::Return(read_grant));
+  EXPECT_CALL(permission_context,
+              GetWritePermissionGrant(
+                  origin, test_dir,
+                  NativeFileSystemPermissionContext::HandleType::kDirectory,
+                  NativeFileSystemPermissionContext::UserAction::kOpen))
+      .WillOnce(testing::Return(write_grant));
+
+  EXPECT_CALL(
+      *read_grant,
+      RequestPermission_(
+          frame_id,
+          NativeFileSystemPermissionGrant::UserActivationState::kNotRequired,
+          testing::_))
+      .WillOnce(RunOnceCallback<2>(NativeFileSystemPermissionGrant::
+                                       PermissionRequestOutcome::kUserGranted));
+  EXPECT_CALL(*read_grant, GetStatus())
+      .WillRepeatedly(testing::Return(PermissionStatus::GRANTED));
+
+  ASSERT_TRUE(
+      NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
+  EXPECT_EQ(test_dir.BaseName().AsUTF8Unsafe(),
+            EvalJs(shell(),
+                   "(async () => {"
+                   "  let e = await self.showDirectoryPicker();"
+                   "  self.selected_entry = e;"
+                   "  return e.name; })()"));
+  EXPECT_EQ(ui::SelectFileDialog::SELECT_FOLDER, dialog_params.type);
+  EXPECT_EQ(default_dir_info.path, dialog_params.default_path);
+}
+
 }  // namespace content
diff --git a/content/browser/file_system_access/file_system_chooser_test_helpers.cc b/content/browser/file_system_access/file_system_chooser_test_helpers.cc
index 89a8fc1f..3dfe58a 100644
--- a/content/browser/file_system_access/file_system_chooser_test_helpers.cc
+++ b/content/browser/file_system_access/file_system_chooser_test_helpers.cc
@@ -35,6 +35,7 @@
         out_params_->file_types = base::nullopt;
       out_params_->owning_window = owning_window;
       out_params_->file_type_index = file_type_index;
+      out_params_->default_path = default_path;
     }
     listener_->FileSelectionCanceled(params);
   }
@@ -77,6 +78,7 @@
         out_params_->file_types = base::nullopt;
       out_params_->owning_window = owning_window;
       out_params_->file_type_index = file_type_index;
+      out_params_->default_path = default_path;
     }
     if (result_.size() == 1)
       listener_->FileSelectedWithExtraInfo(result_[0], 0, params);
diff --git a/content/browser/file_system_access/file_system_chooser_test_helpers.h b/content/browser/file_system_access/file_system_chooser_test_helpers.h
index 92ad3fb5..5696b25 100644
--- a/content/browser/file_system_access/file_system_chooser_test_helpers.h
+++ b/content/browser/file_system_access/file_system_chooser_test_helpers.h
@@ -5,6 +5,7 @@
 #ifndef CONTENT_BROWSER_FILE_SYSTEM_ACCESS_FILE_SYSTEM_CHOOSER_TEST_HELPERS_H_
 #define CONTENT_BROWSER_FILE_SYSTEM_ACCESS_FILE_SYSTEM_CHOOSER_TEST_HELPERS_H_
 
+#include "base/files/file_path.h"
 #include "base/optional.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/shell_dialogs/select_file_dialog.h"
@@ -23,6 +24,7 @@
   base::Optional<ui::SelectFileDialog::FileTypeInfo> file_types;
   gfx::NativeWindow owning_window = {};
   int file_type_index = -1;
+  base::FilePath default_path;
 };
 
 // A fake ui::SelectFileDialog, which will cancel the file selection instead of
diff --git a/content/browser/file_system_access/file_system_chooser_unittest.cc b/content/browser/file_system_access/file_system_chooser_unittest.cc
index c82e373..0166261 100644
--- a/content/browser/file_system_access/file_system_chooser_unittest.cc
+++ b/content/browser/file_system_access/file_system_chooser_unittest.cc
@@ -180,6 +180,32 @@
             dialog_params.file_types->extension_description_overrides[0]);
 }
 
+TEST_F(FileSystemChooserTest, IgnoreShellIntegratedExtensions) {
+  SelectFileDialogParams dialog_params;
+  ui::SelectFileDialog::SetFactory(
+      new CancellingSelectFileDialogFactory(&dialog_params));
+  std::vector<blink::mojom::ChooseFileSystemEntryAcceptsOptionPtr> accepts;
+  accepts.emplace_back(blink::mojom::ChooseFileSystemEntryAcceptsOption::New(
+      base::ASCIIToUTF16(""), std::vector<std::string>({}),
+      std::vector<std::string>(
+          {"lnk", "foo.lnk", "foo.bar.local", "text", "local"})));
+  SyncShowDialog(std::move(accepts), /*include_accepts_all=*/false);
+
+  ASSERT_TRUE(dialog_params.file_types);
+  EXPECT_FALSE(dialog_params.file_types->include_all_files);
+  ASSERT_EQ(1u, dialog_params.file_types->extensions.size());
+  EXPECT_EQ(1, dialog_params.file_type_index);
+
+  ASSERT_EQ(1u, dialog_params.file_types->extensions[0].size());
+  EXPECT_EQ(dialog_params.file_types->extensions[0][0],
+            FILE_PATH_LITERAL("text"));
+
+  ASSERT_EQ(1u,
+            dialog_params.file_types->extension_description_overrides.size());
+  EXPECT_EQ(base::ASCIIToUTF16(""),
+            dialog_params.file_types->extension_description_overrides[0]);
+}
+
 TEST_F(FileSystemChooserTest, LocalPath) {
   const base::FilePath local_path(FILE_PATH_LITERAL("/foo/bar"));
   ui::SelectedFileInfo selected_file(local_path, local_path);
diff --git a/content/browser/file_system_access/native_file_system_manager_impl.cc b/content/browser/file_system_access/native_file_system_manager_impl.cc
index a4ae8c9..4d5d21a7 100644
--- a/content/browser/file_system_access/native_file_system_manager_impl.cc
+++ b/content/browser/file_system_access/native_file_system_manager_impl.cc
@@ -36,6 +36,7 @@
 #include "storage/browser/file_system/file_system_operation_runner.h"
 #include "storage/browser/file_system/file_system_url.h"
 #include "storage/browser/file_system/isolated_context.h"
+#include "storage/common/file_system/file_system_types.h"
 #include "storage/common/file_system/file_system_util.h"
 #include "third_party/blink/public/mojom/file_system_access/native_file_system_drag_drop_token.mojom.h"
 #include "third_party/blink/public/mojom/file_system_access/native_file_system_error.mojom.h"
@@ -49,6 +50,7 @@
     NativeFileSystemPermissionContext::SensitiveDirectoryResult;
 using storage::FileSystemContext;
 using HandleType = NativeFileSystemPermissionContext::HandleType;
+using PathInfo = NativeFileSystemPermissionContext::PathInfo;
 
 namespace {
 
@@ -177,6 +179,23 @@
           std::move(reply_runner), std::move(callback)));
 }
 
+void GetDirectoryExistsFromUrl(
+    storage::FileSystemURL url,
+    base::OnceCallback<void(base::File::Error)> callback,
+    scoped_refptr<base::SequencedTaskRunner> reply_runner,
+    storage::FileSystemOperationRunner* operation_runner) {
+  operation_runner->DirectoryExists(
+      url, base::BindOnce(
+               [](scoped_refptr<base::SequencedTaskRunner> reply_runner,
+                  base::OnceCallback<void(base::File::Error)> callback,
+                  base::File::Error result) {
+                 // Post next task back on the UI thread.
+                 reply_runner->PostTask(
+                     FROM_HERE, base::BindOnce(std::move(callback), result));
+               },
+               std::move(reply_runner), std::move(callback)));
+}
+
 }  // namespace
 
 NativeFileSystemManagerImpl::SharedHandleState::SharedHandleState(
@@ -310,21 +329,52 @@
     return;
   }
 
-  // TODO(https://crbug.com/1142824): Check if path exists.
-  // TODO(asully): If PathType is kExternal, use FileSystemURL resolved path.
-  base::FilePath default_directory;
+  PathInfo path_info;
   if (permission_context_) {
-    default_directory =
-        permission_context_->GetLastPickedDirectory(context.origin).path;
-    if (default_directory.empty()) {
-      default_directory = permission_context_->GetDefaultDirectory().path;
-    }
+    path_info = permission_context_->GetLastPickedDirectory(context.origin);
   }
 
-  // TODO(https://crbug.com/1019408): Append suggested filename to the default
-  // directory.
+  auto url = CreateFileSystemURLFromPath(context.origin, path_info.type,
+                                         path_info.path);
+  auto fs_url = url.url;
+  operation_runner().PostTaskWithThisObject(
+      FROM_HERE,
+      base::BindOnce(
+          &GetDirectoryExistsFromUrl, std::move(fs_url),
+          base::BindOnce(
+              &NativeFileSystemManagerImpl::SetDefaultPathAndShowPicker,
+              weak_factory_.GetWeakPtr(), context, type, std::move(accepts),
+              include_accepts_all, std::move(url).url, std::move(callback)),
+          base::SequencedTaskRunnerHandle::Get()));
+}
+
+void NativeFileSystemManagerImpl::SetDefaultPathAndShowPicker(
+    const BindingContext& context,
+    blink::mojom::ChooseFileSystemEntryType type,
+    std::vector<blink::mojom::ChooseFileSystemEntryAcceptsOptionPtr> accepts,
+    bool include_accepts_all,
+    storage::FileSystemURL url,
+    ChooseEntriesCallback callback,
+    base::File::Error result) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  base::FilePath default_directory;
+  if (result != base::File::Error::FILE_OK) {
+    if (permission_context_) {
+      auto default_path_info = permission_context_->GetDefaultDirectory();
+      auto default_url = CreateFileSystemURLFromPath(
+          context.origin, default_path_info.type, default_path_info.path);
+      default_directory = default_url.url.path();
+    }
+  } else /*result == base::File::Error::FILE_OK*/ {
+    default_directory = url.path();
+  }
+
+  // TODO(https://crbug.com/1019408): Append suggested filename to
+  // default_path.
   FileSystemChooser::Options options(type, std::move(accepts),
-                                     include_accepts_all, default_directory);
+                                     include_accepts_all,
+                                     std::move(default_directory));
 
   if (auto_file_picker_result_for_test_) {
     DidChooseEntries(context, options, std::move(callback),
diff --git a/content/browser/file_system_access/native_file_system_manager_impl.h b/content/browser/file_system_access/native_file_system_manager_impl.h
index 827c18a..bdaa672 100644
--- a/content/browser/file_system_access/native_file_system_manager_impl.h
+++ b/content/browser/file_system_access/native_file_system_manager_impl.h
@@ -260,6 +260,14 @@
   friend class NativeFileSystemFileHandleImpl;
 
   ~NativeFileSystemManagerImpl() override;
+  void SetDefaultPathAndShowPicker(
+      const BindingContext& context,
+      blink::mojom::ChooseFileSystemEntryType type,
+      std::vector<blink::mojom::ChooseFileSystemEntryAcceptsOptionPtr> accepts,
+      bool include_accepts_all,
+      storage::FileSystemURL url,
+      ChooseEntriesCallback callback,
+      base::File::Error result);
   void DidOpenSandboxedFileSystem(const BindingContext& binding_context,
                                   GetSandboxedFileSystemCallback callback,
                                   const GURL& root,
diff --git a/content/browser/gpu/compositor_util.cc b/content/browser/gpu/compositor_util.cc
index da600f6..959568d 100644
--- a/content/browser/gpu/compositor_util.cc
+++ b/content/browser/gpu/compositor_util.cc
@@ -37,6 +37,7 @@
 #include "gpu/config/gpu_switches.h"
 #include "gpu/ipc/host/gpu_memory_buffer_support.h"
 #include "gpu/vulkan/buildflags.h"
+#include "media/base/media_switches.h"
 #include "media/media_buildflags.h"
 #include "third_party/blink/public/common/switches.h"
 #include "ui/gl/gl_switches.h"
@@ -133,7 +134,7 @@
      SafeGetFeatureStatus(gpu_feature_info,
                           gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE),
 #if (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && !defined(OS_ANDROID)
-     !command_line.HasSwitch(switches::kEnableAcceleratedVideoDecode),
+     !base::FeatureList::IsEnabled(media::kVaapiVideoDecodeLinux),
 #else
      command_line.HasSwitch(switches::kDisableAcceleratedVideoDecode),
 #endif  //  (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))&&
diff --git a/content/browser/initiator_csp_context.cc b/content/browser/initiator_csp_context.cc
index 3384af1..f8f26e2 100644
--- a/content/browser/initiator_csp_context.cc
+++ b/content/browser/initiator_csp_context.cc
@@ -8,14 +8,11 @@
 
 InitiatorCSPContext::InitiatorCSPContext(
     std::vector<network::mojom::ContentSecurityPolicyPtr> policies,
-    network::mojom::CSPSourcePtr self_source,
     mojo::PendingRemote<blink::mojom::NavigationInitiator> navigation_initiator)
     : reporting_render_frame_host_impl_(nullptr),
       initiator(std::move(navigation_initiator)) {
   for (auto& policy : policies)
     AddContentSecurityPolicy(std::move(policy));
-
-  SetSelf(std::move(self_source));
 }
 
 InitiatorCSPContext::~InitiatorCSPContext() = default;
diff --git a/content/browser/initiator_csp_context.h b/content/browser/initiator_csp_context.h
index d7e8b3bc..c21cc8e 100644
--- a/content/browser/initiator_csp_context.h
+++ b/content/browser/initiator_csp_context.h
@@ -24,7 +24,6 @@
  public:
   InitiatorCSPContext(
       std::vector<network::mojom::ContentSecurityPolicyPtr> policies,
-      network::mojom::CSPSourcePtr self_source,
       mojo::PendingRemote<blink::mojom::NavigationInitiator>
           navigation_initiator);
   ~InitiatorCSPContext() override;
diff --git a/content/browser/media/media_internals_audio_focus_helper.cc b/content/browser/media/media_internals_audio_focus_helper.cc
index 3540c65..482d282 100644
--- a/content/browser/media/media_internals_audio_focus_helper.cc
+++ b/content/browser/media/media_internals_audio_focus_helper.cc
@@ -4,11 +4,12 @@
 
 #include "content/browser/media/media_internals_audio_focus_helper.h"
 
-#include <list>
 #include <string>
 
 #include "base/bind.h"
 #include "base/containers/adapters.h"
+#include "base/ranges/algorithm.h"
+#include "base/strings/strcat.h"
 #include "base/values.h"
 #include "content/browser/media/media_internals.h"
 #include "content/public/browser/browser_task_traits.h"
@@ -44,6 +45,7 @@
 const char kMediaSessionIsSensitive[] = "Sensitive";
 
 const char kMediaSessionHasAudio[] = "HasAudio";
+const char kMediaSessionHasVideo[] = "HasVideo";
 const char kMediaSessionHasAudioVideo[] = "HasAudioVideo";
 
 }  // namespace
@@ -225,100 +227,114 @@
 std::string MediaInternalsAudioFocusHelper::BuildNameString(
     const media_session::mojom::AudioFocusRequestStatePtr& state,
     const std::string& provided_name) const {
-  std::stringstream stream;
+  std::string result;
 
   // Add the |source_name| (optional).
-  if (state->source_name.has_value()) {
-    stream << state->source_name.value();
-    stream << ":";
-  }
+  if (state->source_name.has_value())
+    base::StrAppend(&result, {state->source_name.value(), ":"});
 
   // Add the |request_id|.
-  stream << state->request_id.value().ToString();
+  result.append(state->request_id.value().ToString());
 
   if (!provided_name.empty())
-    stream << " " << provided_name;
-  return stream.str();
+    base::StrAppend(&result, {" ", provided_name});
+
+  return result;
 }
 
 std::string MediaInternalsAudioFocusHelper::BuildStateString(
     const media_session::mojom::AudioFocusRequestStatePtr& state,
     const std::string& provided_state) const {
-  std::stringstream stream;
+  std::string result(" ");
 
   // Convert the AudioFocusType mojo enum to a string.
   switch (state->audio_focus_type) {
     case media_session::mojom::AudioFocusType::kGain:
-      stream << " " << kAudioFocusTypeGain;
+      result.append(kAudioFocusTypeGain);
       break;
     case media_session::mojom::AudioFocusType::kGainTransient:
-      stream << " " << kAudioFocusTypeGainTransient;
+      result.append(kAudioFocusTypeGainTransient);
       break;
     case media_session::mojom::AudioFocusType::kGainTransientMayDuck:
-      stream << " " << kAudioFocusTypeGainTransientMayDuck;
+      result.append(kAudioFocusTypeGainTransientMayDuck);
       break;
     case media_session::mojom::AudioFocusType::kAmbient:
-      stream << " " << kAudioFocusTypeAmbient;
+      result.append(kAudioFocusTypeAmbient);
       break;
   }
 
   // Convert the MediaSessionInfo::SessionState mojo enum to a string.
+  result.append(" ");
   switch (state->session_info->state) {
     case media_session::mojom::MediaSessionInfo::SessionState::kActive:
-      stream << " " << kMediaSessionStateActive;
+      result.append(kMediaSessionStateActive);
       break;
     case media_session::mojom::MediaSessionInfo::SessionState::kDucking:
-      stream << " " << kMediaSessionStateDucking;
+      result.append(kMediaSessionStateDucking);
       break;
     case media_session::mojom::MediaSessionInfo::SessionState::kSuspended:
-      stream << " " << kMediaSessionStateSuspended;
+      result.append(kMediaSessionStateSuspended);
       break;
     case media_session::mojom::MediaSessionInfo::SessionState::kInactive:
-      stream << " " << kMediaSessionStateInactive;
+      result.append(kMediaSessionStateInactive);
       break;
   }
 
   // Convert the MediaPlaybackState mojo enum to a string.
+  result.append(" ");
   switch (state->session_info->playback_state) {
     case media_session::mojom::MediaPlaybackState::kPaused:
-      stream << " " << kMediaSessionPlaybackStatePaused;
+      result.append(kMediaSessionPlaybackStatePaused);
       break;
     case media_session::mojom::MediaPlaybackState::kPlaying:
-      stream << " " << kMediaSessionPlaybackStatePlaying;
+      result.append(kMediaSessionPlaybackStatePlaying);
       break;
   }
 
-  // Convert the audio_video_state to a string.
-  switch (state->session_info->audio_video_state) {
-    case media_session::mojom::MediaAudioVideoState::kUnknown:
-      break;
-    case media_session::mojom::MediaAudioVideoState::kAudioOnly:
-      stream << " " << kMediaSessionHasAudio;
-      break;
-    case media_session::mojom::MediaAudioVideoState::kAudioVideo:
-      stream << " " << kMediaSessionHasAudioVideo;
-      break;
+  // Convert the audio_video_states to a string.
+  if (state->session_info->audio_video_states) {
+    result.append(" {");
+    base::ranges::for_each(
+        *state->session_info->audio_video_states, [&result](const auto& state) {
+          result.append(" ");
+          switch (state) {
+            case media_session::mojom::MediaAudioVideoState::kAudioOnly:
+              result.append(kMediaSessionHasAudio);
+              break;
+            case media_session::mojom::MediaAudioVideoState::kVideoOnly:
+              result.append(kMediaSessionHasVideo);
+              break;
+            case media_session::mojom::MediaAudioVideoState::kAudioVideo:
+              result.append(kMediaSessionHasAudioVideo);
+              break;
+            case media_session::mojom::MediaAudioVideoState::kDeprecatedUnknown:
+              NOTREACHED();
+              break;
+          }
+        });
+    result.append(" }");
   }
 
   // Convert the |force_duck| boolean into a string.
   if (state->session_info->force_duck)
-    stream << " " << kAudioFocusForceDuck;
+    base::StrAppend(&result, {" ", kAudioFocusForceDuck});
 
   // Convert the |prefer_stop_for_gain_focus_loss| boolean into a string.
   if (state->session_info->prefer_stop_for_gain_focus_loss)
-    stream << " " << kAudioFocusPreferStop;
+    base::StrAppend(&result, {" ", kAudioFocusPreferStop});
 
   // Convert the |is_controllable| boolean into a string.
   if (state->session_info->is_controllable)
-    stream << " " << kMediaSessionIsControllable;
+    base::StrAppend(&result, {" ", kMediaSessionIsControllable});
 
   // Convert the |is_sensitive| boolean into a string.
   if (state->session_info->is_sensitive)
-    stream << " " << kMediaSessionIsSensitive;
+    base::StrAppend(&result, {" ", kMediaSessionIsSensitive});
 
   if (!provided_state.empty())
-    stream << " " << provided_state;
-  return stream.str();
+    base::StrAppend(&result, {" ", provided_state});
+
+  return result;
 }
 
 }  // namespace content
diff --git a/content/browser/media/session/media_session_controller.cc b/content/browser/media/session/media_session_controller.cc
index d50a377..4e27c52a 100644
--- a/content/browser/media/session/media_session_controller.cc
+++ b/content/browser/media/session/media_session_controller.cc
@@ -213,9 +213,14 @@
   return true;
 }
 
+bool MediaSessionController::HasAudio(int player_id) const {
+  DCHECK_EQ(player_id_, player_id);
+  return has_audio_;
+}
+
 bool MediaSessionController::HasVideo(int player_id) const {
   DCHECK_EQ(player_id_, player_id);
-  return has_video_ && has_audio_;
+  return has_video_;
 }
 
 std::string MediaSessionController::GetAudioOutputSinkId(int player_id) const {
diff --git a/content/browser/media/session/media_session_controller.h b/content/browser/media/session/media_session_controller.h
index 5231d6b..2b2033c 100644
--- a/content/browser/media/session/media_session_controller.h
+++ b/content/browser/media/session/media_session_controller.h
@@ -25,6 +25,10 @@
 // Helper class for controlling a single player's MediaSession instance.  Sends
 // browser side MediaSession commands back to a player hosted in the renderer
 // process.
+// MediaSessionController registers itself with MediaSessionImpl as the
+// MediaSessionPlayerObserver for the associated player, and for that player
+// only.  Consequently, it expects all MediaSessionPlayerObserver calls to
+// occur for that player only.
 class CONTENT_EXPORT MediaSessionController
     : public MediaSessionPlayerObserver {
  public:
@@ -44,7 +48,7 @@
   // the MediaSession instance in sync with renderer side behavior.
   void OnPlaybackPaused(bool reached_end_of_stream);
 
-  // MediaSessionObserver implementation.
+  // MediaSessionPlayerObserver implementation.
   void OnSuspend(int player_id) override;
   void OnResume(int player_id) override;
   void OnSeekForward(int player_id, base::TimeDelta seek_time) override;
@@ -58,6 +62,7 @@
   base::Optional<media_session::MediaPosition> GetPosition(
       int player_id) const override;
   bool IsPictureInPictureAvailable(int player_id) const override;
+  bool HasAudio(int player_id) const override;
   bool HasVideo(int player_id) const override;
   std::string GetAudioOutputSinkId(int player_id) const override;
   bool SupportsAudioOutputDeviceSwitching(int player_id) const override;
diff --git a/content/browser/media/session/media_session_controller_unittest.cc b/content/browser/media/session/media_session_controller_unittest.cc
index a2e96ed..4ac41d1 100644
--- a/content/browser/media/session/media_session_controller_unittest.cc
+++ b/content/browser/media/session/media_session_controller_unittest.cc
@@ -179,7 +179,7 @@
 };
 
 TEST_F(MediaSessionControllerTest, NoAudioNoSession) {
-  controller_->SetMetadata(false, false, media::MediaContentType::Persistent);
+  controller_->SetMetadata(false, true, media::MediaContentType::Persistent);
   ASSERT_TRUE(controller_->OnPlaybackStarted());
   EXPECT_FALSE(media_session()->IsActive());
   EXPECT_FALSE(media_session()->IsControllable());
@@ -258,7 +258,7 @@
 }
 
 TEST_F(MediaSessionControllerTest, Reinitialize) {
-  controller_->SetMetadata(false, false, media::MediaContentType::Persistent);
+  controller_->SetMetadata(false, true, media::MediaContentType::Persistent);
   ASSERT_TRUE(controller_->OnPlaybackStarted());
   EXPECT_FALSE(media_session()->IsActive());
   EXPECT_FALSE(media_session()->IsControllable());
@@ -408,7 +408,7 @@
 
 TEST_F(MediaSessionControllerTest, AddPlayerWhenAddingAudio) {
   controller_->SetMetadata(
-      /* has_audio = */ false, /* has_video = */ false,
+      /* has_audio = */ false, /* has_video = */ true,
       media::MediaContentType::Persistent);
   ASSERT_TRUE(controller_->OnPlaybackStarted());
   ASSERT_FALSE(media_session()->IsActive());
@@ -422,7 +422,7 @@
 TEST_F(MediaSessionControllerTest,
        AddPlayerWhenEnteringPictureInPictureWithNoAudio) {
   controller_->SetMetadata(
-      /* has_audio = */ false, /* has_video = */ false,
+      /* has_audio = */ false, /* has_video = */ true,
       media::MediaContentType::Persistent);
   ASSERT_TRUE(controller_->OnPlaybackStarted());
   ASSERT_FALSE(media_session()->IsActive());
@@ -435,7 +435,7 @@
 TEST_F(MediaSessionControllerTest,
        AddPlayerWhenEnteringPictureInPicturePaused) {
   controller_->SetMetadata(
-      /*has_audio=*/false, /*has_video=*/false,
+      /*has_audio=*/false, /*has_video=*/true,
       media::MediaContentType::Persistent);
   ASSERT_TRUE(controller_->OnPlaybackStarted());
   controller_->OnPlaybackPaused(/*reached_end_of_stream=*/false);
@@ -451,7 +451,7 @@
   contents()->SetHasPictureInPictureVideo(true);
 
   controller_->SetMetadata(
-      /* has_audio = */ false, /* has_video = */ false,
+      /* has_audio = */ false, /* has_video = */ true,
       media::MediaContentType::Persistent);
   ASSERT_TRUE(controller_->OnPlaybackStarted());
   EXPECT_TRUE(media_session()->IsActive());
@@ -471,7 +471,7 @@
 
 TEST_F(MediaSessionControllerTest, HasVideo_False) {
   controller_->SetMetadata(
-      /* has_audio = */ false, /* has_video = */ false,
+      /* has_audio = */ true, /* has_video = */ false,
       media::MediaContentType::Persistent);
   EXPECT_FALSE(controller_->HasVideo(controller_->get_player_id_for_testing()));
 }
diff --git a/content/browser/media/session/media_session_impl.cc b/content/browser/media/session/media_session_impl.cc
index 8bf006db..aba9289 100644
--- a/content/browser/media/session/media_session_impl.cc
+++ b/content/browser/media/session/media_session_impl.cc
@@ -940,7 +940,7 @@
     info->playback_state = MediaPlaybackState::kPlaying;
   }
 
-  info->audio_video_state = GetMediaAudioVideoState();
+  info->audio_video_states = GetMediaAudioVideoStates();
   info->is_controllable = IsControllable();
 
   // If the browser context is off the record then it should be sensitive.
@@ -1529,28 +1529,33 @@
   });
 }
 
-MediaAudioVideoState MediaSessionImpl::GetMediaAudioVideoState() {
+std::vector<MediaAudioVideoState> MediaSessionImpl::GetMediaAudioVideoStates() {
   RenderFrameHost* routed_rfh =
       routed_service_ ? routed_service_->GetRenderFrameHost() : nullptr;
-  MediaAudioVideoState state = MediaAudioVideoState::kUnknown;
+  std::vector<MediaAudioVideoState> states;
 
   ForAllPlayers(base::BindRepeating(
-      [](RenderFrameHost* routed_rfh, MediaAudioVideoState* state,
+      [](RenderFrameHost* routed_rfh, std::vector<MediaAudioVideoState>* states,
          const PlayerIdentifier& player) {
         // If we have a routed frame then we should limit the players to the
         // frame so it is aligned with the media metadata.
         if (routed_rfh && player.observer->render_frame_host() != routed_rfh)
           return;
 
-        if (player.observer->HasVideo(player.player_id))
-          *state = MediaAudioVideoState::kAudioVideo;
-
-        if (*state != MediaAudioVideoState::kAudioVideo)
-          *state = MediaAudioVideoState::kAudioOnly;
+        const bool has_audio = player.observer->HasAudio(player.player_id);
+        const bool has_video = player.observer->HasVideo(player.player_id);
+        if (has_audio && has_video) {
+          states->push_back(MediaAudioVideoState::kAudioVideo);
+        } else if (has_audio) {
+          states->push_back(MediaAudioVideoState::kAudioOnly);
+        } else {
+          DCHECK(has_video);
+          states->push_back(MediaAudioVideoState::kVideoOnly);
+        }
       },
-      routed_rfh, &state));
+      routed_rfh, &states));
 
-  return state;
+  return states;
 }
 
 void MediaSessionImpl::ForAllPlayers(
diff --git a/content/browser/media/session/media_session_impl.h b/content/browser/media/session/media_session_impl.h
index 05615cd..a79f8b6 100644
--- a/content/browser/media/session/media_session_impl.h
+++ b/content/browser/media/session/media_session_impl.h
@@ -409,11 +409,12 @@
   void DidReceiveAction(media_session::mojom::MediaSessionAction action,
                         blink::mojom::MediaSessionActionDetailsPtr details);
 
-  // Returns the media audio video state. This is whether the players associated
-  // with the media session are audio-only or have audio and video. If we have
-  // a |routed_service_| then we limit to players on that frame because this
-  // should align with the metadata.
-  media_session::mojom::MediaAudioVideoState GetMediaAudioVideoState();
+  // Returns the media audio video state for each player. This is whether the
+  // players associated with the media session are audio-only, video-only, or
+  // have both audio and video. If we have a |routed_service_| then we limit to
+  // players on that frame because this should align with the metadata.
+  std::vector<media_session::mojom::MediaAudioVideoState>
+  GetMediaAudioVideoStates();
 
   // Calls the callback with each |PlayerIdentifier| for every player associated
   // with this media session.
diff --git a/content/browser/media/session/media_session_impl_service_routing_unittest.cc b/content/browser/media/session/media_session_impl_service_routing_unittest.cc
index 6eb58be6..6f7f452 100644
--- a/content/browser/media/session/media_session_impl_service_routing_unittest.cc
+++ b/content/browser/media/session/media_session_impl_service_routing_unittest.cc
@@ -26,6 +26,7 @@
 using ::testing::InvokeWithoutArgs;
 using ::testing::NiceMock;
 
+using media_session::mojom::MediaAudioVideoState;
 using media_session::mojom::MediaSessionAction;
 using media_session::mojom::MediaSessionImageType;
 
@@ -40,8 +41,9 @@
 
 class MockMediaSessionPlayerObserver : public MediaSessionPlayerObserver {
  public:
-  explicit MockMediaSessionPlayerObserver(RenderFrameHost* rfh, bool has_video)
-      : render_frame_host_(rfh), has_video_(has_video) {}
+  MockMediaSessionPlayerObserver(RenderFrameHost* rfh,
+                                 MediaAudioVideoState audio_video_state)
+      : render_frame_host_(rfh), audio_video_state_(audio_video_state) {}
 
   ~MockMediaSessionPlayerObserver() override = default;
 
@@ -70,7 +72,15 @@
     return false;
   }
 
-  bool HasVideo(int player_id) const override { return has_video_; }
+  bool HasAudio(int player_id) const override {
+    return audio_video_state_ == MediaAudioVideoState::kAudioOnly ||
+           audio_video_state_ == MediaAudioVideoState::kAudioVideo;
+  }
+
+  bool HasVideo(int player_id) const override {
+    return audio_video_state_ == MediaAudioVideoState::kVideoOnly ||
+           audio_video_state_ == MediaAudioVideoState::kAudioVideo;
+  }
 
   std::string GetAudioOutputSinkId(int player_id) const override { return ""; }
 
@@ -85,7 +95,7 @@
  private:
   RenderFrameHost* render_frame_host_;
 
-  bool const has_video_;
+  const media_session::mojom::MediaAudioVideoState audio_video_state_;
 
   base::Optional<media_session::MediaPosition> position_;
 };
@@ -138,16 +148,20 @@
                                      : nullptr;
   }
 
-  void StartPlayerForFrame(TestRenderFrameHost* frame, bool has_video = false) {
-    StartPlayerForFrame(frame, media::MediaContentType::Persistent, has_video);
+  void StartPlayerForFrame(TestRenderFrameHost* frame,
+                           MediaAudioVideoState audio_video_state =
+                               MediaAudioVideoState::kAudioOnly) {
+    StartPlayerForFrame(frame, media::MediaContentType::Persistent,
+                        audio_video_state);
   }
 
   void StartPlayerForFrame(TestRenderFrameHost* frame,
                            media::MediaContentType type,
-                           bool has_video = false) {
+                           MediaAudioVideoState audio_video_state =
+                               MediaAudioVideoState::kAudioOnly) {
     players_[frame] =
-        std::make_unique<NiceMock<MockMediaSessionPlayerObserver>>(frame,
-                                                                   has_video);
+        std::make_unique<NiceMock<MockMediaSessionPlayerObserver>>(
+            frame, audio_video_state);
     MediaSessionImpl::Get(contents())
         ->AddPlayer(players_[frame].get(), kPlayerId, type);
   }
@@ -1061,109 +1075,107 @@
 }
 
 TEST_F(MediaSessionImplServiceRoutingTest, RouteAudioVideoState) {
-  {
-    media_session::test::MockMediaSessionMojoObserver observer(
-        *GetMediaSession());
+  for (const auto audio_or_video_only :
+       {MediaAudioVideoState::kAudioOnly, MediaAudioVideoState::kVideoOnly}) {
+    SCOPED_TRACE(audio_or_video_only);
 
-    // The default state should be unknown.
-    observer.WaitForAudioVideoState(
-        media_session::mojom::MediaAudioVideoState::kUnknown);
-  }
+    {
+      media_session::test::MockMediaSessionMojoObserver observer(
+          *GetMediaSession());
 
-  StartPlayerForFrame(main_frame_, false /* has_video */);
+      // The default state should be unknown.
+      observer.WaitForAudioVideoStates({});
+    }
 
-  {
-    media_session::test::MockMediaSessionMojoObserver observer(
-        *GetMediaSession());
+    StartPlayerForFrame(main_frame_, audio_or_video_only);
 
-    // We should set the state to audio only.
-    observer.WaitForAudioVideoState(
-        media_session::mojom::MediaAudioVideoState::kAudioOnly);
-  }
+    {
+      media_session::test::MockMediaSessionMojoObserver observer(
+          *GetMediaSession());
 
-  StartPlayerForFrame(sub_frame_, true /* has_video */);
+      // We should set the state to audio/video only.
+      observer.WaitForAudioVideoStates({audio_or_video_only});
+    }
 
-  {
-    media_session::test::MockMediaSessionMojoObserver observer(
-        *GetMediaSession());
+    StartPlayerForFrame(sub_frame_, MediaAudioVideoState::kAudioVideo);
 
-    // The new player has a video track so we should now be AudioVideo.
-    observer.WaitForAudioVideoState(
-        media_session::mojom::MediaAudioVideoState::kAudioVideo);
-  }
+    {
+      media_session::test::MockMediaSessionMojoObserver observer(
+          *GetMediaSession());
 
-  CreateServiceForFrame(main_frame_);
-  ASSERT_EQ(services_[main_frame_].get(), ComputeServiceForRouting());
+      // The new player has both an audio and video track.
+      observer.WaitForAudioVideoStates(
+          {audio_or_video_only, MediaAudioVideoState::kAudioVideo});
+    }
 
-  {
-    media_session::test::MockMediaSessionMojoObserver observer(
-        *GetMediaSession());
+    CreateServiceForFrame(main_frame_);
+    ASSERT_EQ(services_[main_frame_].get(), ComputeServiceForRouting());
 
-    // The service on the main frame will restrict the audio video state to
-    // only look at the routed frame.
-    observer.WaitForAudioVideoState(
-        media_session::mojom::MediaAudioVideoState::kAudioOnly);
-  }
+    {
+      media_session::test::MockMediaSessionMojoObserver observer(
+          *GetMediaSession());
 
-  CreateServiceForFrame(sub_frame_);
-  ASSERT_EQ(services_[main_frame_].get(), ComputeServiceForRouting());
+      // The service on the main frame will restrict the audio video state to
+      // only look at the routed frame.
+      observer.WaitForAudioVideoStates({audio_or_video_only});
+    }
 
-  {
-    media_session::test::MockMediaSessionMojoObserver observer(
-        *GetMediaSession());
+    CreateServiceForFrame(sub_frame_);
+    ASSERT_EQ(services_[main_frame_].get(), ComputeServiceForRouting());
 
-    // The service on the main frame will restrict the audio video state to
-    // only look at the routed frame.
-    observer.WaitForAudioVideoState(
-        media_session::mojom::MediaAudioVideoState::kAudioOnly);
-  }
+    {
+      media_session::test::MockMediaSessionMojoObserver observer(
+          *GetMediaSession());
 
-  DestroyServiceForFrame(main_frame_);
-  ASSERT_EQ(services_[sub_frame_].get(), ComputeServiceForRouting());
+      // The service on the main frame will restrict the audio video state to
+      // only look at the routed frame.
+      observer.WaitForAudioVideoStates({audio_or_video_only});
+    }
 
-  {
-    media_session::test::MockMediaSessionMojoObserver observer(
-        *GetMediaSession());
+    DestroyServiceForFrame(main_frame_);
+    ASSERT_EQ(services_[sub_frame_].get(), ComputeServiceForRouting());
 
-    // Now that the service on the main frame has been destroyed then we should
-    // only look at players on the sub frame.
-    observer.WaitForAudioVideoState(
-        media_session::mojom::MediaAudioVideoState::kAudioVideo);
-  }
+    {
+      media_session::test::MockMediaSessionMojoObserver observer(
+          *GetMediaSession());
 
-  DestroyServiceForFrame(sub_frame_);
-  ASSERT_EQ(nullptr, ComputeServiceForRouting());
+      // Now that the service on the main frame has been destroyed then we
+      // should only look at players on the sub frame.
+      observer.WaitForAudioVideoStates({MediaAudioVideoState::kAudioVideo});
+    }
 
-  {
-    media_session::test::MockMediaSessionMojoObserver observer(
-        *GetMediaSession());
+    DestroyServiceForFrame(sub_frame_);
+    ASSERT_EQ(nullptr, ComputeServiceForRouting());
 
-    // Now that there is no service we should be looking at all the players
-    // again.
-    observer.WaitForAudioVideoState(
-        media_session::mojom::MediaAudioVideoState::kAudioVideo);
-  }
+    {
+      media_session::test::MockMediaSessionMojoObserver observer(
+          *GetMediaSession());
 
-  ClearPlayersForFrame(sub_frame_);
+      // Now that there is no service we should be looking at all the players
+      // again.
+      observer.WaitForAudioVideoStates(
+          {audio_or_video_only, MediaAudioVideoState::kAudioVideo});
+    }
 
-  {
-    media_session::test::MockMediaSessionMojoObserver observer(
-        *GetMediaSession());
+    ClearPlayersForFrame(sub_frame_);
 
-    // The state should be updated when we remove the sub frame players.
-    observer.WaitForAudioVideoState(
-        media_session::mojom::MediaAudioVideoState::kAudioOnly);
-  }
+    {
+      media_session::test::MockMediaSessionMojoObserver observer(
+          *GetMediaSession());
 
-  ClearPlayersForFrame(main_frame_);
+      // The state should be updated when we remove the sub frame players.
+      observer.WaitForAudioVideoStates({audio_or_video_only});
+    }
 
-  {
-    media_session::test::MockMediaSessionMojoObserver observer(
-        *GetMediaSession());
+    ClearPlayersForFrame(main_frame_);
 
-    // We should fallback to the default state.
-    observer.WaitForAudioVideoState(
-        media_session::mojom::MediaAudioVideoState::kUnknown);
+    {
+      media_session::test::MockMediaSessionMojoObserver observer(
+          *GetMediaSession());
+
+      // We should fallback to the default state.
+      observer.WaitForAudioVideoStates({});
+    }
   }
 }
 
diff --git a/content/browser/media/session/media_session_impl_uma_unittest.cc b/content/browser/media/session/media_session_impl_uma_unittest.cc
index 06ce7df3..506d8551 100644
--- a/content/browser/media/session/media_session_impl_uma_unittest.cc
+++ b/content/browser/media/session/media_session_impl_uma_unittest.cc
@@ -53,6 +53,7 @@
     return false;
   }
 
+  bool HasAudio(int player_id) const override { return true; }
   bool HasVideo(int player_id) const override { return false; }
 
   std::string GetAudioOutputSinkId(int player_id) const override { return ""; }
diff --git a/content/browser/media/session/media_session_player_observer.h b/content/browser/media/session/media_session_player_observer.h
index 7e1fdf9..6fce422 100644
--- a/content/browser/media/session/media_session_player_observer.h
+++ b/content/browser/media/session/media_session_player_observer.h
@@ -56,6 +56,9 @@
   // Returns if picture-in-picture is available for |player_id|.
   virtual bool IsPictureInPictureAvailable(int player_id) const = 0;
 
+  // Returns true if the |player_id| has audio tracks.
+  virtual bool HasAudio(int player_id) const = 0;
+
   // Returns true if the |player_id| has video tracks.
   virtual bool HasVideo(int player_id) const = 0;
 
diff --git a/content/browser/media/session/media_session_service_impl_browsertest.cc b/content/browser/media/session/media_session_service_impl_browsertest.cc
index 66c80f00..6fcab67 100644
--- a/content/browser/media/session/media_session_service_impl_browsertest.cc
+++ b/content/browser/media/session/media_session_service_impl_browsertest.cc
@@ -66,6 +66,7 @@
     return false;
   }
 
+  bool HasAudio(int player_id) const override { return true; }
   bool HasVideo(int player_id) const override { return false; }
 
   std::string GetAudioOutputSinkId(int player_id) const override { return ""; }
diff --git a/content/browser/media/session/mock_media_session_player_observer.cc b/content/browser/media/session/mock_media_session_player_observer.cc
index 57c7eeb..44a45425 100644
--- a/content/browser/media/session/mock_media_session_player_observer.cc
+++ b/content/browser/media/session/mock_media_session_player_observer.cc
@@ -164,6 +164,12 @@
   return received_set_audio_sink_id_calls_;
 }
 
+bool MockMediaSessionPlayerObserver::HasAudio(int player_id) const {
+  EXPECT_GE(player_id, 0);
+  EXPECT_GT(players_.size(), static_cast<size_t>(player_id));
+  return true;
+}
+
 bool MockMediaSessionPlayerObserver::HasVideo(int player_id) const {
   EXPECT_GE(player_id, 0);
   EXPECT_GT(players_.size(), static_cast<size_t>(player_id));
diff --git a/content/browser/media/session/mock_media_session_player_observer.h b/content/browser/media/session/mock_media_session_player_observer.h
index a8392617..8ada516 100644
--- a/content/browser/media/session/mock_media_session_player_observer.h
+++ b/content/browser/media/session/mock_media_session_player_observer.h
@@ -37,6 +37,7 @@
       int player_id) const override;
   bool IsPictureInPictureAvailable(int player_id) const override;
   RenderFrameHost* render_frame_host() const override;
+  bool HasAudio(int player_id) const override;
   bool HasVideo(int player_id) const override;
   std::string GetAudioOutputSinkId(int player_id) const override;
   bool SupportsAudioOutputDeviceSwitching(int player_id) const override;
diff --git a/content/browser/media/session/pepper_player_delegate.cc b/content/browser/media/session/pepper_player_delegate.cc
index 77b1716..44b546e 100644
--- a/content/browser/media/session/pepper_player_delegate.cc
+++ b/content/browser/media/session/pepper_player_delegate.cc
@@ -98,6 +98,11 @@
       render_frame_host_->GetRoutingID(), pp_instance_, volume));
 }
 
+bool PepperPlayerDelegate::HasAudio(int player_id) const {
+  // We don't actually know whether a pepper player has both audio/video.
+  return true;
+}
+
 bool PepperPlayerDelegate::HasVideo(int player_id) const {
   // We don't actually know whether a pepper player has both audio/video.
   return true;
diff --git a/content/browser/media/session/pepper_player_delegate.h b/content/browser/media/session/pepper_player_delegate.h
index f0802ee..68f4e9e1 100644
--- a/content/browser/media/session/pepper_player_delegate.h
+++ b/content/browser/media/session/pepper_player_delegate.h
@@ -37,6 +37,7 @@
       int player_id) const override;
   bool IsPictureInPictureAvailable(int player_id) const override;
   RenderFrameHost* render_frame_host() const override;
+  bool HasAudio(int player_id) const override;
   bool HasVideo(int player_id) const override;
   std::string GetAudioOutputSinkId(int player_id) const override;
   bool SupportsAudioOutputDeviceSwitching(int player_id) const override;
diff --git a/content/browser/renderer_host/ancestor_throttle.cc b/content/browser/renderer_host/ancestor_throttle.cc
index cba465a..e08419c 100644
--- a/content/browser/renderer_host/ancestor_throttle.cc
+++ b/content/browser/renderer_host/ancestor_throttle.cc
@@ -156,17 +156,26 @@
   // attribute at the beginning of the navigation and not now, since the
   // beforeunload handlers might have modified it in the meantime.
   std::vector<network::mojom::ContentSecurityPolicyPtr> frame_csp;
-  frame_csp.emplace_back(
+  network::mojom::ContentSecurityPolicyPtr frame_csp_attribute =
       request->frame_tree_node()->csp_attribute()
           ? request->frame_tree_node()->csp_attribute()->Clone()
-          : nullptr);
+          : nullptr;
+  if (frame_csp_attribute) {
+    const GURL& url = navigation_handle()->GetURL();
+
+    // TODO(antoniosartori): Maybe we should revisit what 'self' means in the
+    // 'csp' attribute.
+    frame_csp_attribute->self_origin = network::mojom::CSPSource::New(
+        url.scheme(), url.host(), url.EffectiveIntPort(), "", false, false);
+  }
+  frame_csp.emplace_back(std::move(frame_csp_attribute));
+
   const network::mojom::ContentSecurityPolicy* parent_required_csp =
       request->frame_tree_node()->parent()->required_csp();
 
   std::string error_message;
-  if (!network::IsValidRequiredCSPAttr(
-          frame_csp, parent_required_csp,
-          url::Origin::Create(navigation_handle()->GetURL()), error_message)) {
+  if (!network::IsValidRequiredCSPAttr(frame_csp, parent_required_csp,
+                                       error_message)) {
     if (frame_csp[0]) {
       navigation_handle()->GetParentFrame()->AddMessageToConsole(
           blink::mojom::ConsoleMessageLevel::kError,
@@ -485,7 +494,6 @@
   FrameAncestorCSPContext csp_context(
       NavigationRequest::From(navigation_handle())->GetRenderFrameHost(),
       content_security_policy);
-  csp_context.SetSelf(url::Origin::Create(navigation_handle()->GetURL()));
 
   // Check CSP frame-ancestors against every parent.
   // We enforce frame-ancestors in the outer delegate for portals, but not
@@ -554,8 +562,7 @@
   }
   if (network::Subsumes(
           *request->required_csp(),
-          request->response()->parsed_headers->content_security_policy,
-          url::Origin::Create(navigation_handle()->GetURL()))) {
+          request->response()->parsed_headers->content_security_policy)) {
     return CheckResult::PROCEED;
   }
 
diff --git a/content/browser/renderer_host/cursor_manager_unittest.cc b/content/browser/renderer_host/cursor_manager_unittest.cc
index fe49a3a..2edfb0d 100644
--- a/content/browser/renderer_host/cursor_manager_unittest.cc
+++ b/content/browser/renderer_host/cursor_manager_unittest.cc
@@ -56,12 +56,12 @@
         std::make_unique<MockRenderProcessHost>(browser_context_.get());
     agent_scheduling_group_host_ =
         std::make_unique<AgentSchedulingGroupHost>(*process_host_);
-    widget_host_.reset(MakeNewWidgetHost());
+    widget_host_ = MakeNewWidgetHost();
     top_view_ =
         new MockRenderWidgetHostViewForCursors(widget_host_.get(), true);
   }
 
-  RenderWidgetHostImpl* MakeNewWidgetHost() {
+  std::unique_ptr<RenderWidgetHostImpl> MakeNewWidgetHost() {
     int32_t routing_id = process_host_->GetNextRoutingID();
     return MockRenderWidgetHost::Create(
         &delegate_, *agent_scheduling_group_host_, routing_id);
diff --git a/content/browser/renderer_host/form_submission_throttle_unittest.cc b/content/browser/renderer_host/form_submission_throttle_unittest.cc
index 03c6636..60b9c9a 100644
--- a/content/browser/renderer_host/form_submission_throttle_unittest.cc
+++ b/content/browser/renderer_host/form_submission_throttle_unittest.cc
@@ -19,6 +19,8 @@
     policy->header = network::mojom::ContentSecurityPolicyHeader::New();
     policy->directives[network::mojom::CSPDirectiveName::FormAction] =
         std::move(source_none);
+    policy->self_origin = network::mojom::CSPSource::New(
+        "https", "www.example.org", 443, "", false, false);
     main_test_rfh()->AddContentSecurityPolicy(std::move(policy));
   }
 };
diff --git a/content/browser/renderer_host/input/fling_scheduler_unittest.cc b/content/browser/renderer_host/input/fling_scheduler_unittest.cc
index 4816881..811f063 100644
--- a/content/browser/renderer_host/input/fling_scheduler_unittest.cc
+++ b/content/browser/renderer_host/input/fling_scheduler_unittest.cc
@@ -57,16 +57,17 @@
   FlingSchedulerTest() {}
   void SetUp() override {
     view_ = CreateView();
-    widget_host_->SetView(view_);
+    widget_host_->SetView(view_.get());
 
-    fling_scheduler_ = std::make_unique<FakeFlingScheduler>(widget_host_);
+    fling_scheduler_ = std::make_unique<FakeFlingScheduler>(widget_host_.get());
     fling_controller_ = std::make_unique<FlingController>(
         this, fling_scheduler_.get(), FlingController::Config());
   }
 
   void TearDown() override {
-    view_->Destroy();
-    widget_host_->ShutdownAndDestroyWidget(true);
+    view_.release()->Destroy();  // 'delete this' is called internally.
+    widget_host_->ShutdownAndDestroyWidget(false);
+    widget_host_.reset();
     process_host_->Cleanup();
     agent_scheduling_group_host_.reset();
     process_host_.reset();
@@ -75,7 +76,7 @@
     base::RunLoop().RunUntilIdle();
   }
 
-  TestRenderWidgetHostView* CreateView() {
+  std::unique_ptr<TestRenderWidgetHostView> CreateView() {
     browser_context_ = std::make_unique<TestBrowserContext>();
     process_host_ =
         std::make_unique<MockRenderProcessHost>(browser_context_.get());
@@ -84,12 +85,10 @@
         std::make_unique<AgentSchedulingGroupHost>(*process_host_);
     int32_t routing_id = process_host_->GetNextRoutingID();
     delegate_ = std::make_unique<MockRenderWidgetHostDelegate>();
-    widget_host_ =
-        TestRenderWidgetHost::Create(
-            delegate_.get(), *agent_scheduling_group_host_, routing_id, false)
-            .release();
-    delegate_->set_widget_host(widget_host_);
-    return new TestRenderWidgetHostView(widget_host_);
+    widget_host_ = TestRenderWidgetHost::Create(
+        delegate_.get(), *agent_scheduling_group_host_, routing_id, false);
+    delegate_->set_widget_host(widget_host_.get());
+    return std::make_unique<TestRenderWidgetHostView>(widget_host_.get());
   }
 
   void SimulateFlingStart(const gfx::Vector2dF& velocity) {
@@ -128,10 +127,10 @@
  private:
   BrowserTaskEnvironment task_environment_;
   std::unique_ptr<TestBrowserContext> browser_context_;
-  RenderWidgetHostImpl* widget_host_;
+  std::unique_ptr<RenderWidgetHostImpl> widget_host_;
   std::unique_ptr<MockRenderProcessHost> process_host_;
   std::unique_ptr<AgentSchedulingGroupHost> agent_scheduling_group_host_;
-  TestRenderWidgetHostView* view_;
+  std::unique_ptr<TestRenderWidgetHostView> view_;
   std::unique_ptr<MockRenderWidgetHostDelegate> delegate_;
 #if defined(OS_WIN)
   display::win::test::ScopedScreenWin scoped_screen_win_;
diff --git a/content/browser/renderer_host/input/mouse_latency_browsertest.cc b/content/browser/renderer_host/input/mouse_latency_browsertest.cc
index 2cc1f5f..577579a 100644
--- a/content/browser/renderer_host/input/mouse_latency_browsertest.cc
+++ b/content/browser/renderer_host/input/mouse_latency_browsertest.cc
@@ -80,7 +80,8 @@
                           AgentSchedulingGroupHost& agent_scheduling_group,
                           int32_t routing_id,
                           bool hidden)
-      : RenderWidgetHostImpl(delegate,
+      : RenderWidgetHostImpl(/*self_owned=*/false,
+                             delegate,
                              agent_scheduling_group,
                              routing_id,
                              hidden,
@@ -92,8 +93,6 @@
       blink::mojom::InputEventResultState ack_result) override {
     RenderWidgetHostImpl::OnMouseEventAck(event, ack_source, ack_result);
   }
-
- private:
 };
 
 class TracingRenderWidgetHostFactory : public RenderWidgetHostFactory {
diff --git a/content/browser/renderer_host/mixed_content_navigation_throttle.cc b/content/browser/renderer_host/mixed_content_navigation_throttle.cc
index 76a1b53..00a9142b 100644
--- a/content/browser/renderer_host/mixed_content_navigation_throttle.cc
+++ b/content/browser/renderer_host/mixed_content_navigation_throttle.cc
@@ -20,8 +20,8 @@
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/navigation_policy.h"
-#include "content/public/common/origin_util.h"
 #include "net/base/url_util.h"
+#include "services/network/public/cpp/is_potentially_trustworthy.h"
 #include "third_party/blink/public/common/loader/network_utils.h"
 #include "third_party/blink/public/common/security_context/insecure_request_policy.h"
 #include "third_party/blink/public/common/web_preferences/web_preferences.h"
@@ -56,7 +56,7 @@
   return url.SchemeIs(url::kBlobScheme) ||
          url.SchemeIs(url::kFileSystemScheme) ||
          blink::network_utils::IsOriginSecure(url) ||
-         IsPotentiallyTrustworthyOrigin(url::Origin::Create(url));
+         network::IsOriginPotentiallyTrustworthy(url::Origin::Create(url));
 }
 
 // This method should return the same results as
diff --git a/content/browser/renderer_host/mock_render_widget_host.cc b/content/browser/renderer_host/mock_render_widget_host.cc
index fa6d0ca..f4d0e2e 100644
--- a/content/browser/renderer_host/mock_render_widget_host.cc
+++ b/content/browser/renderer_host/mock_render_widget_host.cc
@@ -38,25 +38,27 @@
 }
 
 // static
-MockRenderWidgetHost* MockRenderWidgetHost::Create(
+std::unique_ptr<MockRenderWidgetHost> MockRenderWidgetHost::Create(
     RenderWidgetHostDelegate* delegate,
     AgentSchedulingGroupHost& agent_scheduling_group,
     int32_t routing_id) {
   mojo::AssociatedRemote<blink::mojom::Widget> blink_widget;
   auto blink_widget_receiver =
       blink_widget.BindNewEndpointAndPassDedicatedReceiver();
-  return new MockRenderWidgetHost(delegate, agent_scheduling_group, routing_id,
-                                  blink_widget.Unbind());
+  return Create(delegate, agent_scheduling_group, routing_id,
+                blink_widget.Unbind());
 }
 
-MockRenderWidgetHost* MockRenderWidgetHost::Create(
+// static
+std::unique_ptr<MockRenderWidgetHost> MockRenderWidgetHost::Create(
     RenderWidgetHostDelegate* delegate,
     AgentSchedulingGroupHost& agent_scheduling_group,
     int32_t routing_id,
     mojo::PendingAssociatedRemote<blink::mojom::Widget> pending_blink_widget) {
   DCHECK(pending_blink_widget);
-  return new MockRenderWidgetHost(delegate, agent_scheduling_group, routing_id,
-                                  std::move(pending_blink_widget));
+  return base::WrapUnique(
+      new MockRenderWidgetHost(delegate, agent_scheduling_group, routing_id,
+                               std::move(pending_blink_widget)));
 }
 
 blink::mojom::WidgetInputHandler*
@@ -73,7 +75,8 @@
     AgentSchedulingGroupHost& agent_scheduling_group,
     int routing_id,
     mojo::PendingAssociatedRemote<blink::mojom::Widget> pending_blink_widget)
-    : RenderWidgetHostImpl(delegate,
+    : RenderWidgetHostImpl(/*self_owned=*/false,
+                           delegate,
                            agent_scheduling_group,
                            routing_id,
                            /*hidden=*/false,
diff --git a/content/browser/renderer_host/mock_render_widget_host.h b/content/browser/renderer_host/mock_render_widget_host.h
index 63c7d232..665757d 100644
--- a/content/browser/renderer_host/mock_render_widget_host.h
+++ b/content/browser/renderer_host/mock_render_widget_host.h
@@ -58,12 +58,12 @@
 
   InputRouter* input_router() { return input_router_.get(); }
 
-  static MockRenderWidgetHost* Create(
+  static std::unique_ptr<MockRenderWidgetHost> Create(
       RenderWidgetHostDelegate* delegate,
       AgentSchedulingGroupHost& agent_scheduling_group,
       int32_t routing_id);
 
-  static MockRenderWidgetHost* Create(
+  static std::unique_ptr<MockRenderWidgetHost> Create(
       RenderWidgetHostDelegate* delegate,
       AgentSchedulingGroupHost& agent_scheduling_group,
       int32_t routing_id,
diff --git a/content/browser/renderer_host/navigation_controller_impl_browsertest.cc b/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
index 273091f..1da9c12 100644
--- a/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
@@ -49,6 +49,7 @@
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/bindings_policy.h"
+#include "content/public/common/content_client.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/common/use_zoom_for_dsf_policy.h"
@@ -68,6 +69,7 @@
 #include "content/test/content_browser_test_utils_internal.h"
 #include "content/test/did_commit_navigation_interceptor.h"
 #include "content/test/render_document_feature.h"
+#include "content/test/test_content_browser_client.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/controllable_http_response.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
@@ -451,6 +453,167 @@
 }
 #endif  // defined(OS_ANDROID)
 
+// ContentBrowserClient that blocks normal commits to any URL in
+// VerifyDidCommitParams.
+class BlockAllCommitContentBrowserClient : public TestContentBrowserClient {
+ public:
+  // Any visit to any URL will be blocked by VerifyDidCommitParams, except if
+  // the checks are skipped (e.g. loadDataWithBaseURL).
+  BlockAllCommitContentBrowserClient() = default;
+
+  bool CanCommitURL(RenderProcessHost* process_host,
+                    const GURL& site_url) override {
+    return false;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BlockAllCommitContentBrowserClient);
+};
+
+// Tests that navigating with LoadDataWithBaseURL succeeds even when the data
+// URL is typically blocked by an embedder.
+IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
+                       LoadDataWithBlockedURL) {
+  // LoadDataWithBaseURL is never subject to --site-per-process policy today
+  // (this API is only used by Android WebView [where OOPIFs have not shipped
+  // yet] and GuestView cases [which always hosts guests inside a renderer
+  // without an origin lock]).  Therefore, skip the test in --site-per-process
+  // mode to avoid renderer kills which won't happen in practice as described
+  // above.
+  //
+  // TODO(https://crbug.com/962643): Consider enabling this test once Android
+  // Webview or WebView guests support OOPIFs and/or origin locks.
+  if (AreAllSitesIsolatedForTesting())
+    return;
+
+  const GURL base_url = embedded_test_server()->GetURL("/title1.html");
+  const GURL history_url("http://historyurl");
+  const std::string title = "blocked_url";
+  const std::string data = base::StringPrintf(
+      "<html><head><title>%s</title></head><body>foo</body></html>",
+      title.c_str());
+  const GURL data_url = GURL("data:text/html;charset=utf-8," + data);
+  BlockAllCommitContentBrowserClient content_browser_client;
+  ContentBrowserClient* old_client =
+      SetBrowserClientForTesting(&content_browser_client);
+
+  NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
+      shell()->web_contents()->GetController());
+
+  TestNavigationObserver same_tab_observer(shell()->web_contents(), 1);
+  TitleWatcher title_watcher(shell()->web_contents(), base::UTF8ToUTF16(title));
+  shell()->LoadDataWithBaseURL(history_url, data, base_url);
+  same_tab_observer.Wait();
+  base::string16 actual_title = title_watcher.WaitAndGetTitle();
+  EXPECT_EQ(title, base::UTF16ToUTF8(actual_title));
+
+  NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
+  EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
+  EXPECT_EQ(data_url, contents()->GetMainFrame()->GetLastCommittedURL());
+  {
+    // Make a same-document navigation via history.pushState.
+    TestNavigationObserver same_tab_observer(shell()->web_contents(), 1);
+    EXPECT_TRUE(
+        ExecuteScript(shell(), "history.pushState('', 'test', '#foo')"));
+    same_tab_observer.Wait();
+  }
+
+  // Verify the last committed NavigationEntry.
+  EXPECT_EQ(2, controller.GetEntryCount());
+  entry = controller.GetLastCommittedEntry();
+  EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
+  EXPECT_EQ(data_url, contents()->GetMainFrame()->GetLastCommittedURL());
+  {
+    // Go back.
+    TestNavigationObserver back_load_observer(shell()->web_contents());
+    controller.GoBack();
+    back_load_observer.Wait();
+  }
+
+  // Verify the last committed NavigationEntry.
+  EXPECT_EQ(2, controller.GetEntryCount());
+  entry = controller.GetLastCommittedEntry();
+  EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
+  EXPECT_EQ(data_url, contents()->GetMainFrame()->GetLastCommittedURL());
+
+  {
+    // Make a same-document navigation via fragment navigation.
+    TestNavigationObserver same_tab_observer(shell()->web_contents(), 1);
+    EXPECT_TRUE(ExecuteScript(shell(), "location.href = '#bar';"));
+    same_tab_observer.Wait();
+  }
+
+  // Verify the last committed NavigationEntry.
+  EXPECT_EQ(2, controller.GetEntryCount());
+  entry = controller.GetLastCommittedEntry();
+  EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
+  EXPECT_EQ(data_url, contents()->GetMainFrame()->GetLastCommittedURL());
+
+  SetBrowserClientForTesting(old_client);
+}
+
+// Tests that same-document navigations after a LoadDataWithBaseURL with an
+// invalid base_url won't succeed.
+IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
+                       LoadDataWithBlockedURLAndInvalidBaseURL) {
+  // LoadDataWithBaseURL is never subject to --site-per-process policy today
+  // (this API is only used by Android WebView [where OOPIFs have not shipped
+  // yet] and GuestView cases [which always hosts guests inside a renderer
+  // without an origin lock]).  Therefore, skip the test in --site-per-process
+  // mode to avoid renderer kills which won't happen in practice as described
+  // above.
+  //
+  // TODO(https://crbug.com/962643): Consider enabling this test once Android
+  // Webview or WebView guests support OOPIFs and/or origin locks.
+  if (AreAllSitesIsolatedForTesting())
+    return;
+
+  const GURL base_url("http://");  // Invalid.
+  EXPECT_TRUE(!base_url.is_valid());
+  const GURL history_url("http://historyurl");
+  const std::string title = "invalid_base_url";
+  const std::string data = base::StringPrintf(
+      "<html><head><title>%s</title></head><body>foo</body></html>",
+      title.c_str());
+  const GURL data_url = GURL("data:text/html;charset=utf-8," + data);
+  BlockAllCommitContentBrowserClient content_browser_client;
+  ContentBrowserClient* old_client =
+      SetBrowserClientForTesting(&content_browser_client);
+
+  NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
+      shell()->web_contents()->GetController());
+
+  TestNavigationObserver same_tab_observer(shell()->web_contents(), 1);
+  TitleWatcher title_watcher(shell()->web_contents(), base::UTF8ToUTF16(title));
+  shell()->LoadDataWithBaseURL(history_url, data, base_url);
+  same_tab_observer.Wait();
+  base::string16 actual_title = title_watcher.WaitAndGetTitle();
+  EXPECT_EQ(title, base::UTF16ToUTF8(actual_title));
+
+  // The navigation succeeds even though the base URL is invalid.
+  NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
+  EXPECT_EQ(1, controller.GetEntryCount());
+  EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
+  EXPECT_EQ(data_url, contents()->GetMainFrame()->GetLastCommittedURL());
+
+  {
+    // Make a same-document navigation via history.pushState.
+    TestNavigationObserver same_tab_observer(shell()->web_contents(), 1);
+    EXPECT_TRUE(
+        ExecuteScript(shell(), "history.pushState('', 'test', '#foo')"));
+    same_tab_observer.Wait();
+  }
+
+  // Verify that the same-document navigation succeeds.
+  EXPECT_EQ(2, controller.GetEntryCount());
+  entry = controller.GetLastCommittedEntry();
+  EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
+  EXPECT_EQ(data_url.spec() + "#foo",
+            contents()->GetMainFrame()->GetLastCommittedURL().spec());
+
+  SetBrowserClientForTesting(old_client);
+}
+
 IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
                        NavigateFromLoadDataWithBaseURL) {
   // LoadDataWithBaseURL is never subject to --site-per-process policy today
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index c0b31bf..0e1c0fa2 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -90,7 +90,6 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/common/navigation_policy.h"
 #include "content/public/common/network_service_util.h"
-#include "content/public/common/origin_util.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/common/url_utils.h"
 #include "mojo/public/cpp/system/data_pipe.h"
@@ -235,7 +234,8 @@
 // TODO(clamy): This should be function in FrameTreeNode.
 bool IsSecureFrame(RenderFrameHostImpl* frame) {
   while (frame) {
-    if (!IsPotentiallyTrustworthyOrigin(frame->GetLastCommittedOrigin()))
+    if (!network::IsOriginPotentiallyTrustworthy(
+            frame->GetLastCommittedOrigin()))
       return false;
     frame = frame->GetParent();
   }
@@ -1024,7 +1024,6 @@
       expected_render_process_host_id_(ChildProcessHost::kInvalidUniqueID),
       initiator_csp_context_(std::make_unique<InitiatorCSPContext>(
           std::move(common_params_->initiator_csp_info->initiator_csp),
-          std::move(common_params_->initiator_csp_info->initiator_self_source),
           std::move(navigation_initiator))),
       rfh_restored_from_back_forward_cache_(
           rfh_restored_from_back_forward_cache),
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 1a7c0e9..52dfc50e1 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -328,14 +328,6 @@
 base::LazyInstance<TokenFrameMap>::Leaky g_token_frame_map =
     LAZY_INSTANCE_INITIALIZER;
 
-// Returns true if |validated_params| represents a WebView loadDataWithBaseUrl
-// navigation.
-bool IsLoadDataWithBaseURL(
-    const mojom::DidCommitProvisionalLoadParams& validated_params) {
-  return NavigationRequest::IsLoadDataWithBaseURL(validated_params.url,
-                                                  validated_params.base_url);
-}
-
 // Ensure that we reset nav_entry_id_ in DidCommitProvisionalLoad if any of
 // the validations fail and lead to an early return.  Call disable() once we
 // know the commit will be successful.  Resetting nav_entry_id_ avoids acting on
@@ -652,7 +644,8 @@
   StartDownload(std::move(parameters), nullptr);
 }
 
-void RecordCrossOriginIsolationMetrics(RenderFrameHostImpl* rfh) {
+void RecordWebPlatformSecurityMetrics(RenderFrameHostImpl* rfh,
+                                      NavigationRequest* navigation_request) {
   ContentBrowserClient* client = GetContentClient()->browser();
   if (rfh->cross_origin_opener_policy().value ==
       network::mojom::CrossOriginOpenerPolicyValue::kSameOrigin) {
@@ -683,6 +676,45 @@
     client->LogWebFeatureForCurrentPage(
         rfh, blink::mojom::WebFeature::kCrossOriginOpenerPolicyReporting);
   }
+
+  // Record iframes embedded in cross-origin contexts without a CSP
+  // frame-ancestor directive.
+  bool is_embedded_in_cross_origin_context = false;
+  RenderFrameHostImpl* parent = rfh->frame_tree_node()->parent();
+  while (parent) {
+    if (!parent->GetLastCommittedOrigin().IsSameOriginWith(
+            rfh->GetLastCommittedOrigin())) {
+      is_embedded_in_cross_origin_context = true;
+      break;
+    }
+    parent = parent->frame_tree_node()->parent();
+  }
+
+  bool has_embedding_control = false;
+  if (!navigation_request->response()) {
+    // This navigation did not result in a network request. The embedding of
+    // the frame is not controlled by network headers.
+    has_embedding_control = true;
+  } else {
+    // Check if the request has a CSP frame-ancestor directive.
+    for (const auto& csp : navigation_request->response()
+                               ->parsed_headers->content_security_policy) {
+      if (csp->header->type ==
+              network::mojom::ContentSecurityPolicyType::kEnforce &&
+          csp->directives.contains(
+              network::mojom::CSPDirectiveName::FrameAncestors)) {
+        has_embedding_control = true;
+        break;
+      }
+    }
+  }
+
+  if (is_embedded_in_cross_origin_context && !has_embedding_control &&
+      !navigation_request->IsErrorPage()) {
+    client->LogWebFeatureForCurrentPage(
+        rfh,
+        blink::mojom::WebFeature::kCrossOriginSubframeWithoutEmbeddingControl);
+  }
 }
 
 // Subframe navigations can optionally have associated Trust Tokens operations
@@ -1047,7 +1079,6 @@
       // RenderWidgetHostImpl, the main render frame should probably start
       // owning the RenderWidgetHostImpl itself.
       DCHECK(GetLocalRenderWidgetHost());
-      DCHECK(!GetLocalRenderWidgetHost()->owned_by_render_frame_host());
     } else {
       // For local child roots, the RenderFrameHost directly creates and owns
       // its RenderWidgetHost.
@@ -1057,7 +1088,6 @@
       owned_render_widget_host_ = RenderWidgetHostFactory::Create(
           frame_tree_->render_widget_delegate(), agent_scheduling_group_,
           widget_routing_id, /*hidden=*/true);
-      owned_render_widget_host_->set_owned_by_render_frame_host(true);
 #if defined(OS_ANDROID)
       owned_render_widget_host_->SetForceEnableZoom(
           delegate_->GetOrCreateWebPreferences().force_enable_zoom);
@@ -1072,18 +1102,6 @@
   }
   ResetFeaturePolicy();
 
-  // Content-Security-Policy: The CSP source 'self' is usually the origin of the
-  // current document, set by SetLastCommittedOrigin(). However, before a new
-  // frame commits its first navigation, 'self' should correspond to the origin
-  // of the parent (in case of a new iframe) or the opener (in case of a new
-  // window). This is necessary to correctly enforce CSP during the initial
-  // navigation.
-  FrameTreeNode* frame_owner =
-      frame_tree_node_->parent() ? frame_tree_node_->parent()->frame_tree_node()
-                                 : frame_tree_node_->opener();
-  if (frame_owner)
-    CSPContext::SetSelf(frame_owner->current_origin());
-
   // New RenderFrameHostImpl are put in their own virtual browsing context
   // group. Then, they can inherit from:
   // 1) Their opener in RenderFrameHostImpl::CreateNewWindow().
@@ -2658,7 +2676,6 @@
 
 void RenderFrameHostImpl::SetLastCommittedOrigin(const url::Origin& origin) {
   last_committed_origin_ = origin;
-  CSPContext::SetSelf(origin);
 }
 
 void RenderFrameHostImpl::SetLastCommittedOriginForTesting(
@@ -8338,11 +8355,17 @@
   // WebView's loadDataWithBaseURL API is allowed to bypass normal commit
   // checks because it is allowed to commit anything into its unlocked process
   // and its data: URL and non-opaque origin would fail the normal commit
-  // checks.
+  // checks. We should also allow same-document navigations within pages loaded
+  // with loadDataWithBaseURL. Since renderer-initiated same-document
+  // navigations won't have a NavigationRequest at this point, we need to check
+  // |is_loaded_from_load_data_with_base_url_|.
+  DCHECK(navigation_request || is_same_document_navigation ||
+         !frame_tree_node_->has_committed_real_load());
   bool bypass_checks_for_webview = false;
   if ((navigation_request && NavigationRequest::IsLoadDataWithBaseURL(
                                  navigation_request->common_params())) ||
-      (is_same_document_navigation && IsLoadDataWithBaseURL(*params))) {
+      (is_same_document_navigation &&
+       is_loaded_from_load_data_with_base_url_)) {
     // Allow bypass if the process isn't locked. Otherwise run normal checks.
     bypass_checks_for_webview = !ChildProcessSecurityPolicyImpl::GetInstance()
                                      ->GetProcessLock(process->GetID())
@@ -8760,7 +8783,15 @@
   is_overriding_user_agent_ = navigation_request->IsOverridingUserAgent() &&
                               frame_tree_node_->IsMainFrame();
 
-  RecordCrossOriginIsolationMetrics(this);
+  // Mark whether the document is loaded with loadDataWithBaseURL or not. If
+  // |is_loaded_from_load_data_with_base_url_| is true, we will bypass checks
+  // in VerifyDidCommitParams for same-document navigations in the loaded
+  // document.
+  is_loaded_from_load_data_with_base_url_ =
+      NavigationRequest::IsLoadDataWithBaseURL(
+          navigation_request->common_params());
+
+  RecordWebPlatformSecurityMetrics(this, navigation_request);
 
   CrossOriginOpenerPolicyReporter::InstallAccessMonitorsIfNeeded(
       frame_tree_node_);
@@ -9365,19 +9396,10 @@
   return last_committed_entry ? last_committed_entry->GetPostID() : -1;
 }
 
-bool DoBaseURLExpectationsMatch(const GURL& browser_base_url,
-                                const GURL& renderer_base_url,
+bool DoBaseURLExpectationsMatch(const GURL& renderer_base_url,
                                 const net::Error& net_error_code) {
-  // base_url value is currently only used in the browser side for two cases:
-  // 1) To check if the document is loaded with loadDataWithBaseURL in
-  // ValidateDidCommitParams. In this case, |renderer_base_url| should be the
-  // same as |browser_base_url|, except for when the browser sent an
-  // invalid URL - |renderer_base_url| should be empty in this case.
-  if (!browser_base_url.is_empty() && browser_base_url != renderer_base_url &&
-      (browser_base_url.is_valid() || !renderer_base_url.is_empty())) {
-    return false;
-  }
-  // 2) To check if a navigation results in an error page or not in
+  // base_url value is currently only used in the browser side to check if a
+  // navigation results in an error page or not in
   // NavigationRequest::DidCommitNavigation. This can be known by just checking
   // for the net error code value instead, as all navigations that result in an
   // error page should be known by the browser side before committing.
@@ -9439,8 +9461,8 @@
       data_url_as_string, request->GetNetErrorCode(),
       frame_tree_node_->IsMainFrame());
 
-  const bool base_url_expectations_match = DoBaseURLExpectationsMatch(
-      browser_base_url, params.base_url, request->GetNetErrorCode());
+  const bool base_url_expectations_match =
+      DoBaseURLExpectationsMatch(params.base_url, request->GetNetErrorCode());
 
   const int64_t browser_post_id =
       CalculatePostID(params.method, request->common_params().post_data,
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h
index 685e7e7..f492d77f 100644
--- a/content/browser/renderer_host/render_frame_host_impl.h
+++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -3075,6 +3075,10 @@
   // not.
   bool is_overriding_user_agent_ = false;
 
+  // Whether the currently committed document is a result of webview's
+  // loadDataWithBaseURL API or not.
+  bool is_loaded_from_load_data_with_base_url_ = false;
+
   // The last reported character encoding, not canonicalized.
   std::string last_reported_encoding_;
 
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 4fe62d5..0c1b981 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -3185,9 +3185,6 @@
     !BUILDFLAG(IS_CHROMEOS_LACROS)
     switches::kDisableDevShmUsage,
 #endif
-#if (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && !defined(OS_ANDROID)
-    switches::kEnableAcceleratedVideoDecode,
-#endif
 #if defined(OS_MAC)
     // Allow this to be set when invoking the browser and relayed along.
     sandbox::policy::switches::kEnableSandboxLogging,
diff --git a/content/browser/renderer_host/render_widget_host_factory.cc b/content/browser/renderer_host/render_widget_host_factory.cc
index 3c7dfe5..8b576dc 100644
--- a/content/browser/renderer_host/render_widget_host_factory.cc
+++ b/content/browser/renderer_host/render_widget_host_factory.cc
@@ -22,7 +22,7 @@
     return factory_->CreateRenderWidgetHost(delegate, agent_scheduling_group,
                                             routing_id, hidden);
   }
-  return std::make_unique<RenderWidgetHostImpl>(
+  return RenderWidgetHostImpl::Create(
       delegate, agent_scheduling_group, routing_id, hidden,
       std::make_unique<FrameTokenMessageQueue>());
 }
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index d4df86598..eaf64f3 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -326,13 +326,39 @@
 ///////////////////////////////////////////////////////////////////////////////
 // RenderWidgetHostImpl
 
+// static
+std::unique_ptr<RenderWidgetHostImpl> RenderWidgetHostImpl::Create(
+    RenderWidgetHostDelegate* delegate,
+    AgentSchedulingGroupHost& agent_scheduling_host,
+    int32_t routing_id,
+    bool hidden,
+    std::unique_ptr<FrameTokenMessageQueue> frame_token_message_queue) {
+  return base::WrapUnique(new RenderWidgetHostImpl(
+      /*self_owned=*/false, delegate, agent_scheduling_host, routing_id, hidden,
+      std::move(frame_token_message_queue)));
+}
+
+// static
+RenderWidgetHostImpl* RenderWidgetHostImpl::CreateSelfOwned(
+    RenderWidgetHostDelegate* delegate,
+    AgentSchedulingGroupHost& agent_scheduling_host,
+    int32_t routing_id,
+    bool hidden,
+    std::unique_ptr<FrameTokenMessageQueue> frame_token_message_queue) {
+  return new RenderWidgetHostImpl(/*self_owned=*/true, delegate,
+                                  agent_scheduling_host, routing_id, hidden,
+                                  std::move(frame_token_message_queue));
+}
+
 RenderWidgetHostImpl::RenderWidgetHostImpl(
+    bool self_owned,
     RenderWidgetHostDelegate* delegate,
     AgentSchedulingGroupHost& agent_scheduling_group,
     int32_t routing_id,
     bool hidden,
     std::unique_ptr<FrameTokenMessageQueue> frame_token_message_queue)
-    : delegate_(delegate),
+    : self_owned_(self_owned),
+      delegate_(delegate),
       agent_scheduling_group_(agent_scheduling_group),
       routing_id_(routing_id),
       clock_(base::DefaultTickClock::GetInstance()),
@@ -372,7 +398,13 @@
                              routing_id_),
           this));
   CHECK(result.second) << "Inserting a duplicate item!";
-  agent_scheduling_group.GetProcess()->AddObserver(this);
+
+  // Self-owned RenderWidgetHost lifetime is managed by the renderer process.
+  // To avoid leaking any instance. They self-delete when their renderer process
+  // is gone.
+  if (self_owned_)
+    agent_scheduling_group.GetProcess()->AddObserver(this);
+
   render_process_blocked_state_changed_subscription_ =
       agent_scheduling_group.GetProcess()->RegisterBlockStateChangedCallback(
           base::BindRepeating(
@@ -394,6 +426,7 @@
 }
 
 RenderWidgetHostImpl::~RenderWidgetHostImpl() {
+  CHECK(!self_owned_);
   render_frame_metadata_provider_.RemoveObserver(this);
   if (!destroyed_)
     Destroy(false);
@@ -812,7 +845,7 @@
   // Historically this was done by finding the RenderViewHost for the widget,
   // but a child local root would not convert to a RenderViewHost but is for a
   // frame.
-  const bool is_frame_widget = owner_delegate_ || owned_by_render_frame_host_;
+  const bool is_frame_widget = !self_owned_;
 
   blink::VisualProperties visual_properties;
 
@@ -1895,11 +1928,8 @@
 void RenderWidgetHostImpl::RenderProcessExited(
     RenderProcessHost* host,
     const ChildProcessTerminationInfo& info) {
-  // When the RenderViewHost or the RenderFrameHost own this instance, they
-  // manage its destruction. Otherwise it is owned by the renderer process and
-  // must self-destroy when it exits.
-  if (!owner_delegate_ && !owned_by_render_frame_host_)
-    Destroy(true);
+  CHECK(self_owned_);
+  Destroy(/*also_delete=*/true);  // Delete |this|.
 }
 
 blink::mojom::WidgetInputHandler*
@@ -2199,7 +2229,10 @@
     delegate_->RenderWidgetDeleted(this);
 
   if (also_delete) {
-    CHECK(!owner_delegate_);
+    CHECK(self_owned_);
+    // The destructor CHECKs self-owned RenderWidgetHostImpl aren't destroyed
+    // externally. This bit needs to be reset to allow internal deletion.
+    self_owned_ = false;
     delete this;
   }
 }
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index a023b982..aa994c8 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -148,10 +148,22 @@
       public blink::mojom::WidgetHost,
       public blink::mojom::PointerLockContext {
  public:
-  // |routing_id| must not be MSG_ROUTING_NONE.
-  // If this object outlives |delegate|, DetachDelegate() must be called when
-  // |delegate| goes away.
-  RenderWidgetHostImpl(
+  // See the constructor for documentations.
+  static std::unique_ptr<RenderWidgetHostImpl> Create(
+      RenderWidgetHostDelegate* delegate,
+      AgentSchedulingGroupHost& agent_scheduling_host,
+      int32_t routing_id,
+      bool hidden,
+      std::unique_ptr<FrameTokenMessageQueue> frame_token_message_queue);
+
+  // See the constructor for documentations.
+  //
+  // Contrary to Create(), this function doesn't give ownership of the
+  // RenderWidgetHost. Instead, this instance is self-owned. It deletes itself
+  // when:
+  // - ShutdownAndDestroyWidget(also_delete = true) is called.
+  // - its RenderProcess exit.
+  static RenderWidgetHostImpl* CreateSelfOwned(
       RenderWidgetHostDelegate* delegate,
       AgentSchedulingGroupHost& agent_scheduling_host,
       int32_t routing_id,
@@ -352,15 +364,6 @@
   // Returns true if the frame content needs be stored before being evicted.
   bool ShouldShowStaleContentOnEviction();
 
-  // Signal whether this RenderWidgetHost is owned by a RenderFrameHost, in
-  // which case it does not do self-deletion.
-  void set_owned_by_render_frame_host(bool owned_by_rfh) {
-    owned_by_render_frame_host_ = owned_by_rfh;
-  }
-  bool owned_by_render_frame_host() const {
-    return owned_by_render_frame_host_;
-  }
-
   void SetFrameDepth(unsigned int depth);
   void SetIntersectsViewport(bool intersects);
   void UpdatePriority();
@@ -807,6 +810,16 @@
   GetLastVisualPropertiesSentToRendererForTesting();
 
  protected:
+  // |routing_id| must not be MSG_ROUTING_NONE.
+  // If this object outlives |delegate|, DetachDelegate() must be called when
+  // |delegate| goes away.
+  RenderWidgetHostImpl(
+      bool self_owned,
+      RenderWidgetHostDelegate* delegate,
+      AgentSchedulingGroupHost& agent_scheduling_host,
+      int32_t routing_id,
+      bool hidden,
+      std::unique_ptr<FrameTokenMessageQueue> frame_token_message_queue);
   // ---------------------------------------------------------------------------
   // The following method is overridden by RenderViewHost to send upwards to
   // its delegate.
@@ -1058,6 +1071,19 @@
   // An expiry time for resetting the pending_user_activation_timer_.
   static const base::TimeDelta kActivationNotificationExpireTime;
 
+  // RenderWidgetHost are either:
+  // - Owned by RenderViewHostImpl.
+  // - Owned by RenderFrameHost, for local root iframes.
+  // - Self owned. Lifetime is managed from the renderer process, via Mojo IPC;
+  //   This is used to implement:
+  //   - Color Chooser popup.
+  //   - Date/Time chooser popup.
+  //   - Internal popup. Essentially, the <select> element popup.
+  //
+  // self_owned RenderWidgetHost are expected to be deleted using:
+  // ShutdownAndDestroyWidget(true /* also_delete */);
+  bool self_owned_;
+
   // true if a renderer has once been valid. We use this flag to display a sad
   // tab only when we lose our renderer and not if a paint occurs during
   // initialization.
@@ -1247,10 +1273,6 @@
   PendingSnapshotMap pending_browser_snapshots_;
   PendingSnapshotMap pending_surface_browser_snapshots_;
 
-  // Indicates whether a RenderFramehost has ownership, in which case this
-  // object does not self destroy.
-  bool owned_by_render_frame_host_ = false;
-
   // Indicates whether this RenderWidgetHost thinks is focused. This is trying
   // to match what the renderer process knows. It is different from
   // RenderWidgetHostView::HasFocus in that in that the focus request may fail,
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router_unittest.cc b/content/browser/renderer_host/render_widget_host_input_event_router_unittest.cc
index 1383b6c..3a3045d4 100644
--- a/content/browser/renderer_host/render_widget_host_input_event_router_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_input_event_router_unittest.cc
@@ -232,7 +232,7 @@
         std::make_unique<MockRenderProcessHost>(browser_context_.get());
     agent_scheduling_group_host_root_ =
         std::make_unique<AgentSchedulingGroupHost>(*process_host_root_);
-    widget_host_root_ = std::make_unique<RenderWidgetHostImpl>(
+    widget_host_root_ = RenderWidgetHostImpl::Create(
         &delegate_, *agent_scheduling_group_host_root_,
         process_host_root_->GetNextRoutingID(),
         /*hidden=*/false, std::make_unique<FrameTokenMessageQueue>());
@@ -289,7 +289,7 @@
         std::make_unique<MockRenderProcessHost>(browser_context_.get());
     child.agent_scheduling_group_host =
         std::make_unique<AgentSchedulingGroupHost>(*child.process_host);
-    child.widget_host = std::make_unique<RenderWidgetHostImpl>(
+    child.widget_host = RenderWidgetHostImpl::Create(
         &delegate_, *child.agent_scheduling_group_host,
         child.process_host->GetNextRoutingID(),
         /*hidden=*/false, std::make_unique<FrameTokenMessageQueue>());
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc
index 81650beb..11fbf37 100644
--- a/content/browser/renderer_host/render_widget_host_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -544,9 +544,9 @@
     screen_.reset(aura::TestScreen::Create(gfx::Size()));
     display::Screen::SetScreenInstance(screen_.get());
 #endif
-    host_.reset(MockRenderWidgetHost::Create(
+    host_ = MockRenderWidgetHost::Create(
         delegate_.get(), *agent_scheduling_group_host_,
-        process_->GetNextRoutingID(), widget_.GetNewRemote()));
+        process_->GetNextRoutingID(), widget_.GetNewRemote());
     // Set up the RenderWidgetHost as being for a main frame.
     host_->set_owner_delegate(&mock_owner_delegate_);
     // Act like there is no RenderWidget present in the renderer yet.
diff --git a/content/browser/renderer_host/render_widget_host_view_android_unittest.cc b/content/browser/renderer_host/render_widget_host_view_android_unittest.cc
index 2817fbb..2e5f06e 100644
--- a/content/browser/renderer_host/render_widget_host_view_android_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android_unittest.cc
@@ -81,12 +81,12 @@
 
 void RenderWidgetHostViewAndroidTest::SetUp() {
   browser_context_.reset(new TestBrowserContext());
-  delegate_.reset(new MockRenderWidgetHostDelegate());
+  delegate_ = std::make_unique<MockRenderWidgetHostDelegate>();
   process_ = std::make_unique<MockRenderProcessHost>(browser_context_.get());
   agent_scheduling_group_ =
       std::make_unique<AgentSchedulingGroupHost>(*process_);
-  host_.reset(MockRenderWidgetHost::Create(
-      delegate_.get(), *agent_scheduling_group_, process_->GetNextRoutingID()));
+  host_ = MockRenderWidgetHost::Create(
+      delegate_.get(), *agent_scheduling_group_, process_->GetNextRoutingID());
   parent_layer_ = cc::Layer::Create();
   parent_view_.SetLayer(parent_layer_);
   layer_ = cc::Layer::Create();
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
index 7963225..465d9ff 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -388,6 +388,8 @@
     return widget_.ReceivedScreenRects();
   }
 
+  // Instance self-delete when its |agent_scheduling_groups|'s process will
+  // exit.
   static MockRenderWidgetHostImpl* Create(
       RenderWidgetHostDelegate* delegate,
       AgentSchedulingGroupHost& agent_scheduling_group,
@@ -419,7 +421,8 @@
   MockRenderWidgetHostImpl(RenderWidgetHostDelegate* delegate,
                            AgentSchedulingGroupHost& agent_scheduling_group,
                            int32_t routing_id)
-      : RenderWidgetHostImpl(delegate,
+      : RenderWidgetHostImpl(/*self_owned=*/true,
+                             delegate,
                              agent_scheduling_group,
                              routing_id,
                              /*hidden=*/false,
@@ -522,8 +525,6 @@
     EXPECT_EQ(view, host->GetView());
     view->Destroy();
     EXPECT_EQ(nullptr, host->GetView());
-
-    delete host;
   }
 
   void SetUpEnvironment() {
@@ -584,16 +585,9 @@
 
   void TearDownEnvironment() {
     sink_ = nullptr;
-    if (view_) {
+    if (view_)
       DestroyView(view_);
-    } else if (widget_host_) {
-      // Delete |widget_host_| in cases where |view_| gets destroyed
-      // by its parent, but the host does not get destroyed.
-      delete widget_host_;
-    }
-
     parent_view_->Destroy();
-    delete parent_host_;
 
     process_host_->Cleanup();
     agent_scheduling_group_host_ = nullptr;
@@ -3259,10 +3253,8 @@
   EXPECT_EQ(*views[1]->window_->layer()->GetOldestAcceptableFallback(),
             *views[1]->window_->layer()->GetSurfaceId());
 
-  for (size_t i = 0; i < renderer_count; ++i) {
+  for (size_t i = 0; i < renderer_count; ++i)
     views[i]->Destroy();
-    delete hosts[i];
-  }
 }
 
 // Test that changing the memory pressure should delete saved frames. This test
@@ -3330,10 +3322,8 @@
   base::RunLoop().RunUntilIdle();
   EXPECT_EVICTED(views[1]);
 
-  for (size_t i = 0; i < renderer_count; ++i) {
+  for (size_t i = 0; i < renderer_count; ++i)
     views[i]->Destroy();
-    delete hosts[i];
-  }
 }
 
 TEST_F(RenderWidgetHostViewAuraTest, SourceEventTypeExistsInLatencyInfo) {
@@ -5825,16 +5815,13 @@
 
   void TearDown() override {
     view_for_first_process_->Destroy();
-    delete widget_host_for_first_process_;
 
     view_for_second_process_->Destroy();
-    delete widget_host_for_second_process_;
     second_process_host_->Cleanup();
     second_agent_scheduling_group_host_.reset();
     second_process_host_.reset();
 
     view_for_third_process_->Destroy();
-    delete widget_host_for_third_process_;
     third_process_host_->Cleanup();
     third_agent_scheduling_group_host_.reset();
     third_process_host_.reset();
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame_unittest.cc b/content/browser/renderer_host/render_widget_host_view_child_frame_unittest.cc
index 35813c14..058e36f 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame_unittest.cc
@@ -124,7 +124,7 @@
     int32_t routing_id = process_host_->GetNextRoutingID();
     sink_ = &process_host_->sink();
 
-    widget_host_ = new RenderWidgetHostImpl(
+    widget_host_ = RenderWidgetHostImpl::Create(
         &delegate_, *agent_scheduling_group_host_, routing_id,
         /*hidden=*/false, std::make_unique<FrameTokenMessageQueue>());
 
@@ -143,7 +143,8 @@
 
     blink::ScreenInfo screen_info;
     screen_info.rect = gfx::Rect(1, 2, 3, 4);
-    view_ = RenderWidgetHostViewChildFrame::Create(widget_host_, screen_info);
+    view_ =
+        RenderWidgetHostViewChildFrame::Create(widget_host_.get(), screen_info);
     // Test we get the expected ScreenInfo before the FrameDelegate is set.
     blink::ScreenInfo actual_screen_info;
     view_->GetScreenInfo(&actual_screen_info);
@@ -159,7 +160,7 @@
     sink_ = nullptr;
     if (view_)
       view_->Destroy();
-    delete widget_host_;
+    widget_host_.reset();
     process_host_->Cleanup();
     agent_scheduling_group_host_ = nullptr;
     delete test_frame_connector_;
@@ -196,7 +197,7 @@
 
   // Tests should set these to NULL if they've already triggered their
   // destruction.
-  RenderWidgetHostImpl* widget_host_;
+  std::unique_ptr<RenderWidgetHostImpl> widget_host_;
   RenderWidgetHostViewChildFrame* view_;
   MockFrameConnector* test_frame_connector_;
 };
diff --git a/content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper_unittest.mm b/content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper_unittest.mm
index 79e1aaa..6bf39a6 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper_unittest.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper_unittest.mm
@@ -149,15 +149,16 @@
 
   @autoreleasepool {
     int32_t routing_id = process_host->GetNextRoutingID();
-    RenderWidgetHostImpl* render_widget = new RenderWidgetHostImpl(
-        &delegate, *agent_scheduling_group_host, routing_id,
-        /*hidden=*/false, std::make_unique<FrameTokenMessageQueue>());
+    std::unique_ptr<RenderWidgetHostImpl> render_widget =
+        RenderWidgetHostImpl::Create(
+            &delegate, *agent_scheduling_group_host, routing_id,
+            /*hidden=*/false, std::make_unique<FrameTokenMessageQueue>());
 
     ui::WindowResizeHelperMac::Get()->Init(base::ThreadTaskRunnerHandle::Get());
 
     // Owned by its |GetInProcessNSView()|, i.e. |rwhv_cocoa|.
     RenderWidgetHostViewMac* rwhv_mac =
-        new RenderWidgetHostViewMac(render_widget);
+        new RenderWidgetHostViewMac(render_widget.get());
     base::scoped_nsobject<RenderWidgetHostViewCocoa> rwhv_cocoa(
         [rwhv_mac->GetInProcessNSView() retain]);
 
@@ -178,9 +179,6 @@
     size_t num_edit_commands = [edit_command_strings count];
     EXPECT_EQ(delegate.edit_command_message_count_, num_edit_commands);
     rwhv_cocoa.reset();
-
-    // The |render_widget|'s process needs to be deleted within |message_loop|.
-    delete render_widget;
   }
   process_host->Cleanup();
   ui::WindowResizeHelperMac::Get()->ShutdownForTests();
diff --git a/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm b/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
index 2835c78..dd2d010 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
@@ -334,12 +334,12 @@
   MOCK_METHOD0(Blur, void());
 
   ui::LatencyInfo lastWheelEventLatencyInfo;
-  static MockRenderWidgetHostImpl* Create(
+  static std::unique_ptr<MockRenderWidgetHostImpl> Create(
       RenderWidgetHostDelegate* delegate,
       AgentSchedulingGroupHost& agent_scheduling_group_host,
       int32_t routing_id) {
-    return new MockRenderWidgetHostImpl(delegate, agent_scheduling_group_host,
-                                        routing_id);
+    return base::WrapUnique(new MockRenderWidgetHostImpl(
+        delegate, agent_scheduling_group_host, routing_id));
   }
 
   MockWidgetInputHandler* input_handler() { return &input_handler_; }
@@ -356,7 +356,8 @@
       RenderWidgetHostDelegate* delegate,
       AgentSchedulingGroupHost& agent_scheduling_group_host,
       int32_t routing_id)
-      : RenderWidgetHostImpl(delegate,
+      : RenderWidgetHostImpl(/*self_owned=*/false,
+                             delegate,
                              agent_scheduling_group_host,
                              routing_id,
                              /*hidden=*/false,
@@ -492,9 +493,9 @@
     process_host_->Init();
     agent_scheduling_group_host_ =
         std::make_unique<AgentSchedulingGroupHost>(*process_host_);
-    host_ = base::WrapUnique(MockRenderWidgetHostImpl::Create(
-        &delegate_, *agent_scheduling_group_host_,
-        process_host_->GetNextRoutingID()));
+    host_ = MockRenderWidgetHostImpl::Create(&delegate_,
+                                             *agent_scheduling_group_host_,
+                                             process_host_->GetNextRoutingID());
     mojo::AssociatedRemote<blink::mojom::FrameWidgetHost> frame_widget_host;
     auto frame_widget_host_receiver =
         frame_widget_host.BindNewEndpointAndPassDedicatedReceiver();
@@ -1327,9 +1328,10 @@
   AgentSchedulingGroupHost agent_scheduling_group_host(process_host);
   MockRenderWidgetHostDelegate delegate;
   int32_t routing_id = process_host.GetNextRoutingID();
-  MockRenderWidgetHostImpl* host = MockRenderWidgetHostImpl::Create(
-      &delegate, agent_scheduling_group_host, routing_id);
-  RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(host);
+  std::unique_ptr<MockRenderWidgetHostImpl> host =
+      MockRenderWidgetHostImpl::Create(&delegate, agent_scheduling_group_host,
+                                       routing_id);
+  RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(host.get());
   base::RunLoop().RunUntilIdle();
 
   // Send an initial wheel event for scrolling by 3 lines.
@@ -1362,7 +1364,8 @@
   const base::TimeDelta max_time_between_phase_ended_and_momentum_phase_began =
       view->max_time_between_phase_ended_and_momentum_phase_began_for_test();
 
-  host->ShutdownAndDestroyWidget(true);
+  host->ShutdownAndDestroyWidget(false);
+  host.reset();
 
   // Wait for the mouse_wheel_end_dispatch_timer_ to expire after host is
   // destroyed. The pending wheel end event won't get dispatched since the
@@ -1388,9 +1391,10 @@
   AgentSchedulingGroupHost agent_scheduling_group_host(process_host);
   MockRenderWidgetHostDelegate delegate;
   int32_t routing_id = process_host.GetNextRoutingID();
-  MockRenderWidgetHostImpl* host = MockRenderWidgetHostImpl::Create(
-      &delegate, agent_scheduling_group_host, routing_id);
-  RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(host);
+  std::unique_ptr<MockRenderWidgetHostImpl> host =
+      MockRenderWidgetHostImpl::Create(&delegate, agent_scheduling_group_host,
+                                       routing_id);
+  RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(host.get());
   base::RunLoop().RunUntilIdle();
 
   // Send an initial wheel event for scrolling by 3 lines.
@@ -1430,7 +1434,8 @@
   ASSERT_EQ("MouseWheel GestureScrollUpdate", GetMessageNames(events));
   DCHECK(!view->HasPendingWheelEndEventForTesting());
 
-  host->ShutdownAndDestroyWidget(true);
+  host->ShutdownAndDestroyWidget(false);
+  host.reset();
   process_host.Cleanup();
 }
 
@@ -1445,9 +1450,10 @@
   MockRenderWidgetHostDelegate delegate;
   AgentSchedulingGroupHost agent_scheduling_group_host(process_host);
   int32_t routing_id = process_host.GetNextRoutingID();
-  MockRenderWidgetHostImpl* host = MockRenderWidgetHostImpl::Create(
-      &delegate, agent_scheduling_group_host, routing_id);
-  RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(host);
+  std::unique_ptr<MockRenderWidgetHostImpl> host =
+      MockRenderWidgetHostImpl::Create(&delegate, agent_scheduling_group_host,
+                                       routing_id);
+  RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(host.get());
   base::RunLoop().RunUntilIdle();
 
   // Send an initial wheel event for scrolling by 3 lines.
@@ -1488,7 +1494,8 @@
   ASSERT_EQ("MouseWheel GestureScrollEnd MouseWheel", GetMessageNames(events));
   DCHECK(!view->HasPendingWheelEndEventForTesting());
 
-  host->ShutdownAndDestroyWidget(true);
+  host->ShutdownAndDestroyWidget(false);
+  host.reset();
   process_host.Cleanup();
 }
 
@@ -1755,12 +1762,13 @@
     child_widget_ = MockRenderWidgetHostImpl::Create(
         &delegate_, *child_agent_scheduling_group_host_,
         child_process_host_->GetNextRoutingID());
-    child_view_ = new TestRenderWidgetHostView(child_widget_);
+    child_view_ = new TestRenderWidgetHostView(child_widget_.get());
     base::RunLoop().RunUntilIdle();
   }
 
   void TearDown() override {
-    child_widget_->ShutdownAndDestroyWidget(true);
+    child_widget_->ShutdownAndDestroyWidget(false);
+    child_widget_.reset();
     child_process_host_->Cleanup();
     child_agent_scheduling_group_host_.reset();
     child_process_host_.reset();
@@ -1795,7 +1803,7 @@
  protected:
   std::unique_ptr<MockRenderProcessHost> child_process_host_;
   std::unique_ptr<AgentSchedulingGroupHost> child_agent_scheduling_group_host_;
-  MockRenderWidgetHostImpl* child_widget_;
+  std::unique_ptr<MockRenderWidgetHostImpl> child_widget_;
   TestRenderWidgetHostView* child_view_;
 
  private:
@@ -1812,7 +1820,7 @@
   // unmarkText would lead to an IPC. This assumption is made in other similar
   // tests as well). We should observe an IPC being sent to the |child_widget_|.
   SetTextInputType(child_view_, ui::TEXT_INPUT_TYPE_TEXT);
-  EXPECT_EQ(child_widget_, text_input_manager()->GetActiveWidget());
+  EXPECT_EQ(child_widget_.get(), text_input_manager()->GetActiveWidget());
   [tab_GetInProcessNSView() unmarkText];
   base::RunLoop().RunUntilIdle();
   MockWidgetInputHandler::MessageVector events =
@@ -1840,7 +1848,7 @@
   // Make the child view active and then call setMarkedText with some values. We
   // should observe an IPC being sent to the |child_widget_|.
   SetTextInputType(child_view_, ui::TEXT_INPUT_TYPE_TEXT);
-  EXPECT_EQ(child_widget_, text_input_manager()->GetActiveWidget());
+  EXPECT_EQ(child_widget_.get(), text_input_manager()->GetActiveWidget());
   [tab_GetInProcessNSView() setMarkedText:text
                             selectedRange:selectedRange
                          replacementRange:replacementRange];
@@ -1871,7 +1879,7 @@
   // Make the child view active and then call insertText with some values. We
   // should observe an IPC being sent to the |child_widget_|.
   SetTextInputType(child_view_, ui::TEXT_INPUT_TYPE_TEXT);
-  EXPECT_EQ(child_widget_, text_input_manager()->GetActiveWidget());
+  EXPECT_EQ(child_widget_.get(), text_input_manager()->GetActiveWidget());
   [tab_GetInProcessNSView() insertText:text replacementRange:replacementRange];
   base::RunLoop().RunUntilIdle();
   MockWidgetInputHandler::MessageVector events =
@@ -1899,7 +1907,7 @@
   // Make child view active and then call finishComposingText. We should observe
   // an IPC being sent to the |child_widget_|.
   SetTextInputType(child_view_, ui::TEXT_INPUT_TYPE_TEXT);
-  EXPECT_EQ(child_widget_, text_input_manager()->GetActiveWidget());
+  EXPECT_EQ(child_widget_.get(), text_input_manager()->GetActiveWidget());
   // In order to finish composing text, we must first have some marked text. So,
   // we will first call setMarkedText on cocoa view. This would lead to a set
   // composition IPC in the sink, but it doesn't matter since we will be looking
@@ -1941,7 +1949,7 @@
   EXPECT_FALSE(ui::ScopedPasswordInputEnabler::IsPasswordInputEnabled());
 
   SetTextInputType(child_view_, ui::TEXT_INPUT_TYPE_PASSWORD);
-  ASSERT_EQ(child_widget_, text_input_manager()->GetActiveWidget());
+  ASSERT_EQ(child_widget_.get(), text_input_manager()->GetActiveWidget());
   ASSERT_EQ(text_input_manager(), tab_view()->GetTextInputManager());
   ASSERT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, tab_view()->GetTextInputType());
 
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 0e918ff..16d2127 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -3719,7 +3719,7 @@
     return nullptr;
   }
 
-  RenderWidgetHostImpl* widget_host = new RenderWidgetHostImpl(
+  RenderWidgetHostImpl* widget_host = RenderWidgetHostImpl::CreateSelfOwned(
       this, agent_scheduling_group, route_id, IsHidden(),
       std::make_unique<FrameTokenMessageQueue>());
 
diff --git a/content/common/navigation_params.cc b/content/common/navigation_params.cc
index 4d0b164..faa9ace 100644
--- a/content/common/navigation_params.cc
+++ b/content/common/navigation_params.cc
@@ -10,8 +10,7 @@
 mojom::InitiatorCSPInfoPtr CreateInitiatorCSPInfo() {
   return mojom::InitiatorCSPInfo::New(
       network::mojom::CSPDisposition::CHECK,
-      std::vector<network::mojom::ContentSecurityPolicyPtr>() /* empty */,
-      nullptr /* initiator_self_source */
+      std::vector<network::mojom::ContentSecurityPolicyPtr>() /* empty */
   );
 }
 
diff --git a/content/common/navigation_params.mojom b/content/common/navigation_params.mojom
index 38031af..64c4b56 100644
--- a/content/common/navigation_params.mojom
+++ b/content/common/navigation_params.mojom
@@ -51,9 +51,8 @@
   network.mojom.CSPDisposition should_check_main_world_csp =
       network.mojom.CSPDisposition.CHECK;
 
-  // The relevant CSP policies and the initiator 'self' source to be used.
+  // The relevant CSP policies.
   array<network.mojom.ContentSecurityPolicy> initiator_csp;
-  network.mojom.CSPSource? initiator_self_source;
 };
 
 enum NavigationType {
diff --git a/content/common/origin_util.cc b/content/common/origin_util.cc
index fa76c3e..8654a973 100644
--- a/content/common/origin_util.cc
+++ b/content/common/origin_util.cc
@@ -27,8 +27,4 @@
   return false;
 }
 
-bool IsPotentiallyTrustworthyOrigin(const url::Origin& origin) {
-  return network::IsOriginPotentiallyTrustworthy(origin);
-}
-
 }  // namespace content
diff --git a/content/common/origin_util_unittest.cc b/content/common/origin_util_unittest.cc
deleted file mode 100644
index edbe97f..0000000
--- a/content/common/origin_util_unittest.cc
+++ /dev/null
@@ -1,26 +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.
-
-#include "content/public/common/origin_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-namespace content {
-
-TEST(OriginUtilTest, IsPotentiallyTrustworthyOrigin) {
-  EXPECT_FALSE(
-      IsPotentiallyTrustworthyOrigin(url::Origin::Create(GURL("about:blank"))));
-  EXPECT_FALSE(IsPotentiallyTrustworthyOrigin(
-      url::Origin::Create(GURL("about:blank#ref"))));
-  EXPECT_FALSE(IsPotentiallyTrustworthyOrigin(
-      url::Origin::Create(GURL("about:srcdoc"))));
-
-  EXPECT_FALSE(IsPotentiallyTrustworthyOrigin(
-      url::Origin::Create(GURL("javascript:alert('blah')"))));
-
-  EXPECT_FALSE(IsPotentiallyTrustworthyOrigin(
-      url::Origin::Create(GURL("data:test/plain;blah"))));
-}
-
-}  // namespace content
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 2021868..21b56c26 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -897,11 +897,6 @@
 const char kDisableAcceleratedVideoDecode[] =
     "disable-accelerated-video-decode";
 
-#if (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && !defined(OS_ANDROID)
-// Enables hardware acceleration of video decoding on linux. (defaults to off)
-const char kEnableAcceleratedVideoDecode[] = "enable-accelerated-video-decode";
-#endif
-
 #if defined(OS_ANDROID)
 // Disable Media Session API
 const char kDisableMediaSessionAPI[] = "disable-media-session-api";
diff --git a/content/public/common/origin_util.h b/content/public/common/origin_util.h
index d3457a1..7d30bc8 100644
--- a/content/public/common/origin_util.h
+++ b/content/public/common/origin_util.h
@@ -16,13 +16,6 @@
 // http (localhost only), https, or a custom-set secure scheme.
 bool CONTENT_EXPORT OriginCanAccessServiceWorkers(const GURL& url);
 
-// This is based on SecurityOrigin::isPotentiallyTrustworthy and tries to mimic
-// its behavior.
-//
-// TODO(https://crbug.com/1153336): Remove this function and use
-// network::IsOriginPotentiallyTrustworthy instead.
-bool CONTENT_EXPORT IsPotentiallyTrustworthyOrigin(const url::Origin& origin);
-
 }  // namespace content
 
 #endif  // CONTENT_PUBLIC_COMMON_ORIGIN_UTIL_H_
diff --git a/content/renderer/content_security_policy_util.cc b/content/renderer/content_security_policy_util.cc
index c933b66..1e2f40a0 100644
--- a/content/renderer/content_security_policy_util.cc
+++ b/content/renderer/content_security_policy_util.cc
@@ -36,6 +36,8 @@
     const blink::WebContentSecurityPolicy& policy_in) {
   auto policy = network::mojom::ContentSecurityPolicy::New();
 
+  policy->self_origin = BuildCSPSource(policy_in.self_origin);
+
   policy->header = network::mojom::ContentSecurityPolicyHeader::New(
       policy_in.header.Utf8(), policy_in.disposition, policy_in.source);
   policy->use_reporting_api = policy_in.use_reporting_api;
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index f1df03c..33e6dfc 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -572,8 +572,6 @@
   auto initiator_csp_info = mojom::InitiatorCSPInfo::New();
   initiator_csp_info->should_check_main_world_csp =
       info->should_check_main_world_content_security_policy;
-  initiator_csp_info->initiator_self_source =
-      BuildCSPSource(info->initiator_self_source);
   for (const auto& policy : info->initiator_csp) {
     initiator_csp_info->initiator_csp.push_back(
         BuildContentSecurityPolicy(policy));
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index aa0472b..a52c3c7 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -1104,7 +1104,7 @@
 
   const bool enable_video_accelerator =
 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
-      cmd_line->HasSwitch(switches::kEnableAcceleratedVideoDecode) &&
+      base::FeatureList::IsEnabled(media::kVaapiVideoDecodeLinux) &&
 #else
       !cmd_line->HasSwitch(switches::kDisableAcceleratedVideoDecode) &&
 #endif  // defined(OS_LINUX) && !defined(OS_CHROMEOS)
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 3f001ba..1a2db75 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -2065,7 +2065,6 @@
     "../common/input/touch_event_stream_validator_unittest.cc",
     "../common/inter_process_time_ticks_converter_unittest.cc",
     "../common/net/ip_address_space_util_unittest.cc",
-    "../common/origin_util_unittest.cc",
     "../common/service_manager/service_manager_connection_impl_unittest.cc",
     "../common/service_worker/service_worker_utils_unittest.cc",
     "../common/state_transitions_unittest.cc",
diff --git a/content/test/navigation_simulator_impl.cc b/content/test/navigation_simulator_impl.cc
index 112d2bf..40c2219 100644
--- a/content/test/navigation_simulator_impl.cc
+++ b/content/test/navigation_simulator_impl.cc
@@ -1176,7 +1176,7 @@
   common_params->has_user_gesture = has_user_gesture_;
   common_params->initiator_csp_info = mojom::InitiatorCSPInfo::New(
       should_check_main_world_csp_,
-      std::vector<network::mojom::ContentSecurityPolicyPtr>(), nullptr);
+      std::vector<network::mojom::ContentSecurityPolicyPtr>());
 
   mojo::PendingAssociatedRemote<mojom::NavigationClient>
       navigation_client_remote;
diff --git a/content/test/test_render_widget_host.cc b/content/test/test_render_widget_host.cc
index 5e16091..35a7278d 100644
--- a/content/test/test_render_widget_host.cc
+++ b/content/test/test_render_widget_host.cc
@@ -25,7 +25,8 @@
     AgentSchedulingGroupHost& agent_scheduling_group,
     int32_t routing_id,
     bool hidden)
-    : RenderWidgetHostImpl(delegate,
+    : RenderWidgetHostImpl(/*self_owned=*/false,
+                           delegate,
                            agent_scheduling_group,
                            routing_id,
                            hidden,
diff --git a/google_apis/drive/drive_common_callbacks.h b/google_apis/drive/drive_common_callbacks.h
index 67674a4..cccf52f8c 100644
--- a/google_apis/drive/drive_common_callbacks.h
+++ b/google_apis/drive/drive_common_callbacks.h
@@ -25,9 +25,6 @@
 // request is already finished, nothing happens.
 typedef base::OnceClosure CancelCallbackOnce;
 typedef base::RepeatingClosure CancelCallbackRepeating;
-// TODO(https://crbug.com/1007686): Remove usage of CancelCallback.
-// All remaining usages are outside of google_apis/drive.
-typedef base::Closure CancelCallback;
 
 }  // namespace google_apis
 
diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg
index a059662..b9e0e53 100644
--- a/infra/config/generated/cr-buildbucket.cfg
+++ b/infra/config/generated/cr-buildbucket.cfg
@@ -20340,7 +20340,7 @@
         cmd: "recipes"
       }
       properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"$recipe_engine/isolated\":{\"server\":\"https://isolateserver.appspot.com\"},\"builder_group\":\"chromium\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 21600
+      execution_timeout_secs: 25200
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
       experiments {
@@ -21461,7 +21461,7 @@
         cmd: "recipes"
       }
       properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"$recipe_engine/isolated\":{\"server\":\"https://isolateserver.appspot.com\"},\"builder_group\":\"chromium\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 21600
+      execution_timeout_secs: 25200
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
       experiments {
diff --git a/infra/config/subprojects/chromium/ci.star b/infra/config/subprojects/chromium/ci.star
index a607a0a..75f620c8 100644
--- a/infra/config/subprojects/chromium/ci.star
+++ b/infra/config/subprojects/chromium/ci.star
@@ -1235,7 +1235,9 @@
     ),
     cores = 32,
     os = os.WINDOWS_DEFAULT,
-    execution_timeout = 6 * time.hour,
+    # TODO(crbug.com/1155416):
+    # builds with PGO change take long time.
+    execution_timeout = 7 * time.hour,
     tree_closing = False,
 )
 
@@ -1272,7 +1274,9 @@
     ),
     cores = 32,
     os = os.WINDOWS_DEFAULT,
-    execution_timeout = 6 * time.hour,
+    # TODO(crbug.com/1155416):
+    # builds with PGO change take long time.
+    execution_timeout = 7 * time.hour,
     tree_closing = False,
 )
 
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/full_card_request_result_delegate_bridge.h b/ios/chrome/browser/ui/autofill/manual_fill/full_card_request_result_delegate_bridge.h
index 70dbf67..10c0868 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/full_card_request_result_delegate_bridge.h
+++ b/ios/chrome/browser/ui/autofill/manual_fill/full_card_request_result_delegate_bridge.h
@@ -43,7 +43,8 @@
       const autofill::payments::FullCardRequest& full_card_request,
       const autofill::CreditCard& card,
       const base::string16& cvc) override;
-  void OnFullCardRequestFailed() override;
+  void OnFullCardRequestFailed(
+      autofill::payments::FullCardRequest::FailureType failure_type) override;
 
   __weak id<FullCardRequestResultDelegateObserving> delegate_ = nil;
   base::WeakPtrFactory<FullCardRequestResultDelegateBridge> weak_ptr_factory_;
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/full_card_request_result_delegate_bridge.mm b/ios/chrome/browser/ui/autofill/manual_fill/full_card_request_result_delegate_bridge.mm
index 5aa41ed..06a0907 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/full_card_request_result_delegate_bridge.mm
+++ b/ios/chrome/browser/ui/autofill/manual_fill/full_card_request_result_delegate_bridge.mm
@@ -32,6 +32,7 @@
   [delegate_ onFullCardRequestSucceeded:card];
 }
 
-void FullCardRequestResultDelegateBridge::OnFullCardRequestFailed() {
+void FullCardRequestResultDelegateBridge::OnFullCardRequestFailed(
+    autofill::payments::FullCardRequest::FailureType /* failure_type */) {
   [delegate_ onFullCardRequestFailed];
 }
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/full_card_requester_unittest.mm b/ios/chrome/browser/ui/autofill/manual_fill/full_card_requester_unittest.mm
index f8bb7ec6..326b4b9 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/full_card_requester_unittest.mm
+++ b/ios/chrome/browser/ui/autofill/manual_fill/full_card_requester_unittest.mm
@@ -46,7 +46,9 @@
       const autofill::CreditCard& card,
       const base::string16& cvc) override {}
 
-  void OnFullCardRequestFailed() override {}
+  void OnFullCardRequestFailed(
+      autofill::payments::FullCardRequest::FailureType /* failure_type */)
+      override {}
 
   base::WeakPtr<FakeResultDelegate> GetWeakPtr() {
     return weak_ptr_factory_.GetWeakPtr();
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_egtest.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_egtest.mm
index 24b1605..ef480f30 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_egtest.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_egtest.mm
@@ -254,8 +254,7 @@
       assertWithMatcher:grey_nil()];
 }
 
-// TODO(crbug.com/1037651): Test fails.
-- (void)DISABLED_testCloseNTPWhenSwitching {
+- (void)testCloseNTPWhenSwitching {
   // Open the first page.
   GURL URL1 = self.testServer->GetURL(kPage1URL);
   [ChromeEarlGrey loadURL:URL1];
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_strip/tab_strip_view_controller.mm b/ios/chrome/browser/ui/tab_switcher/tab_strip/tab_strip_view_controller.mm
index d0ccb1b..b240302 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_strip/tab_strip_view_controller.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_strip/tab_strip_view_controller.mm
@@ -27,7 +27,6 @@
 // Default image insets for the new tab button.
 const CGFloat kNewTabButtonLeadingImageInset = -10.0;
 const CGFloat kNewTabButtonBottomImageInset = -2.0;
-
 }  // namespace
 
 @interface TabStripViewController () <TabStripCellDelegate>
@@ -40,6 +39,9 @@
 @property(nonatomic, copy) NSString* selectedItemID;
 // Index of the selected item in |items|.
 @property(nonatomic, readonly) NSUInteger selectedIndex;
+// Constraints that are used when the button needs to be kept next to the last
+// cell.
+@property NSLayoutConstraint* lastCellConstraint;
 
 @end
 
@@ -72,7 +74,7 @@
   [self.view addSubview:self.buttonNewTab];
   [NSLayoutConstraint activateConstraints:@[
     [self.buttonNewTab.trailingAnchor
-        constraintEqualToAnchor:self.view.trailingAnchor],
+        constraintLessThanOrEqualToAnchor:self.view.trailingAnchor],
     [self.buttonNewTab.topAnchor constraintEqualToAnchor:self.view.topAnchor],
     [self.buttonNewTab.heightAnchor
         constraintEqualToAnchor:self.view.heightAnchor],
@@ -80,6 +82,11 @@
         constraintEqualToConstant:kNewTabButtonWidth],
   ]];
 
+  self.lastCellConstraint = [self.buttonNewTab.leadingAnchor
+      constraintEqualToAnchor:self.view.trailingAnchor];
+  self.lastCellConstraint.priority = UILayoutPriorityDefaultHigh;
+  self.lastCellConstraint.active = YES;
+
   [self.buttonNewTab addTarget:self
                         action:@selector(sendNewTabCommand)
               forControlEvents:UIControlEventTouchUpInside];
@@ -110,6 +117,29 @@
   return cell;
 }
 
+- (void)collectionView:(UICollectionView*)collectionView
+       willDisplayCell:(UICollectionViewCell*)cell
+    forItemAtIndexPath:(NSIndexPath*)indexPath {
+  NSInteger numberOfItems = [self collectionView:collectionView
+                          numberOfItemsInSection:indexPath.section];
+  if (indexPath.row == numberOfItems - 1) {
+    // Adding a constant to the button's contraints to keep it next to the last
+    // cell using the given collectionView and cell.
+    CGFloat newConstant = -(collectionView.bounds.size.width -
+                            (cell.frame.origin.x + cell.frame.size.width));
+    self.lastCellConstraint.constant = newConstant;
+  }
+}
+
+- (void)scrollViewDidScroll:(UIScrollView*)scrollView {
+  // Adding a constant to the button's contraints to keep it next to the last
+  // cell while scrolling with given scrollView.
+  CGFloat newConstant = scrollView.contentSize.width -
+                        scrollView.contentOffset.x -
+                        scrollView.bounds.size.width;
+  self.lastCellConstraint.constant = newConstant;
+}
+
 #pragma mark - TabStripConsumer
 
 - (void)populateItems:(NSArray<TabSwitcherItem*>*)items
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
index 0b9a5cc8..0b11282 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-e8cc68e7f0a9462e7fe5176f72c0472b0d43f798
\ No newline at end of file
+2b3d204e5918d247b8e90f73e12835955dcc58d5
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
index 3a6af793..9e1deefc 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-8b4ba9ac6d9db8818ca21e0da16edf6c9b7596b6
\ No newline at end of file
+1315245f706a6c58602a83f60bf2a1ad1220a44d
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
index 3cad4a7..b242833 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-07706cc502d4e96f8cd467cc21928fac20f2ad5e
\ No newline at end of file
+1389d75fb3829ebedeae6955b19b41a21dcd93e1
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
index 7e6a680..ea84dcf 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-196af581649bc19a3ec986a79f3dea7785abbf3d
\ No newline at end of file
+2980294d0e3dcd2d0bf77b9d0141398d109b0246
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
index 521ef566..04bd590 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-2794e08bd996f366ef29661aec67b2ac55f1d36d
\ No newline at end of file
+9453ec87331f63de623d0482efa16c3036c7ca86
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
index 173fe76..68ca5c1a 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-9f82383e0b823c90af30e49bee1b0f175d24f72d
\ No newline at end of file
+5dfe95b60108c50d96450b9b22a1b997b7dd8ca7
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
index 5b2b871..6596e1c 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-5cc00d13e041eddf6ecb6d24097c1d3680c6fba1
\ No newline at end of file
+0a0913037c289c2a95507ace0e373259b847fc2f
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
index b30de96..4c6355b 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-f2a5782397ad41a258e4d1a4fe6c5ac3449c9ed7
\ No newline at end of file
+ce6382cadc89ca61b10f8e6b2ab2c18b88af2b5f
\ No newline at end of file
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index b789187..be4e0f6 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -428,6 +428,13 @@
 const base::Feature kUnifiedAutoplay{"UnifiedAutoplay",
                                      base::FEATURE_ENABLED_BY_DEFAULT};
 
+#if (defined(OS_LINUX) || defined(OS_FREEBSD)) && !defined(OS_CHROMEOS)
+// Enable vaapi video decoding on linux. This is already enabled by default on
+// chromeos, but needs an experiment on linux.
+const base::Feature kVaapiVideoDecodeLinux{"VaapiVideoDecoder",
+                                           base::FEATURE_DISABLED_BY_DEFAULT};
+#endif  // (defined(OS_LINUX) || defined(OS_FREEBSD)) && !defined(OS_CHROMEOS)
+
 // Enable VA-API hardware decode acceleration for AV1.
 const base::Feature kVaapiAV1Decoder{"VaapiAV1Decoder",
                                      base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/media/base/media_switches.h b/media/base/media_switches.h
index f83346d..1b6792e 100644
--- a/media/base/media_switches.h
+++ b/media/base/media_switches.h
@@ -171,6 +171,9 @@
 MEDIA_EXPORT extern const base::Feature kUseMediaHistoryStore;
 MEDIA_EXPORT extern const base::Feature kUseR16Texture;
 MEDIA_EXPORT extern const base::Feature kUseSodaForLiveCaption;
+#if (defined(OS_LINUX) || defined(OS_FREEBSD)) && !defined(OS_CHROMEOS)
+MEDIA_EXPORT extern const base::Feature kVaapiVideoDecodeLinux;
+#endif  // (defined(OS_LINUX) || defined(OS_FREEBSD)) && !defined(OS_CHROMEOS)
 MEDIA_EXPORT extern const base::Feature kVaapiAV1Decoder;
 MEDIA_EXPORT extern const base::Feature kVaapiLowPowerEncoderGen9x;
 MEDIA_EXPORT extern const base::Feature kVaapiEnforceVideoMinMaxResolution;
diff --git a/media/video/gpu_memory_buffer_video_frame_pool.cc b/media/video/gpu_memory_buffer_video_frame_pool.cc
index ed32389..ed4238b 100644
--- a/media/video/gpu_memory_buffer_video_frame_pool.cc
+++ b/media/video/gpu_memory_buffer_video_frame_pool.cc
@@ -456,7 +456,23 @@
   DCHECK_LE(bytes_per_row, std::abs(dest_stride_uv));
   DCHECK_EQ(0, first_row % 2);
   DCHECK(source_frame->format() == PIXEL_FORMAT_I420 ||
-         source_frame->format() == PIXEL_FORMAT_YV12);
+         source_frame->format() == PIXEL_FORMAT_YV12 ||
+         source_frame->format() == PIXEL_FORMAT_NV12);
+  if (source_frame->format() == PIXEL_FORMAT_NV12) {
+    libyuv::CopyPlane(source_frame->visible_data(VideoFrame::kYPlane) +
+                          first_row * source_frame->stride(VideoFrame::kYPlane),
+                      source_frame->stride(VideoFrame::kYPlane),
+                      dest_y + first_row * dest_stride_y, dest_stride_y,
+                      bytes_per_row, rows);
+    libyuv::CopyPlane(
+        source_frame->visible_data(VideoFrame::kUVPlane) +
+            first_row / 2 * source_frame->stride(VideoFrame::kUVPlane),
+        source_frame->stride(VideoFrame::kUVPlane),
+        dest_uv + first_row / 2 * dest_stride_uv, dest_stride_uv, bytes_per_row,
+        rows / 2);
+
+    return;
+  }
   libyuv::I420ToNV12(
       source_frame->visible_data(VideoFrame::kYPlane) +
           first_row * source_frame->stride(VideoFrame::kYPlane),
@@ -642,6 +658,12 @@
   if (!IOSurfaceCanSetColorSpace(video_frame->ColorSpace()))
     passthrough = true;
 #endif
+
+  if (!video_frame->IsMappable()) {
+    // Already a hardware frame.
+    passthrough = true;
+  }
+
   if (output_format_ == GpuVideoAcceleratorFactories::OutputFormat::UNDEFINED)
     passthrough = true;
   switch (pixel_format) {
@@ -650,11 +672,11 @@
     case PIXEL_FORMAT_I420:
     case PIXEL_FORMAT_YUV420P10:
     case PIXEL_FORMAT_I420A:
+    case PIXEL_FORMAT_NV12:
       break;
     // Unsupported cases.
     case PIXEL_FORMAT_I422:
     case PIXEL_FORMAT_I444:
-    case PIXEL_FORMAT_NV12:
     case PIXEL_FORMAT_NV21:
     case PIXEL_FORMAT_UYVY:
     case PIXEL_FORMAT_YUY2:
diff --git a/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc b/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc
index e9821951..6ffe20d 100644
--- a/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc
+++ b/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc
@@ -116,6 +116,30 @@
     return video_frame;
   }
 
+  static scoped_refptr<VideoFrame> CreateTestNV12VideoFrame(int dimension) {
+    const int kDimension = 10;
+    static uint8_t y_data[kDimension * kDimension] = {0};
+    // Subsampled by 2x2, two components.
+    static uint8_t uv_data[kDimension * kDimension / 2] = {0};
+
+    const VideoPixelFormat format = PIXEL_FORMAT_NV12;
+    DCHECK_LE(dimension, kDimension);
+    const gfx::Size size(dimension, dimension);
+
+    scoped_refptr<VideoFrame> video_frame =
+        VideoFrame::WrapExternalYuvData(format,              // format
+                                        size,                // coded_size
+                                        gfx::Rect(size),     // visible_rect
+                                        size,                // natural_size
+                                        size.width(),        // y_stride
+                                        size.width(),        // uv_stride
+                                        y_data,              // y_data
+                                        uv_data,             // uv_data
+                                        base::TimeDelta());  // timestamp
+    EXPECT_TRUE(video_frame);
+    return video_frame;
+  }
+
   // Note, the X portion is set to 1 since it may use ARGB instead of
   // XRGB on some platforms.
   uint32_t as_xr30(uint32_t r, uint32_t g, uint32_t b) {
@@ -304,6 +328,22 @@
   EXPECT_TRUE(frame->metadata()->read_lock_fences_enabled);
 }
 
+TEST_F(GpuMemoryBufferVideoFramePoolTest, CreateOneHardwareFrameForNV12Input) {
+  scoped_refptr<VideoFrame> software_frame = CreateTestNV12VideoFrame(10);
+  scoped_refptr<VideoFrame> frame;
+  mock_gpu_factories_->SetVideoFrameOutputFormat(
+      media::GpuVideoAcceleratorFactories::OutputFormat::NV12_DUAL_GMB);
+  gpu_memory_buffer_pool_->MaybeCreateHardwareFrame(
+      software_frame, base::BindOnce(MaybeCreateHardwareFrameCallback, &frame));
+
+  RunUntilIdle();
+
+  EXPECT_NE(software_frame.get(), frame.get());
+  EXPECT_EQ(PIXEL_FORMAT_NV12, frame->format());
+  EXPECT_EQ(2u, frame->NumTextures());
+  EXPECT_EQ(2u, sii_->shared_image_count());
+}
+
 TEST_F(GpuMemoryBufferVideoFramePoolTest, CreateOneHardwareXR30Frame) {
   scoped_refptr<VideoFrame> software_frame = CreateTestYUVVideoFrame(10, 10);
   scoped_refptr<VideoFrame> frame;
diff --git a/media/video/vpx_video_encoder.cc b/media/video/vpx_video_encoder.cc
index 7e23a78..15f6c948 100644
--- a/media/video/vpx_video_encoder.cc
+++ b/media/video/vpx_video_encoder.cc
@@ -228,6 +228,7 @@
   }
 
   options_ = options;
+  originally_configured_size_ = options.frame_size;
   output_cb_ = BindToCurrentLoop(std::move(output_cb));
   codec_ = std::move(codec);
   std::move(done_cb).Run(Status());
@@ -356,18 +357,42 @@
     return;
   }
 
-  auto old_area = options_.frame_size.GetCheckedArea();
-  auto new_area = options.frame_size.GetCheckedArea();
-  DCHECK(old_area.IsValid());
-
-  // Libvpx doesn't support reconfiguring in a way that enlarges frame area.
-  // https://bugs.chromium.org/p/webm/issues/detail?id=1642
-  if (!new_area.IsValid() || new_area.ValueOrDie() > old_area.ValueOrDie()) {
-    auto status =
-        Status(StatusCode::kEncoderUnsupportedConfig,
-               "libvpx doesn't support dynamically increasing frame area");
-    std::move(done_cb).Run(std::move(status));
-    return;
+  // Libvpx is very peculiar about encoded frame size changes,
+  // - VP8: As long as the frame area doesn't increase, internal codec
+  //        structures don't need to be reallocated and codec can be simply
+  //        reconfigured.
+  // - VP9: The codec cannot increase encoded width or height larger than their
+  //        initial values.
+  //
+  // Mind the difference between old frame sizes:
+  // - |originally_configured_size_| is set only once when the vpx_codec_ctx_t
+  // is created.
+  // - |options_.frame_size| changes every time ChangeOptions() is called.
+  // More info can be found here:
+  //   https://bugs.chromium.org/p/webm/issues/detail?id=1642
+  //   https://bugs.chromium.org/p/webm/issues/detail?id=912
+  if (profile_ == VP8PROFILE_ANY) {
+    // VP8 resize restrictions
+    auto old_area = originally_configured_size_.GetCheckedArea();
+    auto new_area = options.frame_size.GetCheckedArea();
+    DCHECK(old_area.IsValid());
+    if (!new_area.IsValid() || new_area.ValueOrDie() > old_area.ValueOrDie()) {
+      auto status = Status(
+          StatusCode::kEncoderUnsupportedConfig,
+          "libvpx/VP8 doesn't support dynamically increasing frame area");
+      std::move(done_cb).Run(std::move(status));
+      return;
+    }
+  } else {
+    // VP9 resize restrictions
+    if (options.frame_size.width() > originally_configured_size_.width() ||
+        options.frame_size.height() > originally_configured_size_.height()) {
+      auto status = Status(
+          StatusCode::kEncoderUnsupportedConfig,
+          "libvpx/VP9 doesn't support dynamically increasing frame dimentions");
+      std::move(done_cb).Run(std::move(status));
+      return;
+    }
   }
 
   vpx_codec_enc_cfg_t new_config = codec_config_;
diff --git a/media/video/vpx_video_encoder.h b/media/video/vpx_video_encoder.h
index eee7a1d..cd5a17b 100644
--- a/media/video/vpx_video_encoder.h
+++ b/media/video/vpx_video_encoder.h
@@ -44,6 +44,7 @@
   bool is_vp9_ = false;
   vpx_codec_enc_cfg_t codec_config_ = {};
   vpx_image_t vpx_image_ = {};
+  gfx::Size originally_configured_size_;
   base::TimeDelta last_frame_timestamp_;
   VideoCodecProfile profile_ = VIDEO_CODEC_PROFILE_UNKNOWN;
   Options options_;
diff --git a/remoting/codec/webrtc_video_encoder_gpu.cc b/remoting/codec/webrtc_video_encoder_gpu.cc
index 30958ed..28ff19b 100644
--- a/remoting/codec/webrtc_video_encoder_gpu.cc
+++ b/remoting/codec/webrtc_video_encoder_gpu.cc
@@ -275,6 +275,17 @@
 // static
 bool WebrtcVideoEncoderGpu::IsSupportedByH264(
     const WebrtcVideoEncoderSelector::Profile& profile) {
+#if defined(OS_WIN)
+  // This object is required by Chromium to ensure proper init/uninit of COM on
+  // this thread.  The guidance is to match the lifetime of this object to the
+  // lifetime of the thread if possible.  Since we are still experimenting with
+  // H.264 and run the encoder on a different thread, we use a locally scoped
+  // object for now.
+  // TODO(joedow): Use a COMscoped Autothread (or run in a separate process) if
+  // H.264 becomes a common use case for us.
+  base::win::ScopedCOMInitializer scoped_com_initializer;
+#endif
+
   media::VideoEncodeAccelerator::SupportedProfiles profiles =
       media::GpuVideoEncodeAcceleratorFactory::GetSupportedProfiles(
           CreateGpuPreferences(), CreateGpuWorkarounds());
diff --git a/remoting/codec/webrtc_video_encoder_gpu.h b/remoting/codec/webrtc_video_encoder_gpu.h
index e862647..bbcfdc7 100644
--- a/remoting/codec/webrtc_video_encoder_gpu.h
+++ b/remoting/codec/webrtc_video_encoder_gpu.h
@@ -7,11 +7,16 @@
 
 #include "base/memory/shared_memory_mapping.h"
 #include "base/memory/unsafe_shared_memory_region.h"
+#include "build/build_config.h"
 #include "media/video/video_encode_accelerator.h"
 #include "remoting/codec/encoder_bitrate_filter.h"
 #include "remoting/codec/webrtc_video_encoder.h"
 #include "remoting/codec/webrtc_video_encoder_selector.h"
 
+#if defined(OS_WIN)
+#include "base/win/scoped_com_initializer.h"
+#endif
+
 namespace remoting {
 
 // A WebrtcVideoEncoder implementation utilizing the VideoEncodeAccelerator
@@ -72,6 +77,17 @@
 
   void RunAnyPendingEncode();
 
+#if defined(OS_WIN)
+  // This object is required by Chromium to ensure proper init/uninit of COM on
+  // this thread.  The guidance is to match the lifetime of this object to the
+  // lifetime of the thread if possible.  Since we are still experimenting with
+  // H.264 and run the encoder on a different thread, we use an object-lifetime
+  // scoped instance for now.
+  // TODO(joedow): Use a COMscoped Autothread (or run in a separate process) if
+  // H.264 becomes a common use case for us.
+  base::win::ScopedCOMInitializer scoped_com_initializer_;
+#endif
+
   State state_;
 
   // Only after the first encode request do we know how large the incoming
diff --git a/services/media_session/public/cpp/test/mock_media_session.cc b/services/media_session/public/cpp/test/mock_media_session.cc
index 28fc9fb..1ac3d61 100644
--- a/services/media_session/public/cpp/test/mock_media_session.cc
+++ b/services/media_session/public/cpp/test/mock_media_session.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/ranges/algorithm.h"
 #include "base/stl_util.h"
 
 namespace media_session {
@@ -66,10 +67,14 @@
       expected_controllable_ == session_info_->is_controllable) {
     run_loop_->Quit();
     expected_controllable_.reset();
-  } else if (wanted_state_ == session_info_->state ||
-             session_info_->playback_state == wanted_playback_state_ ||
-             session_info_->audio_video_state == wanted_audio_video_state_) {
-    run_loop_->Quit();
+  } else {
+    if (wanted_state_ == session_info_->state ||
+        session_info_->playback_state == wanted_playback_state_ ||
+        (wanted_audio_video_states_ &&
+         base::ranges::is_permutation(*session_info_->audio_video_states,
+                                      *wanted_audio_video_states_))) {
+      run_loop_->Quit();
+    }
   }
 }
 
@@ -151,12 +156,14 @@
   StartWaiting();
 }
 
-void MockMediaSessionMojoObserver::WaitForAudioVideoState(
-    mojom::MediaAudioVideoState wanted_state) {
-  if (session_info_ && session_info_->audio_video_state == wanted_state)
+void MockMediaSessionMojoObserver::WaitForAudioVideoStates(
+    const std::vector<mojom::MediaAudioVideoState>& wanted_states) {
+  if (session_info_ && base::ranges::is_permutation(
+                           *session_info_->audio_video_states, wanted_states)) {
     return;
+  }
 
-  wanted_audio_video_state_ = wanted_state;
+  wanted_audio_video_states_ = wanted_states;
   StartWaiting();
 }
 
diff --git a/services/media_session/public/cpp/test/mock_media_session.h b/services/media_session/public/cpp/test/mock_media_session.h
index f1401bc..878ca1f 100644
--- a/services/media_session/public/cpp/test/mock_media_session.h
+++ b/services/media_session/public/cpp/test/mock_media_session.h
@@ -50,7 +50,12 @@
 
   void WaitForState(mojom::MediaSessionInfo::SessionState wanted_state);
   void WaitForPlaybackState(mojom::MediaPlaybackState wanted_state);
-  void WaitForAudioVideoState(mojom::MediaAudioVideoState wanted_state);
+
+  // Blocks until the set of audio/video states for the players in the media
+  // session matches |wanted_states|. The order is not important.
+  void WaitForAudioVideoStates(
+      const std::vector<mojom::MediaAudioVideoState>& wanted_states);
+
   void WaitForControllable(bool is_controllable);
 
   void WaitForEmptyMetadata();
@@ -116,7 +121,8 @@
 
   base::Optional<mojom::MediaSessionInfo::SessionState> wanted_state_;
   base::Optional<mojom::MediaPlaybackState> wanted_playback_state_;
-  base::Optional<mojom::MediaAudioVideoState> wanted_audio_video_state_;
+  base::Optional<std::vector<mojom::MediaAudioVideoState>>
+      wanted_audio_video_states_;
   std::unique_ptr<base::RunLoop> run_loop_;
 
   mojo::Receiver<mojom::MediaSessionObserver> receiver_{this};
diff --git a/services/media_session/public/mojom/media_session.mojom b/services/media_session/public/mojom/media_session.mojom
index bec4b5f8..f3a833a 100644
--- a/services/media_session/public/mojom/media_session.mojom
+++ b/services/media_session/public/mojom/media_session.mojom
@@ -9,7 +9,7 @@
 import "ui/gfx/geometry/mojom/geometry.mojom";
 import "url/mojom/url.mojom";
 
-// Next MinVersion: 10
+// Next MinVersion: 11
 
 [Stable, Extensible]
 enum MediaPlaybackState {
@@ -51,9 +51,12 @@
 
 [Stable, Extensible]
 enum MediaAudioVideoState {
-  kUnknown,
+  // Unused as of version 10, see |audio_video_states|.
+  kDeprecatedUnknown,
+
   kAudioOnly,
   kAudioVideo,
+  [MinVersion=10] kVideoOnly,
 };
 
 // Album art in MediaMetadata
@@ -151,12 +154,16 @@
   [MinVersion=7] MediaPictureInPictureState picture_in_picture_state;
 
   // The audio/video state of the Media Session (if known).
-  [MinVersion=8] MediaAudioVideoState audio_video_state;
+  // DEPRECATED, use |audio_video_states| instead.
+  [MinVersion=8] MediaAudioVideoState deprecated_audio_video_state;
 
   // The audio_sink_id tells the client the device_id of the audio output device
   // being used for this media session. A null audio_sink_id implies that the
   // default device is being used.
   [MinVersion=9] string? audio_sink_id;
+
+  // The audio/video states of all the players in the Media Session (if known).
+  [MinVersion=10] array<MediaAudioVideoState>? audio_video_states;
 };
 
 // Contains debugging information about a MediaSession. This will be displayed
diff --git a/services/network/public/cpp/content_security_policy/content_security_policy.cc b/services/network/public/cpp/content_security_policy/content_security_policy.cc
index 3e0d759..84aeebcd 100644
--- a/services/network/public/cpp/content_security_policy/content_security_policy.cc
+++ b/services/network/public/cpp/content_security_policy/content_security_policy.cc
@@ -214,7 +214,7 @@
   // ensure that these are not transmitted between different cross-origin
   // renderers.
   GURL blocked_url = (directive_name == CSPDirectiveName::FrameAncestors)
-                         ? GURL(ToString(context->self_source()))
+                         ? GURL(ToString(*policy->self_origin))
                          : url;
   auto safe_source_location =
       source_location ? source_location->Clone() : mojom::SourceLocation::New();
@@ -842,6 +842,20 @@
   }
 }
 
+mojom::CSPSourcePtr ComputeSelfOrigin(const GURL& url) {
+  if (url.scheme() == url::kFileScheme) {
+    // Forget the host for file schemes. Host can anyway only be `localhost` or
+    // empty and this is platform dependent.
+    //
+    // TODO(antoniosartori): Consider returning mojom::CSPSource::New() for
+    // file: urls, so that 'self' for file: would match nothing.
+    return mojom::CSPSource::New(url::kFileScheme, "", url::PORT_UNSPECIFIED,
+                                 "", false, false);
+  }
+  return mojom::CSPSource::New(url.scheme(), url.host(), url.EffectiveIntPort(),
+                               "", false, false);
+}
+
 void AddContentSecurityPolicyFromHeader(base::StringPiece header,
                                         mojom::ContentSecurityPolicyType type,
                                         const GURL& base_url,
@@ -849,6 +863,7 @@
   DirectivesMap directives = ParseHeaderValue(header);
   out->header = mojom::ContentSecurityPolicyHeader::New(
       header.as_string(), type, mojom::ContentSecurityPolicySource::kHTTP);
+  out->self_origin = ComputeSelfOrigin(base_url);
 
   for (auto directive : directives) {
     if (!base::ranges::all_of(directive.first, IsDirectiveNameCharacter)) {
@@ -1116,6 +1131,8 @@
                                 CSPContext* context,
                                 const mojom::SourceLocationPtr& source_location,
                                 bool is_form_submission) {
+  DCHECK(policy->self_origin);
+
   if (ShouldBypassContentSecurityPolicy(context, directive_name, url))
     return true;
 
@@ -1135,7 +1152,7 @@
       continue;
 
     const auto& source_list = directive->second;
-    bool allowed = CheckCSPSourceList(source_list, url, context,
+    bool allowed = CheckCSPSourceList(*source_list, url, *(policy->self_origin),
                                       has_followed_redirect, is_response_check);
 
     if (!allowed) {
@@ -1189,7 +1206,6 @@
 bool IsValidRequiredCSPAttr(
     const std::vector<mojom::ContentSecurityPolicyPtr>& policy,
     const mojom::ContentSecurityPolicy* context,
-    const url::Origin& origin,
     std::string& error_message) {
   DCHECK(policy.size() == 1);
   if (!policy[0])
@@ -1203,14 +1219,18 @@
     return false;
   }
 
-  if (!policy[0]->report_endpoints.empty()) {
+  if (!policy[0]->report_endpoints.empty() ||
+      // We really don't want any report directives, even with invalid/missing
+      // endpoints.
+      policy[0]->raw_directives.contains(mojom::CSPDirectiveName::ReportURI) ||
+      policy[0]->raw_directives.contains(mojom::CSPDirectiveName::ReportTo)) {
     error_message =
         "The csp attribute cannot contain the directives 'report-to' or "
         "'report-uri'.";
     return false;
   }
 
-  if (context && !Subsumes(*context, policy, origin)) {
+  if (context && !Subsumes(*context, policy)) {
     error_message =
         "The csp attribute Content-Security-Policy is not subsumed by the "
         "frame's parent csp attribute Content-Security-Policy.";
@@ -1221,8 +1241,7 @@
 }
 
 bool Subsumes(const mojom::ContentSecurityPolicy& policy_a,
-              const std::vector<mojom::ContentSecurityPolicyPtr>& policies_b,
-              const url::Origin& origin_b) {
+              const std::vector<mojom::ContentSecurityPolicyPtr>& policies_b) {
   if (policy_a.header->type == mojom::ContentSecurityPolicyType::kReport)
     return true;
 
@@ -1234,6 +1253,9 @@
   if (policies_b.empty())
     return false;
 
+  // All policies in |policies_b| must have the same self_origin.
+  mojom::CSPSource* origin_b = policies_b[0]->self_origin.get();
+
   // A list of directives that we consider for subsumption.
   // See more about source lists here:
   // https://w3c.github.io/webappsec-csp/#framework-directive-source-list
diff --git a/services/network/public/cpp/content_security_policy/content_security_policy.h b/services/network/public/cpp/content_security_policy/content_security_policy.h
index 3f2eaa6..80b967e 100644
--- a/services/network/public/cpp/content_security_policy/content_security_policy.h
+++ b/services/network/public/cpp/content_security_policy/content_security_policy.h
@@ -11,10 +11,6 @@
 
 class GURL;
 
-namespace url {
-class Origin;
-}
-
 namespace net {
 class HttpResponseHeaders;
 }
@@ -83,16 +79,13 @@
 bool IsValidRequiredCSPAttr(
     const std::vector<mojom::ContentSecurityPolicyPtr>& policy,
     const mojom::ContentSecurityPolicy* context,
-    const url::Origin& url,
     std::string& error_message);
 
-// Checks whether |policy_a| subsumes the policy list
-// |policies_b| with origin |origin_b| according to the algorithm
-// https://w3c.github.io/webappsec-cspee/#subsume-policy-list.
+// Checks whether |policy_a| subsumes the policy list |policies_b| according to
+// the algorithm https://w3c.github.io/webappsec-cspee/#subsume-policy-list.
 COMPONENT_EXPORT(NETWORK_CPP)
 bool Subsumes(const mojom::ContentSecurityPolicy& policy_a,
-              const std::vector<mojom::ContentSecurityPolicyPtr>& policies_b,
-              const url::Origin& origin_b);
+              const std::vector<mojom::ContentSecurityPolicyPtr>& policies_b);
 
 COMPONENT_EXPORT(NETWORK_CPP)
 mojom::CSPDirectiveName ToCSPDirectiveName(const std::string& name);
diff --git a/services/network/public/cpp/content_security_policy/content_security_policy_unittest.cc b/services/network/public/cpp/content_security_policy/content_security_policy_unittest.cc
index 5fd66f4..ecb2239 100644
--- a/services/network/public/cpp/content_security_policy/content_security_policy_unittest.cc
+++ b/services/network/public/cpp/content_security_policy/content_security_policy_unittest.cc
@@ -114,6 +114,8 @@
 mojom::ContentSecurityPolicyPtr EmptyCSP() {
   auto policy = mojom::ContentSecurityPolicy::New();
   policy->header = mojom::ContentSecurityPolicyHeader::New();
+  policy->self_origin = network::mojom::CSPSource::New(
+      "", "", url::PORT_UNSPECIFIED, "", false, false);
   return policy;
 }
 
@@ -880,6 +882,40 @@
   }
 }
 
+TEST(ContentSecurityPolicy, ParseStoresSelfOrigin) {
+  struct {
+    const char* url;
+    network::mojom::CSPSourcePtr self_origin;
+  } testCases[]{
+      {
+          "https://example.com",
+          network::mojom::CSPSource::New("https", "example.com", 443, "", false,
+                                         false),
+      },
+      {
+          "http://example.com/main/index.html",
+          network::mojom::CSPSource::New("http", "example.com", 80, "", false,
+                                         false),
+      },
+      {
+          "file://localhost/var/www/index.html",
+          network::mojom::CSPSource::New("file", "", url::PORT_UNSPECIFIED, "",
+                                         false, false),
+      },
+  };
+
+  for (const auto& testCase : testCases) {
+    scoped_refptr<net::HttpResponseHeaders> headers(
+        new net::HttpResponseHeaders("HTTP/1.1 200 OK"));
+    headers->SetHeader("Content-Security-Policy", "default-src 'none'");
+    std::vector<mojom::ContentSecurityPolicyPtr> policies;
+    AddContentSecurityPolicyFromHeaders(*headers, GURL(testCase.url),
+                                        &policies);
+
+    EXPECT_TRUE(testCase.self_origin.Equals(policies[0]->self_origin));
+  }
+}
+
 // Check URL are upgraded iif "upgrade-insecure-requests" directive is defined.
 TEST(ContentSecurityPolicy, ShouldUpgradeInsecureRequest) {
   std::vector<mojom::ContentSecurityPolicyPtr> policies;
@@ -1135,7 +1171,6 @@
     csp->allow_response_redirects = true;
     return csp;
   };
-  context.SetSelf(source_a());
 
   struct TestCase {
     mojom::CSPSourceListPtr navigate_to_list;
@@ -1174,6 +1209,7 @@
 
   for (auto& test : cases) {
     auto policy = EmptyCSP();
+    policy->self_origin = source_a().Clone();
     policy->directives[CSPDirectiveName::NavigateTo] =
         std::move(test.navigate_to_list);
 
@@ -1407,10 +1443,7 @@
     AddContentSecurityPolicyFromHeaders(*required_csp_headers,
                                         GURL("https://example.com/"), &csp);
     std::string out;
-    EXPECT_EQ(
-        test.expected,
-        IsValidRequiredCSPAttr(
-            csp, nullptr, url::Origin::Create(GURL("https://a.com")), out));
+    EXPECT_EQ(test.expected, IsValidRequiredCSPAttr(csp, nullptr, out));
     EXPECT_EQ(test.expected_error, out);
   }
 }
@@ -1460,9 +1493,7 @@
     std::vector<mojom::ContentSecurityPolicyPtr> returned_csp;
     AddContentSecurityPolicyFromHeaders(
         *returned_csp_headers, GURL("https://example.com/"), &returned_csp);
-    EXPECT_EQ(test.expected,
-              Subsumes(*required_csp[0], returned_csp,
-                       url::Origin::Create(GURL("https://a.com"))))
+    EXPECT_EQ(test.expected, Subsumes(*required_csp[0], returned_csp))
         << test.name;
   }
 }
@@ -1526,16 +1557,13 @@
   for (const auto& test : cases) {
     std::vector<mojom::ContentSecurityPolicyPtr> policies_b =
         ParseCSP(test.policies);
-    EXPECT_EQ(Subsumes(*policy_a[0], policies_b,
-                       url::Origin::Create(GURL("https://a.com"))),
-              test.expected)
+    EXPECT_EQ(Subsumes(*policy_a[0], policies_b), test.expected)
         << csp_a << " should " << (test.expected ? "" : "not ") << "subsume "
         << test.policies;
 
     if (!policies_b.empty()) {
       // Check if first policy of `listB` subsumes `A`.
-      EXPECT_EQ(Subsumes(*policies_b[0], policy_a,
-                         url::Origin::Create(GURL("https://a.com"))),
+      EXPECT_EQ(Subsumes(*policies_b[0], policy_a),
                 test.expected_first_policy_opposite)
           << csp_a << " should "
           << (test.expected_first_policy_opposite ? "" : "not ") << "subsume "
@@ -1624,9 +1652,7 @@
         ParseCSP(test.policy_a);
     std::vector<mojom::ContentSecurityPolicyPtr> policies_b =
         ParseCSP(test.policies_b);
-    EXPECT_EQ(Subsumes(*policy_a[0], policies_b,
-                       url::Origin::Create(GURL("https://a.com"))),
-              test.expected)
+    EXPECT_EQ(Subsumes(*policy_a[0], policies_b), test.expected)
         << test.policy_a << " should " << (test.expected ? "" : "not ")
         << "subsume " << test.policies_b;
   }
@@ -1696,9 +1722,7 @@
         ParseCSP(test.policy_a);
     std::vector<mojom::ContentSecurityPolicyPtr> policies_b =
         ParseCSP(test.policies_b);
-    EXPECT_EQ(Subsumes(*policy_a[0], policies_b,
-                       url::Origin::Create(GURL("https://a.com"))),
-              test.expected)
+    EXPECT_EQ(Subsumes(*policy_a[0], policies_b), test.expected)
         << test.policy_a << " should " << (test.expected ? "" : "not ")
         << "subsume " << test.policies_b;
   }
diff --git a/services/network/public/cpp/content_security_policy/csp_context.cc b/services/network/public/cpp/content_security_policy/csp_context.cc
index ee5a5d5..c9d24fa6 100644
--- a/services/network/public/cpp/content_security_policy/csp_context.cc
+++ b/services/network/public/cpp/content_security_policy/csp_context.cc
@@ -5,8 +5,6 @@
 #include "services/network/public/cpp/content_security_policy/csp_context.h"
 #include "services/network/public/cpp/content_security_policy/content_security_policy.h"
 
-#include "url/origin.h"
-
 namespace network {
 
 namespace {
@@ -53,32 +51,6 @@
   return allow;
 }
 
-void CSPContext::SetSelf(const url::Origin& origin) {
-  self_source_.reset();
-
-  // When the origin is unique, no URL should match with 'self'. That's why
-  // |self_source_| stays undefined here.
-  if (origin.opaque())
-    return;
-
-  if (origin.scheme() == url::kFileScheme) {
-    self_source_ = mojom::CSPSource::New(
-        url::kFileScheme, "", url::PORT_UNSPECIFIED, "", false, false);
-    return;
-  }
-
-  self_source_ = mojom::CSPSource::New(
-      origin.scheme(), origin.host(),
-      origin.port() == 0 ? url::PORT_UNSPECIFIED : origin.port(), "", false,
-      false);
-
-  DCHECK_NE("", self_source_->scheme);
-}
-
-void CSPContext::SetSelf(mojom::CSPSourcePtr self_source) {
-  self_source_ = std::move(self_source);
-}
-
 bool CSPContext::SchemeShouldBypassCSP(const base::StringPiece& scheme) {
   return false;
 }
diff --git a/services/network/public/cpp/content_security_policy/csp_context.h b/services/network/public/cpp/content_security_policy/csp_context.h
index 968b39d..485dddc 100644
--- a/services/network/public/cpp/content_security_policy/csp_context.h
+++ b/services/network/public/cpp/content_security_policy/csp_context.h
@@ -9,10 +9,6 @@
 
 class GURL;
 
-namespace url {
-class Origin;
-}
-
 namespace network {
 
 // A CSPContext represents the Document where the Content-Security-Policy are
@@ -87,20 +83,8 @@
     return policies_;
   }
 
-  void SetSelf(const url::Origin& origin);
-  void SetSelf(mojom::CSPSourcePtr self_source);
-
-  // When a CSPSourceList contains 'self', the url is allowed when it match the
-  // CSPSource returned by this function.
-  // Sometimes there is no 'self' source. It means that the current origin is
-  // unique and no urls will match 'self' whatever they are.
-  // Note: When there is a 'self' source, its scheme is guaranteed to be
-  // non-empty.
-  const mojom::CSPSourcePtr& self_source() { return self_source_; }
-
  private:
   // TODO(arthursonzogni): This is an interface. Stop storing object in it.
-  mojom::CSPSourcePtr self_source_;  // Nullable.
   std::vector<mojom::ContentSecurityPolicyPtr> policies_;
 };
 
diff --git a/services/network/public/cpp/content_security_policy/csp_context_unittest.cc b/services/network/public/cpp/content_security_policy/csp_context_unittest.cc
index 39168c0b..151bec3 100644
--- a/services/network/public/cpp/content_security_policy/csp_context_unittest.cc
+++ b/services/network/public/cpp/content_security_policy/csp_context_unittest.cc
@@ -66,19 +66,22 @@
 }
 
 // Build a new policy made of only one directive and no report endpoints.
-mojom::ContentSecurityPolicyPtr BuildPolicy(CSPDirectiveName directive_name,
+mojom::ContentSecurityPolicyPtr BuildPolicy(mojom::CSPSourcePtr self_source,
+                                            CSPDirectiveName directive_name,
                                             mojom::CSPSourcePtr source) {
   auto source_list = mojom::CSPSourceList::New();
   source_list->sources.push_back(std::move(source));
 
   auto policy = EmptyCSP();
   policy->directives[directive_name] = std::move(source_list);
+  policy->self_origin = std::move(self_source);
 
   return policy;
 }
 
 // Build a new policy made of only one directive and no report endpoints.
-mojom::ContentSecurityPolicyPtr BuildPolicy(CSPDirectiveName directive_name,
+mojom::ContentSecurityPolicyPtr BuildPolicy(mojom::CSPSourcePtr self_source,
+                                            CSPDirectiveName directive_name,
                                             mojom::CSPSourcePtr source_1,
                                             mojom::CSPSourcePtr source_2) {
   auto source_list = mojom::CSPSourceList::New();
@@ -87,6 +90,7 @@
 
   auto policy = EmptyCSP();
   policy->directives[directive_name] = std::move(source_list);
+  policy->self_origin = std::move(self_source);
 
   return policy;
 }
@@ -104,8 +108,11 @@
 
 TEST(CSPContextTest, SchemeShouldBypassCSP) {
   CSPContextTest context;
-  context.AddContentSecurityPolicy(BuildPolicy(
-      CSPDirectiveName::DefaultSrc, BuildCSPSource("", "example.com")));
+  auto self_source = network::mojom::CSPSource::New("http", "example.com", 80,
+                                                    "", false, false);
+  context.AddContentSecurityPolicy(
+      BuildPolicy(self_source.Clone(), CSPDirectiveName::DefaultSrc,
+                  BuildCSPSource("", "example.com")));
 
   EXPECT_FALSE(context.IsAllowedByCsp(
       CSPDirectiveName::FrameSrc, GURL("data:text/html,<html></html>"), false,
@@ -120,14 +127,15 @@
 
 TEST(CSPContextTest, MultiplePolicies) {
   CSPContextTest context;
-  context.SetSelf(url::Origin::Create(GURL("http://example.com")));
+  auto self_source = network::mojom::CSPSource::New("http", "example.com", 80,
+                                                    "", false, false);
 
-  context.AddContentSecurityPolicy(BuildPolicy(CSPDirectiveName::FrameSrc,
-                                               BuildCSPSource("", "a.com"),
-                                               BuildCSPSource("", "b.com")));
-  context.AddContentSecurityPolicy(BuildPolicy(CSPDirectiveName::FrameSrc,
-                                               BuildCSPSource("", "a.com"),
-                                               BuildCSPSource("", "c.com")));
+  context.AddContentSecurityPolicy(
+      BuildPolicy(self_source.Clone(), CSPDirectiveName::FrameSrc,
+                  BuildCSPSource("", "a.com"), BuildCSPSource("", "b.com")));
+  context.AddContentSecurityPolicy(
+      BuildPolicy(self_source.Clone(), CSPDirectiveName::FrameSrc,
+                  BuildCSPSource("", "a.com"), BuildCSPSource("", "c.com")));
 
   EXPECT_TRUE(context.IsAllowedByCsp(
       CSPDirectiveName::FrameSrc, GURL("http://a.com"), false, false,
@@ -145,11 +153,12 @@
 
 TEST(CSPContextTest, SanitizeDataForUseInCspViolation) {
   CSPContextTest context;
-  context.SetSelf(url::Origin::Create(GURL("http://a.com")));
+  auto self_source =
+      network::mojom::CSPSource::New("http", "a.com", 80, "", false, false);
 
   // Content-Security-Policy: frame-src "a.com/iframe"
   context.AddContentSecurityPolicy(
-      BuildPolicy(CSPDirectiveName::FrameSrc,
+      BuildPolicy(self_source.Clone(), CSPDirectiveName::FrameSrc,
                   mojom::CSPSource::New("", "a.com", url::PORT_UNSPECIFIED,
                                         "/iframe", false, false)));
 
@@ -196,14 +205,18 @@
 // When several policies are infringed, all of them must be reported.
 TEST(CSPContextTest, MultipleInfringement) {
   CSPContextTest context;
-  context.SetSelf(url::Origin::Create(GURL("http://example.com")));
+  auto self_source = network::mojom::CSPSource::New("http", "example.com", 80,
+                                                    "", false, false);
 
-  context.AddContentSecurityPolicy(
-      BuildPolicy(CSPDirectiveName::FrameSrc, BuildCSPSource("", "a.com")));
-  context.AddContentSecurityPolicy(
-      BuildPolicy(CSPDirectiveName::FrameSrc, BuildCSPSource("", "b.com")));
-  context.AddContentSecurityPolicy(
-      BuildPolicy(CSPDirectiveName::FrameSrc, BuildCSPSource("", "c.com")));
+  context.AddContentSecurityPolicy(BuildPolicy(self_source.Clone(),
+                                               CSPDirectiveName::FrameSrc,
+                                               BuildCSPSource("", "a.com")));
+  context.AddContentSecurityPolicy(BuildPolicy(self_source.Clone(),
+                                               CSPDirectiveName::FrameSrc,
+                                               BuildCSPSource("", "b.com")));
+  context.AddContentSecurityPolicy(BuildPolicy(self_source.Clone(),
+                                               CSPDirectiveName::FrameSrc,
+                                               BuildCSPSource("", "c.com")));
 
   EXPECT_FALSE(context.IsAllowedByCsp(
       CSPDirectiveName::FrameSrc, GURL("http://c.com"), false, false,
@@ -222,13 +235,17 @@
 // Tests that the CheckCSPDisposition parameter is obeyed.
 TEST(CSPContextTest, CheckCSPDisposition) {
   CSPContextTest context;
+  auto self_source = network::mojom::CSPSource::New("http", "example.com", 80,
+                                                    "", false, false);
 
   // Add an enforced policy.
-  auto enforce_csp = BuildPolicy(CSPDirectiveName::FrameSrc,
-                                 BuildCSPSource("", "example.com"));
+  auto enforce_csp =
+      BuildPolicy(self_source.Clone(), CSPDirectiveName::FrameSrc,
+                  BuildCSPSource("", "example.com"));
   // Add a report-only policy.
-  auto report_only_csp = BuildPolicy(CSPDirectiveName::DefaultSrc,
-                                     BuildCSPSource("", "example.com"));
+  auto report_only_csp =
+      BuildPolicy(self_source.Clone(), CSPDirectiveName::DefaultSrc,
+                  BuildCSPSource("", "example.com"));
   report_only_csp->header->type = mojom::ContentSecurityPolicyType::kReport;
 
   context.AddContentSecurityPolicy(std::move(enforce_csp));
diff --git a/services/network/public/cpp/content_security_policy/csp_source.cc b/services/network/public/cpp/content_security_policy/csp_source.cc
index 70a11e6..3fe19c7 100644
--- a/services/network/public/cpp/content_security_policy/csp_source.cc
+++ b/services/network/public/cpp/content_security_policy/csp_source.cc
@@ -9,7 +9,6 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "services/network/public/cpp/content_security_policy/content_security_policy.h"
-#include "services/network/public/cpp/content_security_policy/csp_context.h"
 #include "services/network/public/mojom/content_security_policy.mojom.h"
 #include "url/url_canon.h"
 #include "url/url_util.h"
@@ -18,8 +17,8 @@
 
 namespace {
 
-bool HasHost(const mojom::CSPSourcePtr& source) {
-  return !source->host.empty() || source->is_host_wildcard;
+bool HasHost(const mojom::CSPSource& source) {
+  return !source.host.empty() || source.is_host_wildcard;
 }
 
 bool DecodePath(const base::StringPiece& path, std::string* output) {
@@ -55,66 +54,65 @@
   return SchemeMatchingResult::NotMatching;
 }
 
-SchemeMatchingResult SourceAllowScheme(const mojom::CSPSourcePtr& source,
+SchemeMatchingResult SourceAllowScheme(const mojom::CSPSource& source,
                                        const GURL& url,
-                                       CSPContext* context) {
+                                       const mojom::CSPSource& self_source) {
   // The source doesn't specify a scheme and the current origin is unique. In
   // this case, the url doesn't match regardless of its scheme.
-  if (source->scheme.empty() && !context->self_source())
+  if (source.scheme.empty() && self_source.scheme.empty())
     return SchemeMatchingResult::NotMatching;
 
   // |allowed_scheme| is guaranteed to be non-empty.
   const std::string& allowed_scheme =
-      source->scheme.empty() ? context->self_source()->scheme : source->scheme;
+      source.scheme.empty() ? self_source.scheme : source.scheme;
 
   return MatchScheme(allowed_scheme, url.scheme());
 }
 
-bool SourceAllowHost(const mojom::CSPSourcePtr& source,
-                     const std::string& host) {
-  if (source->is_host_wildcard) {
-    if (source->host.empty())
+bool SourceAllowHost(const mojom::CSPSource& source, const std::string& host) {
+  if (source.is_host_wildcard) {
+    if (source.host.empty())
       return true;
     // TODO(arthursonzogni): Chrome used to, incorrectly, match *.x.y to x.y.
     // The renderer version of this function counts how many times it happens.
     // It might be useful to do it outside of blink too.
     // See third_party/blink/renderer/core/frame/csp/csp_source.cc
-    return base::EndsWith(host, '.' + source->host,
+    return base::EndsWith(host, '.' + source.host,
                           base::CompareCase::INSENSITIVE_ASCII);
   } else {
-    return base::EqualsCaseInsensitiveASCII(host, source->host);
+    return base::EqualsCaseInsensitiveASCII(host, source.host);
   }
 }
 
-bool SourceAllowHost(const mojom::CSPSourcePtr& source, const GURL& url) {
+bool SourceAllowHost(const mojom::CSPSource& source, const GURL& url) {
   return SourceAllowHost(source, url.host());
 }
 
-PortMatchingResult SourceAllowPort(const mojom::CSPSourcePtr& source,
+PortMatchingResult SourceAllowPort(const mojom::CSPSource& source,
                                    int port,
                                    const std::string& scheme) {
-  if (source->is_port_wildcard)
+  if (source.is_port_wildcard)
     return PortMatchingResult::MatchingWildcard;
 
-  if (source->port == port) {
-    if (source->port == url::PORT_UNSPECIFIED)
+  if (source.port == port) {
+    if (source.port == url::PORT_UNSPECIFIED)
       return PortMatchingResult::MatchingWildcard;
     return PortMatchingResult::MatchingExact;
   }
 
-  if (source->port == url::PORT_UNSPECIFIED) {
+  if (source.port == url::PORT_UNSPECIFIED) {
     if (DefaultPortForScheme(scheme) == port)
       return PortMatchingResult::MatchingWildcard;
   }
 
   if (port == url::PORT_UNSPECIFIED) {
-    if (source->port == DefaultPortForScheme(scheme))
+    if (source.port == DefaultPortForScheme(scheme))
       return PortMatchingResult::MatchingWildcard;
   }
 
-  int source_port = source->port;
+  int source_port = source.port;
   if (source_port == url::PORT_UNSPECIFIED)
-    source_port = DefaultPortForScheme(source->scheme);
+    source_port = DefaultPortForScheme(source.scheme);
 
   if (port == url::PORT_UNSPECIFIED)
     port = DefaultPortForScheme(scheme);
@@ -125,13 +123,12 @@
   return PortMatchingResult::NotMatching;
 }
 
-PortMatchingResult SourceAllowPort(const mojom::CSPSourcePtr& source,
+PortMatchingResult SourceAllowPort(const mojom::CSPSource& source,
                                    const GURL& url) {
   return SourceAllowPort(source, url.EffectiveIntPort(), url.scheme());
 }
 
-bool SourceAllowPath(const mojom::CSPSourcePtr& source,
-                     const std::string& path) {
+bool SourceAllowPath(const mojom::CSPSource& source, const std::string& path) {
   std::string path_decoded;
   if (!DecodePath(path, &path_decoded)) {
     // TODO(arthursonzogni): try to figure out if that could happen and how to
@@ -139,20 +136,20 @@
     return false;
   }
 
-  if (source->path.empty() || (source->path == "/" && path_decoded.empty()))
+  if (source.path.empty() || (source.path == "/" && path_decoded.empty()))
     return true;
 
   // If the path represents a directory.
-  if (base::EndsWith(source->path, "/", base::CompareCase::SENSITIVE)) {
-    return base::StartsWith(path_decoded, source->path,
+  if (base::EndsWith(source.path, "/", base::CompareCase::SENSITIVE)) {
+    return base::StartsWith(path_decoded, source.path,
                             base::CompareCase::SENSITIVE);
   }
 
   // The path represents a file.
-  return source->path == path_decoded;
+  return source.path == path_decoded;
 }
 
-bool SourceAllowPath(const mojom::CSPSourcePtr& source,
+bool SourceAllowPath(const mojom::CSPSource& source,
                      const GURL& url,
                      bool has_followed_redirect) {
   if (has_followed_redirect)
@@ -180,20 +177,21 @@
 
 }  // namespace
 
-bool CSPSourceIsSchemeOnly(const mojom::CSPSourcePtr& source) {
+bool CSPSourceIsSchemeOnly(const mojom::CSPSource& source) {
   return !HasHost(source);
 }
 
-bool CheckCSPSource(const mojom::CSPSourcePtr& source,
+bool CheckCSPSource(const mojom::CSPSource& source,
                     const GURL& url,
-                    CSPContext* context,
+                    const mojom::CSPSource& self_source,
                     bool has_followed_redirect) {
   if (CSPSourceIsSchemeOnly(source)) {
-    return SourceAllowScheme(source, url, context) !=
+    return SourceAllowScheme(source, url, self_source) !=
            SchemeMatchingResult::NotMatching;
   }
   PortMatchingResult portResult = SourceAllowPort(source, url);
-  SchemeMatchingResult schemeResult = SourceAllowScheme(source, url, context);
+  SchemeMatchingResult schemeResult =
+      SourceAllowScheme(source, url, self_source);
   if (requiresUpgrade(schemeResult) && !canUpgrade(portResult))
     return false;
   if (requiresUpgrade(portResult) && !canUpgrade(schemeResult))
@@ -204,71 +202,71 @@
          SourceAllowPath(source, url, has_followed_redirect);
 }
 
-mojom::CSPSourcePtr CSPSourcesIntersect(const mojom::CSPSourcePtr& source_a,
-                                        const mojom::CSPSourcePtr& source_b) {
+mojom::CSPSourcePtr CSPSourcesIntersect(const mojom::CSPSource& source_a,
+                                        const mojom::CSPSource& source_b) {
   // If the original source expressions didn't have a scheme, we should have
   // filled that already with origin's scheme.
-  DCHECK(!source_a->scheme.empty());
-  DCHECK(!source_b->scheme.empty());
+  DCHECK(!source_a.scheme.empty());
+  DCHECK(!source_b.scheme.empty());
 
   auto result = mojom::CSPSource::New();
-  if (MatchScheme(source_a->scheme, source_b->scheme) !=
+  if (MatchScheme(source_a.scheme, source_b.scheme) !=
       SchemeMatchingResult::NotMatching) {
-    result->scheme = source_b->scheme;
-  } else if (MatchScheme(source_b->scheme, source_a->scheme) !=
+    result->scheme = source_b.scheme;
+  } else if (MatchScheme(source_b.scheme, source_a.scheme) !=
              SchemeMatchingResult::NotMatching) {
-    result->scheme = source_a->scheme;
+    result->scheme = source_a.scheme;
   } else {
     return nullptr;
   }
 
   if (CSPSourceIsSchemeOnly(source_a)) {
-    auto new_result = source_b->Clone();
+    auto new_result = source_b.Clone();
     new_result->scheme = result->scheme;
     return new_result;
   } else if (CSPSourceIsSchemeOnly(source_b)) {
-    auto new_result = source_a->Clone();
+    auto new_result = source_a.Clone();
     new_result->scheme = result->scheme;
     return new_result;
   }
 
   const std::string host_a =
-      (source_a->is_host_wildcard ? "*." : "") + source_a->host;
+      (source_a.is_host_wildcard ? "*." : "") + source_a.host;
   const std::string host_b =
-      (source_b->is_host_wildcard ? "*." : "") + source_b->host;
+      (source_b.is_host_wildcard ? "*." : "") + source_b.host;
   if (SourceAllowHost(source_a, host_b)) {
-    result->host = source_b->host;
-    result->is_host_wildcard = source_b->is_host_wildcard;
+    result->host = source_b.host;
+    result->is_host_wildcard = source_b.is_host_wildcard;
   } else if (SourceAllowHost(source_b, host_a)) {
-    result->host = source_a->host;
-    result->is_host_wildcard = source_a->is_host_wildcard;
+    result->host = source_a.host;
+    result->is_host_wildcard = source_a.is_host_wildcard;
   } else {
     return nullptr;
   }
 
-  if (source_b->is_port_wildcard) {
-    result->port = source_a->port;
-    result->is_port_wildcard = source_a->is_port_wildcard;
-  } else if (source_a->is_port_wildcard) {
-    result->port = source_b->port;
-  } else if (SourceAllowPort(source_a, source_b->port, source_b->scheme) !=
+  if (source_b.is_port_wildcard) {
+    result->port = source_a.port;
+    result->is_port_wildcard = source_a.is_port_wildcard;
+  } else if (source_a.is_port_wildcard) {
+    result->port = source_b.port;
+  } else if (SourceAllowPort(source_a, source_b.port, source_b.scheme) !=
                  PortMatchingResult::NotMatching &&
              // If port_a is explicitly specified but port_b is omitted, then we
              // should take port_a instead of port_b, since port_a is stricter.
-             !(source_a->port != url::PORT_UNSPECIFIED &&
-               source_b->port == url::PORT_UNSPECIFIED)) {
-    result->port = source_b->port;
-  } else if (SourceAllowPort(source_b, source_a->port, source_a->scheme) !=
+             !(source_a.port != url::PORT_UNSPECIFIED &&
+               source_b.port == url::PORT_UNSPECIFIED)) {
+    result->port = source_b.port;
+  } else if (SourceAllowPort(source_b, source_a.port, source_a.scheme) !=
              PortMatchingResult::NotMatching) {
-    result->port = source_a->port;
+    result->port = source_a.port;
   } else {
     return nullptr;
   }
 
-  if (SourceAllowPath(source_a, source_b->path))
-    result->path = source_b->path;
-  else if (SourceAllowPath(source_b, source_a->path))
-    result->path = source_a->path;
+  if (SourceAllowPath(source_a, source_b.path))
+    result->path = source_b.path;
+  else if (SourceAllowPath(source_b, source_a.path))
+    result->path = source_a.path;
   else
     return nullptr;
 
@@ -276,14 +274,14 @@
 }
 
 // Check whether |source_a| subsumes |source_b|.
-bool CSPSourceSubsumes(const mojom::CSPSourcePtr& source_a,
-                       const mojom::CSPSourcePtr& source_b) {
+bool CSPSourceSubsumes(const mojom::CSPSource& source_a,
+                       const mojom::CSPSource& source_b) {
   // If the original source expressions didn't have a scheme, we should have
   // filled that already with origin's scheme.
-  DCHECK(!source_a->scheme.empty());
-  DCHECK(!source_b->scheme.empty());
+  DCHECK(!source_a.scheme.empty());
+  DCHECK(!source_b.scheme.empty());
 
-  if (MatchScheme(source_a->scheme, source_b->scheme) ==
+  if (MatchScheme(source_a.scheme, source_b.scheme) ==
       SchemeMatchingResult::NotMatching) {
     return false;
   }
@@ -293,51 +291,51 @@
   if (CSPSourceIsSchemeOnly(source_b))
     return false;
 
-  if (!SourceAllowHost(source_a, (source_b->is_host_wildcard ? "*." : "") +
-                                     source_b->host)) {
+  if (!SourceAllowHost(
+          source_a, (source_b.is_host_wildcard ? "*." : "") + source_b.host)) {
     return false;
   }
 
-  if (source_b->is_port_wildcard && !source_a->is_port_wildcard)
+  if (source_b.is_port_wildcard && !source_a.is_port_wildcard)
     return false;
   PortMatchingResult port_matching =
-      SourceAllowPort(source_a, source_b->port, source_b->scheme);
+      SourceAllowPort(source_a, source_b.port, source_b.scheme);
   if (port_matching == PortMatchingResult::NotMatching)
     return false;
 
-  if (!SourceAllowPath(source_a, source_b->path))
+  if (!SourceAllowPath(source_a, source_b.path))
     return false;
 
   return true;
 }
 
-std::string ToString(const mojom::CSPSourcePtr& source) {
+std::string ToString(const mojom::CSPSource& source) {
   // scheme
   if (CSPSourceIsSchemeOnly(source))
-    return source->scheme + ":";
+    return source.scheme + ":";
 
   std::stringstream text;
-  if (!source->scheme.empty())
-    text << source->scheme << "://";
+  if (!source.scheme.empty())
+    text << source.scheme << "://";
 
   // host
-  if (source->is_host_wildcard) {
-    if (source->host.empty())
+  if (source.is_host_wildcard) {
+    if (source.host.empty())
       text << "*";
     else
-      text << "*." << source->host;
+      text << "*." << source.host;
   } else {
-    text << source->host;
+    text << source.host;
   }
 
   // port
-  if (source->is_port_wildcard)
+  if (source.is_port_wildcard)
     text << ":*";
-  if (source->port != url::PORT_UNSPECIFIED)
-    text << ":" << source->port;
+  if (source.port != url::PORT_UNSPECIFIED)
+    text << ":" << source.port;
 
   // path
-  text << source->path;
+  text << source.path;
 
   return text.str();
 }
diff --git a/services/network/public/cpp/content_security_policy/csp_source.h b/services/network/public/cpp/content_security_policy/csp_source.h
index 8e65b49..49f9948 100644
--- a/services/network/public/cpp/content_security_policy/csp_source.h
+++ b/services/network/public/cpp/content_security_policy/csp_source.h
@@ -13,34 +13,32 @@
 
 namespace network {
 
-class CSPContext;
-
 // Check if a CSP |source| matches the scheme-source grammar.
-bool CSPSourceIsSchemeOnly(const mojom::CSPSourcePtr& source);
+bool CSPSourceIsSchemeOnly(const mojom::CSPSource& source);
 
 // Check if a |url| matches with a CSP |source| matches.
 COMPONENT_EXPORT(NETWORK_CPP)
-bool CheckCSPSource(const mojom::CSPSourcePtr& source,
+bool CheckCSPSource(const mojom::CSPSource& source,
                     const GURL& url,
-                    CSPContext* context,
+                    const mojom::CSPSource& self_source,
                     bool has_followed_redirect = false);
 
 // Compute the source intersection of |source_a| and |source_b|.
 // https://w3c.github.io/webappsec-cspee/#intersection-source-expressions
 COMPONENT_EXPORT(NETWORK_CPP)
-mojom::CSPSourcePtr CSPSourcesIntersect(const mojom::CSPSourcePtr& source_a,
-                                        const mojom::CSPSourcePtr& source_b);
+mojom::CSPSourcePtr CSPSourcesIntersect(const mojom::CSPSource& source_a,
+                                        const mojom::CSPSource& source_b);
 
 // Check if |source_a| subsumes |source_b| according to
 // https://w3c.github.io/webappsec-cspee/#subsume-source-expressions
 COMPONENT_EXPORT(NETWORK_CPP)
-bool CSPSourceSubsumes(const mojom::CSPSourcePtr& source_a,
-                       const mojom::CSPSourcePtr& source_b);
+bool CSPSourceSubsumes(const mojom::CSPSource& source_a,
+                       const mojom::CSPSource& source_b);
 
 // Serialize the CSPSource |source| as a string. This is used for reporting
 // violations.
 COMPONENT_EXPORT(NETWORK_CPP)
-std::string ToString(const mojom::CSPSourcePtr& source);
+std::string ToString(const mojom::CSPSource& source);
 
 }  // namespace network
 
diff --git a/services/network/public/cpp/content_security_policy/csp_source_list.cc b/services/network/public/cpp/content_security_policy/csp_source_list.cc
index 60443a74..d20cd47 100644
--- a/services/network/public/cpp/content_security_policy/csp_source_list.cc
+++ b/services/network/public/cpp/content_security_policy/csp_source_list.cc
@@ -7,7 +7,6 @@
 #include "base/containers/flat_set.h"
 #include "base/ranges/algorithm.h"
 #include "services/network/public/cpp/content_security_policy/content_security_policy.h"
-#include "services/network/public/cpp/content_security_policy/csp_context.h"
 #include "services/network/public/cpp/content_security_policy/csp_source.h"
 
 namespace network {
@@ -18,10 +17,10 @@
 
 bool AllowFromSources(const GURL& url,
                       const std::vector<mojom::CSPSourcePtr>& sources,
-                      CSPContext* context,
+                      const mojom::CSPSource& self_source,
                       bool has_followed_redirect) {
   for (const auto& source : sources) {
-    if (CheckCSPSource(source, url, context, has_followed_redirect))
+    if (CheckCSPSource(*source, url, self_source, has_followed_redirect))
       return true;
   }
   return false;
@@ -73,14 +72,14 @@
     const std::vector<mojom::CSPSourcePtr>& list_b) {
   base::flat_set<std::string> schemes_a;
   for (const auto& source_a : list_a) {
-    if (CSPSourceIsSchemeOnly(source_a)) {
+    if (CSPSourceIsSchemeOnly(*source_a)) {
       AddSourceSchemesToSet(schemes_a, source_a.get());
     }
   }
 
   base::flat_set<std::string> intersection;
   for (const auto& source_b : list_b) {
-    if (CSPSourceIsSchemeOnly(source_b)) {
+    if (CSPSourceIsSchemeOnly(*source_b)) {
       if (schemes_a.contains(source_b->scheme))
         AddSourceSchemesToSet(intersection, source_b.get());
       else if (source_b->scheme == url::kHttpScheme &&
@@ -98,14 +97,13 @@
 
 std::vector<mojom::CSPSourcePtr> ExpandSchemeStarAndSelf(
     const mojom::CSPSourceList& source_list,
-    const mojom::CSPSource& self) {
+    const mojom::CSPSource* self) {
   std::vector<mojom::CSPSourcePtr> result;
   for (const mojom::CSPSourcePtr& item : source_list.sources) {
     mojom::CSPSourcePtr new_item = item->Clone();
     if (new_item->scheme.empty()) {
-      if (self.scheme.empty())
-        continue;
-      new_item->scheme = self.scheme;
+      if (self && !self->scheme.empty())
+        new_item->scheme = self->scheme;
     }
     result.push_back(std::move(new_item));
   }
@@ -117,15 +115,16 @@
         url::kWsScheme, "", url::PORT_UNSPECIFIED, "", false, false));
     result.push_back(mojom::CSPSource::New(
         url::kHttpScheme, "", url::PORT_UNSPECIFIED, "", false, false));
-    if (!self.scheme.empty()) {
+    if (self && !self->scheme.empty()) {
       result.push_back(mojom::CSPSource::New(
-          self.scheme, "", url::PORT_UNSPECIFIED, "", false, false));
+          self->scheme, "", url::PORT_UNSPECIFIED, "", false, false));
     }
   }
 
-  if (source_list.allow_self && !self.scheme.empty() && !self.host.empty()) {
+  if (source_list.allow_self && self && !self->scheme.empty() &&
+      !self->host.empty()) {
     // If |self| is an opaque origin we should ignore it.
-    result.push_back(self.Clone());
+    result.push_back(self->Clone());
   }
   return result;
 }
@@ -133,7 +132,7 @@
 std::vector<mojom::CSPSourcePtr> IntersectSources(
     const mojom::CSPSourceList& source_list_a,
     const std::vector<mojom::CSPSourcePtr>& source_list_b,
-    const mojom::CSPSource& self) {
+    const mojom::CSPSource* self) {
   auto schemes = IntersectSchemesOnly(source_list_a.sources, source_list_b);
 
   std::vector<mojom::CSPSourcePtr> normalized;
@@ -160,7 +159,7 @@
       if (schemes.contains(source_b->scheme))
         continue;
       if (mojom::CSPSourcePtr local_match =
-              CSPSourcesIntersect(source_a, source_b)) {
+              CSPSourcesIntersect(*source_a, *source_b)) {
         normalized.emplace_back(std::move(local_match));
       }
     }
@@ -179,21 +178,21 @@
   // |source_list_a|.
   return base::ranges::all_of(source_list_b, [&](const auto& source_b) {
     return base::ranges::any_of(source_list_a, [&](const auto& source_a) {
-      return CSPSourceSubsumes(source_a, source_b);
+      return CSPSourceSubsumes(*source_a, *source_b);
     });
   });
 }
 
 }  // namespace
 
-bool CheckCSPSourceList(const mojom::CSPSourceListPtr& source_list,
+bool CheckCSPSourceList(const mojom::CSPSourceList& source_list,
                         const GURL& url,
-                        CSPContext* context,
+                        const mojom::CSPSource& self_source,
                         bool has_followed_redirect,
                         bool is_response_check) {
   // If the source list allows all redirects, the decision can't be made until
   // the response is received.
-  if (source_list->allow_response_redirects && !is_response_check)
+  if (source_list.allow_response_redirects && !is_response_check)
     return true;
 
   // Wildcards match network schemes ('http', 'https', 'ftp', 'ws', 'wss'), and
@@ -201,22 +200,21 @@
   // https://w3c.github.io/webappsec-csp/#match-url-to-source-expression. Other
   // schemes, including custom schemes, must be explicitly listed in a source
   // list.
-  if (source_list->allow_star) {
+  if (source_list.allow_star) {
     if (url.SchemeIsHTTPOrHTTPS() || url.SchemeIsWSOrWSS() ||
         url.SchemeIs("ftp")) {
       return true;
     }
-    if (context->self_source() && url.SchemeIs(context->self_source()->scheme))
+    if (!self_source.scheme.empty() && url.SchemeIs(self_source.scheme))
       return true;
   }
 
-  if (source_list->allow_self && context->self_source() &&
-      CheckCSPSource(context->self_source(), url, context,
-                     has_followed_redirect)) {
+  if (source_list.allow_self &&
+      CheckCSPSource(self_source, url, self_source, has_followed_redirect)) {
     return true;
   }
 
-  return AllowFromSources(url, source_list->sources, context,
+  return AllowFromSources(url, source_list.sources, self_source,
                           has_followed_redirect);
 }
 
@@ -224,7 +222,7 @@
     const mojom::CSPSourceList& source_list_a,
     const std::vector<const mojom::CSPSourceList*>& source_list_b,
     CSPDirectiveName directive,
-    const url::Origin& origin_b) {
+    const mojom::CSPSource* origin_b) {
   if (source_list_b.empty())
     return false;
 
@@ -239,10 +237,8 @@
   base::flat_set<std::string> nonces_b((*it)->nonces);
   base::flat_set<mojom::CSPHashSourcePtr> hashes_b(mojo::Clone((*it)->hashes));
 
-  auto origin_b_as_csp_source = mojom::CSPSource::New(
-      origin_b.scheme(), origin_b.host(), origin_b.port(), "", false, false);
   std::vector<mojom::CSPSourcePtr> normalized_sources_b =
-      ExpandSchemeStarAndSelf(**it, *origin_b_as_csp_source);
+      ExpandSchemeStarAndSelf(**it, origin_b);
 
   ++it;
   for (; it != source_list_b.end(); ++it) {
@@ -262,7 +258,7 @@
         mojo::Clone((*it)->hashes));
     IntersectHashes(hashes_b, item_hashes);
     normalized_sources_b =
-        IntersectSources(**it, normalized_sources_b, *origin_b_as_csp_source);
+        IntersectSources(**it, normalized_sources_b, origin_b);
   }
 
   // If source_list_b enforces some nonce, then source_list_a must contain
@@ -310,7 +306,7 @@
 
   // If embedding CSP specifies `self`, `self` refers to the embedee's origin.
   std::vector<mojom::CSPSourcePtr> normalized_sources_a =
-      ExpandSchemeStarAndSelf(source_list_a, *origin_b_as_csp_source);
+      ExpandSchemeStarAndSelf(source_list_a, origin_b);
   return UrlSourceListSubsumes(normalized_sources_a, normalized_sources_b);
 }
 
@@ -332,7 +328,7 @@
   for (const auto& source : source_list->sources) {
     if (!is_empty)
       text << " ";
-    text << ToString(source);
+    text << ToString(*source);
     is_empty = false;
   }
 
diff --git a/services/network/public/cpp/content_security_policy/csp_source_list.h b/services/network/public/cpp/content_security_policy/csp_source_list.h
index d2bc974..141b233d 100644
--- a/services/network/public/cpp/content_security_policy/csp_source_list.h
+++ b/services/network/public/cpp/content_security_policy/csp_source_list.h
@@ -13,22 +13,17 @@
 
 class GURL;
 
-namespace url {
-class Origin;
-}
-
 namespace network {
-class CSPContext;
 
 COMPONENT_EXPORT(NETWORK_CPP)
 std::string ToString(const mojom::CSPSourceListPtr& source_list);
 
 // Return true when at least one source in the |source_list| matches the
-// |url| for a given |context|.
+// |url|.
 COMPONENT_EXPORT(NETWORK_CPP)
-bool CheckCSPSourceList(const mojom::CSPSourceListPtr& source_list,
+bool CheckCSPSourceList(const mojom::CSPSourceList& source_list,
                         const GURL& url,
-                        CSPContext* context,
+                        const mojom::CSPSource& self_source,
                         bool has_followed_redirect = false,
                         bool is_response_check = false);
 
@@ -40,7 +35,7 @@
     const mojom::CSPSourceList& source_list_a,
     const std::vector<const mojom::CSPSourceList*>& source_list_b,
     mojom::CSPDirectiveName directive,
-    const url::Origin& origin_b);
+    const mojom::CSPSource* origin_b);
 
 }  // namespace network
 #endif  // SERVICES_NETWORK_PUBLIC_CPP_CONTENT_SECURITY_POLICY_CSP_SOURCE_LIST_H_
diff --git a/services/network/public/cpp/content_security_policy/csp_source_list_unittest.cc b/services/network/public/cpp/content_security_policy/csp_source_list_unittest.cc
index 7831ed6..4f9c329 100644
--- a/services/network/public/cpp/content_security_policy/csp_source_list_unittest.cc
+++ b/services/network/public/cpp/content_security_policy/csp_source_list_unittest.cc
@@ -6,7 +6,6 @@
 #include "base/strings/stringprintf.h"
 #include "net/http/http_response_headers.h"
 #include "services/network/public/cpp/content_security_policy/content_security_policy.h"
-#include "services/network/public/cpp/content_security_policy/csp_context.h"
 #include "services/network/public/mojom/content_security_policy.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/origin.h"
@@ -19,10 +18,10 @@
 // test expectations on one line.
 bool Allow(const mojom::CSPSourceListPtr& source_list,
            const GURL& url,
-           CSPContext* context,
+           const mojom::CSPSource& self,
            bool is_redirect = false,
            bool is_response_check = false) {
-  return CheckCSPSourceList(source_list, url, context, is_redirect,
+  return CheckCSPSourceList(*source_list, url, self, is_redirect,
                             is_response_check);
 }
 
@@ -77,8 +76,8 @@
 }  // namespace
 
 TEST(CSPSourceList, MultipleSource) {
-  CSPContext context;
-  context.SetSelf(url::Origin::Create(GURL("http://example.com")));
+  auto self = network::mojom::CSPSource::New("http", "example.com", 80, "",
+                                             false, false);
   std::vector<mojom::CSPSourcePtr> sources;
   sources.push_back(mojom::CSPSource::New("", "a.com", url::PORT_UNSPECIFIED,
                                           "", false, false));
@@ -86,92 +85,96 @@
                                           "", false, false));
   auto source_list = mojom::CSPSourceList::New();
   source_list->sources = std::move(sources);
-  EXPECT_TRUE(Allow(source_list, GURL("http://a.com"), &context));
-  EXPECT_TRUE(Allow(source_list, GURL("http://b.com"), &context));
-  EXPECT_FALSE(Allow(source_list, GURL("http://c.com"), &context));
+  EXPECT_TRUE(Allow(source_list, GURL("http://a.com"), *self));
+  EXPECT_TRUE(Allow(source_list, GURL("http://b.com"), *self));
+  EXPECT_FALSE(Allow(source_list, GURL("http://c.com"), *self));
 }
 
 TEST(CSPSourceList, AllowStar) {
-  CSPContext context;
-  context.SetSelf(url::Origin::Create(GURL("http://example.com")));
+  auto self = network::mojom::CSPSource::New("http", "example.com", 80, "",
+                                             false, false);
   auto source_list = mojom::CSPSourceList::New();
   source_list->allow_star = true;
-  EXPECT_TRUE(Allow(source_list, GURL("http://not-example.com"), &context));
-  EXPECT_TRUE(Allow(source_list, GURL("https://not-example.com"), &context));
-  EXPECT_TRUE(Allow(source_list, GURL("ws://not-example.com"), &context));
-  EXPECT_TRUE(Allow(source_list, GURL("wss://not-example.com"), &context));
-  EXPECT_TRUE(Allow(source_list, GURL("ftp://not-example.com"), &context));
+  EXPECT_TRUE(Allow(source_list, GURL("http://not-example.com"), *self));
+  EXPECT_TRUE(Allow(source_list, GURL("https://not-example.com"), *self));
+  EXPECT_TRUE(Allow(source_list, GURL("ws://not-example.com"), *self));
+  EXPECT_TRUE(Allow(source_list, GURL("wss://not-example.com"), *self));
+  EXPECT_TRUE(Allow(source_list, GURL("ftp://not-example.com"), *self));
 
-  EXPECT_FALSE(Allow(source_list, GURL("file://not-example.com"), &context));
-  EXPECT_FALSE(Allow(source_list, GURL("applewebdata://a.test"), &context));
+  EXPECT_FALSE(Allow(source_list, GURL("file://not-example.com"), *self));
+  EXPECT_FALSE(Allow(source_list, GURL("applewebdata://a.test"), *self));
 
-  // With a protocol of 'file', '*' allow 'file:'
-  context.SetSelf(url::Origin::Create(GURL("file://example.com")));
-  EXPECT_TRUE(Allow(source_list, GURL("file://not-example.com"), &context));
-  EXPECT_FALSE(Allow(source_list, GURL("applewebdata://a.test"), &context));
+  {
+    // With a protocol of 'file', '*' allow 'file:'
+    auto self = network::mojom::CSPSource::New(
+        "file", "example.com", url::PORT_UNSPECIFIED, "", false, false);
+    EXPECT_TRUE(Allow(source_list, GURL("file://not-example.com"), *self));
+    EXPECT_FALSE(Allow(source_list, GURL("applewebdata://a.test"), *self));
+  }
 }
 
 TEST(CSPSourceList, AllowSelf) {
-  CSPContext context;
-  context.SetSelf(url::Origin::Create(GURL("http://example.com")));
+  auto self = network::mojom::CSPSource::New("http", "example.com", 80, "",
+                                             false, false);
   auto source_list = mojom::CSPSourceList::New();
   source_list->allow_self = true;
-  EXPECT_TRUE(Allow(source_list, GURL("http://example.com"), &context));
-  EXPECT_FALSE(Allow(source_list, GURL("http://not-example.com"), &context));
-  EXPECT_TRUE(Allow(source_list, GURL("https://example.com"), &context));
-  EXPECT_FALSE(Allow(source_list, GURL("ws://example.com"), &context));
+  EXPECT_TRUE(Allow(source_list, GURL("http://example.com"), *self));
+  EXPECT_FALSE(Allow(source_list, GURL("http://not-example.com"), *self));
+  EXPECT_TRUE(Allow(source_list, GURL("https://example.com"), *self));
+  EXPECT_FALSE(Allow(source_list, GURL("ws://example.com"), *self));
 }
 
 TEST(CSPSourceList, AllowStarAndSelf) {
-  CSPContext context;
-  context.SetSelf(url::Origin::Create(GURL("https://a.com")));
+  auto self =
+      network::mojom::CSPSource::New("https", "a.com", 443, "", false, false);
   auto source_list = mojom::CSPSourceList::New();
 
   // If the request is allowed by {*} and not by {'self'} then it should be
   // allowed by the union {*,'self'}.
   source_list->allow_self = true;
   source_list->allow_star = false;
-  EXPECT_FALSE(Allow(source_list, GURL("http://b.com"), &context));
+  EXPECT_FALSE(Allow(source_list, GURL("http://b.com"), *self));
   source_list->allow_self = false;
   source_list->allow_star = true;
-  EXPECT_TRUE(Allow(source_list, GURL("http://b.com"), &context));
+  EXPECT_TRUE(Allow(source_list, GURL("http://b.com"), *self));
   source_list->allow_self = true;
   source_list->allow_star = true;
-  EXPECT_TRUE(Allow(source_list, GURL("http://b.com"), &context));
+  EXPECT_TRUE(Allow(source_list, GURL("http://b.com"), *self));
 }
 
 TEST(CSPSourceList, AllowSelfWithUnspecifiedPort) {
-  CSPContext context;
-  context.SetSelf(url::Origin::Create(GURL("https://example.com/")));
+  auto self = network::mojom::CSPSource::New("https", "example.com", 443, "",
+                                             false, false);
   auto source_list = mojom::CSPSourceList::New();
   source_list->allow_self = true;
 
-  EXPECT_TRUE(
-      Allow(source_list, GURL("https://example.com/print.pdf"), &context));
+  EXPECT_TRUE(Allow(source_list, GURL("https://example.com/print.pdf"), *self));
 }
 
 TEST(CSPSourceList, AllowNone) {
-  CSPContext context;
-  context.SetSelf(url::Origin::Create(GURL("http://example.com")));
+  auto self = network::mojom::CSPSource::New("http", "example.com", 80, "",
+                                             false, false);
   auto source_list = mojom::CSPSourceList::New();
-  EXPECT_FALSE(Allow(source_list, GURL("http://example.com"), &context));
-  EXPECT_FALSE(Allow(source_list, GURL("https://example.test/"), &context));
+  EXPECT_FALSE(Allow(source_list, GURL("http://example.com"), *self));
+  EXPECT_FALSE(Allow(source_list, GURL("https://example.test/"), *self));
 }
 
 TEST(CSPSourceTest, SelfIsUnique) {
   // Policy: 'self'
   auto source_list = mojom::CSPSourceList::New();
   source_list->allow_self = true;
-  CSPContext context;
 
-  context.SetSelf(url::Origin::Create(GURL("http://a.com")));
-  EXPECT_TRUE(Allow(source_list, GURL("http://a.com"), &context));
-  EXPECT_FALSE(Allow(source_list, GURL("data:text/html,hello"), &context));
+  auto self =
+      network::mojom::CSPSource::New("http", "a.com", 80, "", false, false);
+  EXPECT_TRUE(Allow(source_list, GURL("http://a.com"), *self));
+  EXPECT_FALSE(Allow(source_list, GURL("data:text/html,hello"), *self));
 
-  context.SetSelf(
-      url::Origin::Create(GURL("data:text/html,<iframe src=[...]>")));
-  EXPECT_FALSE(Allow(source_list, GURL("http://a.com"), &context));
-  EXPECT_FALSE(Allow(source_list, GURL("data:text/html,hello"), &context));
+  // Self doesn't match anything.
+  auto no_self_source = network::mojom::CSPSource::New(
+      "", "", url::PORT_UNSPECIFIED, "", false, false);
+  EXPECT_FALSE(Allow(source_list, GURL("http://a.com"), *no_self_source));
+  EXPECT_FALSE(
+      Allow(source_list, GURL("data:text/html,hello"), *no_self_source));
 }
 
 TEST(CSPSourceList, Subsume) {
@@ -257,6 +260,8 @@
       {{"http://*", "http://*.com http://*.example3.com:*/bar/"}, false},
   };
 
+  auto origin_b =
+      mojom::CSPSource::New("https", "frame.test", 443, "", false, false);
   for (const auto& test : cases) {
     auto response_sources = ParseToVectorOfSourceLists(
         mojom::CSPDirectiveName::ScriptSrc, test.response_csp);
@@ -264,8 +269,7 @@
     EXPECT_EQ(test.expected,
               CSPSourceListSubsumes(
                   *required_sources, ToRawPointers(response_sources),
-                  mojom::CSPDirectiveName::ScriptSrc,
-                  url::Origin::Create(GURL("https://frame.test"))))
+                  mojom::CSPDirectiveName::ScriptSrc, origin_b.get()))
         << required << " should " << (test.expected ? "" : "not ") << "subsume "
         << base::JoinString(test.response_csp, ", ");
   }
@@ -383,11 +387,14 @@
     auto response_sources = ParseToVectorOfSourceLists(
         mojom::CSPDirectiveName::ScriptSrc, test.response_csp);
 
+    GURL parsed_test_origin(test.origin);
+    auto origin_b = mojom::CSPSource::New(
+        parsed_test_origin.scheme(), parsed_test_origin.host(),
+        parsed_test_origin.EffectiveIntPort(), "", false, false);
     EXPECT_EQ(test.expected,
-              CSPSourceListSubsumes(*required_sources,
-                                    ToRawPointers(response_sources),
-                                    mojom::CSPDirectiveName::ScriptSrc,
-                                    url::Origin::Create(GURL(test.origin))))
+              CSPSourceListSubsumes(
+                  *required_sources, ToRawPointers(response_sources),
+                  mojom::CSPDirectiveName::ScriptSrc, origin_b.get()))
         << required << "from origin " << test.origin << " should "
         << (test.expected ? "" : "not ") << "subsume "
         << base::JoinString(test.response_csp, ", ");
@@ -489,17 +496,18 @@
        true},
   };
 
+  auto origin_b =
+      mojom::CSPSource::New("https", "frame.test", 443, "", false, false);
   for (const auto& test : cases) {
     mojom::CSPSourceListPtr required_sources =
         ParseToSourceList(test.directive, test.required);
     auto response_sources =
         ParseToVectorOfSourceLists(test.directive, test.response_csp);
 
-    EXPECT_EQ(
-        test.expected,
-        CSPSourceListSubsumes(*required_sources,
-                              ToRawPointers(response_sources), test.directive,
-                              url::Origin::Create(GURL("https://frame.test"))))
+    EXPECT_EQ(test.expected,
+              CSPSourceListSubsumes(*required_sources,
+                                    ToRawPointers(response_sources),
+                                    test.directive, origin_b.get()))
         << test.required << " should " << (test.expected ? "" : "not ")
         << "subsume " << base::JoinString(test.response_csp, ", ");
   }
@@ -576,17 +584,18 @@
        false},
   };
 
+  auto origin_b =
+      mojom::CSPSource::New("https", "frame.test", 443, "", false, false);
   for (const auto& test : cases) {
     mojom::CSPSourceListPtr required_sources =
         ParseToSourceList(test.directive, test.required);
     auto response_sources =
         ParseToVectorOfSourceLists(test.directive, test.response_csp);
 
-    EXPECT_EQ(
-        test.expected,
-        CSPSourceListSubsumes(*required_sources,
-                              ToRawPointers(response_sources), test.directive,
-                              url::Origin::Create(GURL("https://frame.test"))))
+    EXPECT_EQ(test.expected,
+              CSPSourceListSubsumes(*required_sources,
+                                    ToRawPointers(response_sources),
+                                    test.directive, origin_b.get()))
         << test.required << " should " << (test.expected ? "" : "not ")
         << "subsume " << base::JoinString(test.response_csp, ", ");
   }
@@ -728,17 +737,18 @@
        false},
   };
 
+  auto origin_b =
+      mojom::CSPSource::New("https", "frame.test", 443, "", false, false);
   for (const auto& test : cases) {
     mojom::CSPSourceListPtr required_sources =
         ParseToSourceList(test.directive, test.required);
     auto response_sources =
         ParseToVectorOfSourceLists(test.directive, test.response_csp);
 
-    EXPECT_EQ(
-        test.expected,
-        CSPSourceListSubsumes(*required_sources,
-                              ToRawPointers(response_sources), test.directive,
-                              url::Origin::Create(GURL("https://frame.test"))))
+    EXPECT_EQ(test.expected,
+              CSPSourceListSubsumes(*required_sources,
+                                    ToRawPointers(response_sources),
+                                    test.directive, origin_b.get()))
         << test.required << " should " << (test.expected ? "" : "not ")
         << "subsume " << base::JoinString(test.response_csp, ", ");
   }
@@ -911,17 +921,18 @@
        false},
   };
 
+  auto origin_b =
+      mojom::CSPSource::New("https", "frame.test", 443, "", false, false);
   for (const auto& test : cases) {
     mojom::CSPSourceListPtr required_sources =
         ParseToSourceList(test.directive, test.required);
     auto response_sources =
         ParseToVectorOfSourceLists(test.directive, test.response_csp);
 
-    EXPECT_EQ(
-        test.expected,
-        CSPSourceListSubsumes(*required_sources,
-                              ToRawPointers(response_sources), test.directive,
-                              url::Origin::Create(GURL("https://frame.test"))))
+    EXPECT_EQ(test.expected,
+              CSPSourceListSubsumes(*required_sources,
+                                    ToRawPointers(response_sources),
+                                    test.directive, origin_b.get()))
         << test.required << " should " << (test.expected ? "" : "not ")
         << "subsume " << base::JoinString(test.response_csp, ", ");
   }
@@ -982,6 +993,8 @@
        false},
   };
 
+  auto origin_b =
+      mojom::CSPSource::New("https", "another.test", 443, "", false, false);
   for (const auto& test : cases) {
     mojom::CSPSourceListPtr required_sources =
         ParseToSourceList(mojom::CSPDirectiveName::ScriptSrc, test.required);
@@ -991,33 +1004,36 @@
     EXPECT_EQ(test.expected,
               CSPSourceListSubsumes(
                   *required_sources, ToRawPointers(response_sources),
-                  mojom::CSPDirectiveName::ScriptSrc,
-                  url::Origin::Create(GURL("https://another.test/image.png"))))
+                  mojom::CSPDirectiveName::ScriptSrc, origin_b.get()))
         << test.required << " should " << (test.expected ? "" : "not ")
         << "subsume " << base::JoinString(test.response_csp, ", ");
   }
 }
 
 TEST(CSPSourceList, SubsumeListNoScheme) {
+  auto origin_http =
+      mojom::CSPSource::New("http", "example.org", 80, "", false, false);
+  auto origin_https =
+      mojom::CSPSource::New("https", "example.org", 443, "", false, false);
   struct TestCase {
     std::string required;
     std::vector<std::string> response_csp;
-    std::string origin;
+    mojom::CSPSource* origin;
     bool expected;
   } cases[] = {
-      {"http://a.com", {"a.com"}, "https://example.org", true},
-      {"https://a.com", {"a.com"}, "https://example.org", true},
-      {"https://a.com", {"a.com"}, "http://example.org", false},
-      {"data://a.com", {"a.com"}, "https://example.org", false},
-      {"a.com", {"a.com"}, "https://example.org", true},
-      {"a.com", {"a.com"}, "http://example.org", true},
-      {"a.com", {"https://a.com"}, "http://example.org", true},
-      {"a.com", {"https://a.com"}, "https://example.org", true},
-      {"a.com", {"http://a.com"}, "https://example.org", false},
-      {"https:", {"a.com"}, "http://example.org", false},
-      {"http:", {"a.com"}, "http://example.org", true},
-      {"https:", {"a.com", "https:"}, "http://example.org", true},
-      {"https:", {"a.com"}, "https://example.org", true},
+      {"http://a.com", {"a.com"}, origin_https.get(), true},
+      {"https://a.com", {"a.com"}, origin_https.get(), true},
+      {"https://a.com", {"a.com"}, origin_http.get(), false},
+      {"data://a.com", {"a.com"}, origin_https.get(), false},
+      {"a.com", {"a.com"}, origin_https.get(), true},
+      {"a.com", {"a.com"}, origin_http.get(), true},
+      {"a.com", {"https://a.com"}, origin_http.get(), true},
+      {"a.com", {"https://a.com"}, origin_https.get(), true},
+      {"a.com", {"http://a.com"}, origin_https.get(), false},
+      {"https:", {"a.com"}, origin_http.get(), false},
+      {"http:", {"a.com"}, origin_http.get(), true},
+      {"https:", {"a.com", "https:"}, origin_http.get(), true},
+      {"https:", {"a.com"}, origin_https.get(), true},
   };
 
   for (const auto& test : cases) {
@@ -1027,12 +1043,11 @@
         mojom::CSPDirectiveName::ScriptSrc, test.response_csp);
 
     EXPECT_EQ(test.expected,
-              CSPSourceListSubsumes(*required_sources,
-                                    ToRawPointers(response_sources),
-                                    mojom::CSPDirectiveName::ScriptSrc,
-                                    url::Origin::Create(GURL(test.origin))))
-        << test.required << " on origin " << test.origin << " should "
-        << (test.expected ? "" : "not ") << "subsume "
+              CSPSourceListSubsumes(
+                  *required_sources, ToRawPointers(response_sources),
+                  mojom::CSPDirectiveName::ScriptSrc, test.origin))
+        << test.required << " on origin with scheme " << test.origin->scheme
+        << " should " << (test.expected ? "" : "not ") << "subsume "
         << base::JoinString(test.response_csp, ", ");
   }
 }
diff --git a/services/network/public/cpp/content_security_policy/csp_source_unittest.cc b/services/network/public/cpp/content_security_policy/csp_source_unittest.cc
index 88f4e53..7ee11c20 100644
--- a/services/network/public/cpp/content_security_policy/csp_source_unittest.cc
+++ b/services/network/public/cpp/content_security_policy/csp_source_unittest.cc
@@ -5,7 +5,6 @@
 #include "services/network/public/cpp/content_security_policy/csp_source.h"
 #include "net/http/http_response_headers.h"
 #include "services/network/public/cpp/content_security_policy/content_security_policy.h"
-#include "services/network/public/cpp/content_security_policy/csp_context.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/origin.h"
 
@@ -15,11 +14,11 @@
 
 // Allow() is an abbreviation of CSPSource::Allow(). Useful for writing test
 // expectations on one line.
-bool Allow(const network::mojom::CSPSourcePtr& source,
+bool Allow(const network::mojom::CSPSource& source,
            const GURL& url,
-           CSPContext* context,
+           const network::mojom::CSPSource& self_source,
            bool is_redirect = false) {
-  return CheckCSPSource(source, url, context, is_redirect);
+  return CheckCSPSource(source, url, self_source, is_redirect);
 }
 
 network::mojom::CSPSourcePtr CSPSource(const std::string& raw) {
@@ -36,261 +35,291 @@
 }  // namespace
 
 TEST(CSPSourceTest, BasicMatching) {
-  CSPContext context;
-
   auto source = network::mojom::CSPSource::New("http", "example.com", 8000,
                                                "/foo/", false, false);
 
-  EXPECT_TRUE(Allow(source, GURL("http://example.com:8000/foo/"), &context));
-  EXPECT_TRUE(Allow(source, GURL("http://example.com:8000/foo/bar"), &context));
-  EXPECT_TRUE(Allow(source, GURL("HTTP://EXAMPLE.com:8000/foo/BAR"), &context));
+  // Self doesn't match anything.
+  auto self_source = network::mojom::CSPSource::New(
+      "", "", url::PORT_UNSPECIFIED, "", false, false);
 
-  EXPECT_FALSE(Allow(source, GURL("http://example.com:8000/bar/"), &context));
-  EXPECT_FALSE(Allow(source, GURL("https://example.com:8000/bar/"), &context));
-  EXPECT_FALSE(Allow(source, GURL("http://example.com:9000/bar/"), &context));
+  EXPECT_TRUE(
+      Allow(*source, GURL("http://example.com:8000/foo/"), *self_source));
+  EXPECT_TRUE(
+      Allow(*source, GURL("http://example.com:8000/foo/bar"), *self_source));
+  EXPECT_TRUE(
+      Allow(*source, GURL("HTTP://EXAMPLE.com:8000/foo/BAR"), *self_source));
+
   EXPECT_FALSE(
-      Allow(source, GURL("HTTP://example.com:8000/FOO/bar"), &context));
+      Allow(*source, GURL("http://example.com:8000/bar/"), *self_source));
   EXPECT_FALSE(
-      Allow(source, GURL("HTTP://example.com:8000/FOO/BAR"), &context));
+      Allow(*source, GURL("https://example.com:8000/bar/"), *self_source));
+  EXPECT_FALSE(
+      Allow(*source, GURL("http://example.com:9000/bar/"), *self_source));
+  EXPECT_FALSE(
+      Allow(*source, GURL("HTTP://example.com:8000/FOO/bar"), *self_source));
+  EXPECT_FALSE(
+      Allow(*source, GURL("HTTP://example.com:8000/FOO/BAR"), *self_source));
 }
 
 TEST(CSPSourceTest, AllowScheme) {
-  CSPContext context;
+  // Self doesn't match anything.
+  auto no_self_source = network::mojom::CSPSource::New(
+      "", "", url::PORT_UNSPECIFIED, "", false, false);
 
   // http -> {http, https}.
   {
     auto source = network::mojom::CSPSource::New(
         "http", "", url::PORT_UNSPECIFIED, "", false, false);
-    EXPECT_TRUE(Allow(source, GURL("http://a.com"), &context));
-    EXPECT_TRUE(Allow(source, GURL("https://a.com"), &context));
+    EXPECT_TRUE(Allow(*source, GURL("http://a.com"), *no_self_source));
+    EXPECT_TRUE(Allow(*source, GURL("https://a.com"), *no_self_source));
     // This passes because the source is "scheme only" so the upgrade is
     // allowed.
-    EXPECT_TRUE(Allow(source, GURL("https://a.com:80"), &context));
-    EXPECT_FALSE(Allow(source, GURL("ftp://a.com"), &context));
-    EXPECT_FALSE(Allow(source, GURL("ws://a.com"), &context));
-    EXPECT_FALSE(Allow(source, GURL("wss://a.com"), &context));
+    EXPECT_TRUE(Allow(*source, GURL("https://a.com:80"), *no_self_source));
+    EXPECT_FALSE(Allow(*source, GURL("ftp://a.com"), *no_self_source));
+    EXPECT_FALSE(Allow(*source, GURL("ws://a.com"), *no_self_source));
+    EXPECT_FALSE(Allow(*source, GURL("wss://a.com"), *no_self_source));
   }
 
   // ws -> {ws, wss}.
   {
     auto source = network::mojom::CSPSource::New(
         "ws", "", url::PORT_UNSPECIFIED, "", false, false);
-    EXPECT_FALSE(Allow(source, GURL("http://a.com"), &context));
-    EXPECT_FALSE(Allow(source, GURL("https://a.com"), &context));
-    EXPECT_FALSE(Allow(source, GURL("ftp://a.com"), &context));
-    EXPECT_TRUE(Allow(source, GURL("ws://a.com"), &context));
-    EXPECT_TRUE(Allow(source, GURL("wss://a.com"), &context));
+    EXPECT_FALSE(Allow(*source, GURL("http://a.com"), *no_self_source));
+    EXPECT_FALSE(Allow(*source, GURL("https://a.com"), *no_self_source));
+    EXPECT_FALSE(Allow(*source, GURL("ftp://a.com"), *no_self_source));
+    EXPECT_TRUE(Allow(*source, GURL("ws://a.com"), *no_self_source));
+    EXPECT_TRUE(Allow(*source, GURL("wss://a.com"), *no_self_source));
   }
 
   // Exact matches required (ftp)
   {
     auto source = network::mojom::CSPSource::New(
         "ftp", "", url::PORT_UNSPECIFIED, "", false, false);
-    EXPECT_TRUE(Allow(source, GURL("ftp://a.com"), &context));
-    EXPECT_FALSE(Allow(source, GURL("http://a.com"), &context));
+    EXPECT_TRUE(Allow(*source, GURL("ftp://a.com"), *no_self_source));
+    EXPECT_FALSE(Allow(*source, GURL("http://a.com"), *no_self_source));
   }
 
   // Exact matches required (https)
   {
     auto source = network::mojom::CSPSource::New(
         "https", "", url::PORT_UNSPECIFIED, "", false, false);
-    EXPECT_TRUE(Allow(source, GURL("https://a.com"), &context));
-    EXPECT_FALSE(Allow(source, GURL("http://a.com"), &context));
+    EXPECT_TRUE(Allow(*source, GURL("https://a.com"), *no_self_source));
+    EXPECT_FALSE(Allow(*source, GURL("http://a.com"), *no_self_source));
   }
 
   // Exact matches required (wss)
   {
     auto source = network::mojom::CSPSource::New(
         "wss", "", url::PORT_UNSPECIFIED, "", false, false);
-    EXPECT_TRUE(Allow(source, GURL("wss://a.com"), &context));
-    EXPECT_FALSE(Allow(source, GURL("ws://a.com"), &context));
+    EXPECT_TRUE(Allow(*source, GURL("wss://a.com"), *no_self_source));
+    EXPECT_FALSE(Allow(*source, GURL("ws://a.com"), *no_self_source));
   }
 
   // Scheme is empty (ProtocolMatchesSelf).
   {
     auto source = network::mojom::CSPSource::New(
         "", "a.com", url::PORT_UNSPECIFIED, "", false, false);
-    EXPECT_FALSE(Allow(source, GURL("http://a.com"), &context));
+    EXPECT_FALSE(Allow(*source, GURL("http://a.com"), *no_self_source));
 
-    // Self's scheme is http.
-    context.SetSelf(url::Origin::Create(GURL("http://a.com")));
-    EXPECT_TRUE(Allow(source, GURL("http://a.com"), &context));
-    EXPECT_TRUE(Allow(source, GURL("https://a.com"), &context));
-    EXPECT_FALSE(Allow(source, GURL("ftp://a.com"), &context));
+    {
+      // Self's scheme is http.
+      auto self_source =
+          network::mojom::CSPSource::New("http", "a.com", 80, "", false, false);
+      EXPECT_TRUE(Allow(*source, GURL("http://a.com"), *self_source));
+      EXPECT_TRUE(Allow(*source, GURL("https://a.com"), *self_source));
+      EXPECT_FALSE(Allow(*source, GURL("ftp://a.com"), *self_source));
+    }
 
-    // Self's is https.
-    context.SetSelf(url::Origin::Create(GURL("https://a.com")));
-    EXPECT_FALSE(Allow(source, GURL("http://a.com"), &context));
-    EXPECT_TRUE(Allow(source, GURL("https://a.com"), &context));
-    EXPECT_FALSE(Allow(source, GURL("ftp://a.com"), &context));
+    {
+      // Self's is https.
+      auto self_source = network::mojom::CSPSource::New("https", "a.com", 443,
+                                                        "", false, false);
+      EXPECT_FALSE(Allow(*source, GURL("http://a.com"), *self_source));
+      EXPECT_TRUE(Allow(*source, GURL("https://a.com"), *self_source));
+      EXPECT_FALSE(Allow(*source, GURL("ftp://a.com"), *self_source));
+    }
 
-    // Self's scheme is not in the http familly.
-    context.SetSelf(url::Origin::Create(GURL("ftp://a.com/")));
-    EXPECT_FALSE(Allow(source, GURL("http://a.com"), &context));
-    EXPECT_TRUE(Allow(source, GURL("ftp://a.com"), &context));
+    {
+      // Self's scheme is not in the http family.
+      auto self_source =
+          network::mojom::CSPSource::New("ftp", "a.com", 21, "", false, false);
+      EXPECT_FALSE(Allow(*source, GURL("http://a.com"), *self_source));
+      EXPECT_TRUE(Allow(*source, GURL("ftp://a.com"), *self_source));
+    }
 
-    // Self's scheme is unique (non standard scheme).
-    context.SetSelf(url::Origin::Create(GURL("non-standard-scheme://a.com")));
-    EXPECT_FALSE(Allow(source, GURL("http://a.com"), &context));
-    EXPECT_FALSE(Allow(source, GURL("non-standard-scheme://a.com"), &context));
+    {
+      // Self's scheme is unique (non standard scheme).
+      auto self_source = network::mojom::CSPSource::New(
+          "non-standard-scheme", "a.com", url::PORT_UNSPECIFIED, "", false,
+          false);
+      EXPECT_FALSE(Allow(*source, GURL("http://a.com"), *self_source));
+      EXPECT_FALSE(
+          Allow(*source, GURL("non-standard-scheme://a.com"), *self_source));
+    }
 
-    // Self's scheme is unique (data-url).
-    context.SetSelf(
-        url::Origin::Create(GURL("data:text/html,<iframe src=[...]>")));
-    EXPECT_FALSE(Allow(source, GURL("http://a.com"), &context));
-    EXPECT_FALSE(Allow(source, GURL("data:text/html,hello"), &context));
+    // Self's scheme is unique (e.g. data-url).
+    EXPECT_FALSE(Allow(*source, GURL("http://a.com"), *no_self_source));
+    EXPECT_FALSE(Allow(*source, GURL("data:text/html,hello"), *no_self_source));
   }
 }
 
 TEST(CSPSourceTest, AllowHost) {
-  CSPContext context;
-  context.SetSelf(url::Origin::Create(GURL("http://example.com")));
+  auto self_source = network::mojom::CSPSource::New("http", "example.com", 80,
+                                                    "", false, false);
+
+  // Self doesn't match anything.
+  auto no_self_source = network::mojom::CSPSource::New(
+      "", "", url::PORT_UNSPECIFIED, "", false, false);
 
   // Host is * (source-expression = "http://*")
   {
     auto source = network::mojom::CSPSource::New(
         "http", "", url::PORT_UNSPECIFIED, "", true, false);
-    EXPECT_TRUE(Allow(source, GURL("http://a.com"), &context));
-    EXPECT_TRUE(Allow(source, GURL("http://."), &context));
+    EXPECT_TRUE(Allow(*source, GURL("http://a.com"), *self_source));
+    EXPECT_TRUE(Allow(*source, GURL("http://."), *self_source));
   }
 
   // Host is *.foo.bar
   {
     auto source = network::mojom::CSPSource::New(
         "", "foo.bar", url::PORT_UNSPECIFIED, "", true, false);
-    EXPECT_FALSE(Allow(source, GURL("http://a.com"), &context));
-    EXPECT_FALSE(Allow(source, GURL("http://bar"), &context));
-    EXPECT_FALSE(Allow(source, GURL("http://foo.bar"), &context));
-    EXPECT_FALSE(Allow(source, GURL("http://o.bar"), &context));
-    EXPECT_TRUE(Allow(source, GURL("http://*.foo.bar"), &context));
-    EXPECT_TRUE(Allow(source, GURL("http://sub.foo.bar"), &context));
-    EXPECT_TRUE(Allow(source, GURL("http://sub.sub.foo.bar"), &context));
+    EXPECT_FALSE(Allow(*source, GURL("http://a.com"), *self_source));
+    EXPECT_FALSE(Allow(*source, GURL("http://bar"), *self_source));
+    EXPECT_FALSE(Allow(*source, GURL("http://foo.bar"), *self_source));
+    EXPECT_FALSE(Allow(*source, GURL("http://o.bar"), *self_source));
+    EXPECT_TRUE(Allow(*source, GURL("http://*.foo.bar"), *self_source));
+    EXPECT_TRUE(Allow(*source, GURL("http://sub.foo.bar"), *self_source));
+    EXPECT_TRUE(Allow(*source, GURL("http://sub.sub.foo.bar"), *self_source));
     // Please see http://crbug.com/692505
-    EXPECT_TRUE(Allow(source, GURL("http://.foo.bar"), &context));
+    EXPECT_TRUE(Allow(*source, GURL("http://.foo.bar"), *self_source));
   }
 
   // Host is exact.
   {
     auto source = network::mojom::CSPSource::New(
         "", "foo.bar", url::PORT_UNSPECIFIED, "", false, false);
-    EXPECT_TRUE(Allow(source, GURL("http://foo.bar"), &context));
-    EXPECT_FALSE(Allow(source, GURL("http://sub.foo.bar"), &context));
-    EXPECT_FALSE(Allow(source, GURL("http://bar"), &context));
+    EXPECT_TRUE(Allow(*source, GURL("http://foo.bar"), *self_source));
+    EXPECT_FALSE(Allow(*source, GURL("http://sub.foo.bar"), *self_source));
+    EXPECT_FALSE(Allow(*source, GURL("http://bar"), *self_source));
     // Please see http://crbug.com/692505
-    EXPECT_FALSE(Allow(source, GURL("http://.foo.bar"), &context));
+    EXPECT_FALSE(Allow(*source, GURL("http://.foo.bar"), *self_source));
   }
 }
 
 TEST(CSPSourceTest, AllowPort) {
-  CSPContext context;
-  context.SetSelf(url::Origin::Create(GURL("http://example.com")));
+  auto self_source = network::mojom::CSPSource::New("http", "example.com", 80,
+                                                    "", false, false);
 
   // Source's port unspecified.
   {
     auto source = network::mojom::CSPSource::New(
         "", "a.com", url::PORT_UNSPECIFIED, "", false, false);
-    EXPECT_TRUE(Allow(source, GURL("http://a.com:80"), &context));
-    EXPECT_FALSE(Allow(source, GURL("http://a.com:8080"), &context));
-    EXPECT_FALSE(Allow(source, GURL("http://a.com:443"), &context));
-    EXPECT_FALSE(Allow(source, GURL("https://a.com:80"), &context));
-    EXPECT_FALSE(Allow(source, GURL("https://a.com:8080"), &context));
-    EXPECT_TRUE(Allow(source, GURL("https://a.com:443"), &context));
-    EXPECT_FALSE(Allow(source, GURL("unknown://a.com:80"), &context));
-    EXPECT_TRUE(Allow(source, GURL("http://a.com"), &context));
-    EXPECT_TRUE(Allow(source, GURL("http://a.com"), &context));
-    EXPECT_TRUE(Allow(source, GURL("https://a.com"), &context));
+    EXPECT_TRUE(Allow(*source, GURL("http://a.com:80"), *self_source));
+    EXPECT_FALSE(Allow(*source, GURL("http://a.com:8080"), *self_source));
+    EXPECT_FALSE(Allow(*source, GURL("http://a.com:443"), *self_source));
+    EXPECT_FALSE(Allow(*source, GURL("https://a.com:80"), *self_source));
+    EXPECT_FALSE(Allow(*source, GURL("https://a.com:8080"), *self_source));
+    EXPECT_TRUE(Allow(*source, GURL("https://a.com:443"), *self_source));
+    EXPECT_FALSE(Allow(*source, GURL("unknown://a.com:80"), *self_source));
+    EXPECT_TRUE(Allow(*source, GURL("http://a.com"), *self_source));
+    EXPECT_TRUE(Allow(*source, GURL("http://a.com"), *self_source));
+    EXPECT_TRUE(Allow(*source, GURL("https://a.com"), *self_source));
   }
 
   // Source's port is "*".
   {
     auto source = network::mojom::CSPSource::New(
         "", "a.com", url::PORT_UNSPECIFIED, "", false, true);
-    EXPECT_TRUE(Allow(source, GURL("http://a.com"), &context));
-    EXPECT_TRUE(Allow(source, GURL("http://a.com:80"), &context));
-    EXPECT_TRUE(Allow(source, GURL("http://a.com:8080"), &context));
-    EXPECT_TRUE(Allow(source, GURL("https://a.com:8080"), &context));
-    EXPECT_TRUE(Allow(source, GURL("https://a.com:0"), &context));
-    EXPECT_TRUE(Allow(source, GURL("https://a.com"), &context));
+    EXPECT_TRUE(Allow(*source, GURL("http://a.com"), *self_source));
+    EXPECT_TRUE(Allow(*source, GURL("http://a.com:80"), *self_source));
+    EXPECT_TRUE(Allow(*source, GURL("http://a.com:8080"), *self_source));
+    EXPECT_TRUE(Allow(*source, GURL("https://a.com:8080"), *self_source));
+    EXPECT_TRUE(Allow(*source, GURL("https://a.com:0"), *self_source));
+    EXPECT_TRUE(Allow(*source, GURL("https://a.com"), *self_source));
   }
 
   // Source has a port.
   {
     auto source =
         network::mojom::CSPSource::New("", "a.com", 80, "", false, false);
-    EXPECT_TRUE(Allow(source, GURL("http://a.com:80"), &context));
-    EXPECT_TRUE(Allow(source, GURL("http://a.com"), &context));
-    EXPECT_FALSE(Allow(source, GURL("http://a.com:8080"), &context));
-    EXPECT_TRUE(Allow(source, GURL("https://a.com"), &context));
+    EXPECT_TRUE(Allow(*source, GURL("http://a.com:80"), *self_source));
+    EXPECT_TRUE(Allow(*source, GURL("http://a.com"), *self_source));
+    EXPECT_FALSE(Allow(*source, GURL("http://a.com:8080"), *self_source));
+    EXPECT_TRUE(Allow(*source, GURL("https://a.com"), *self_source));
   }
 
   // Allow upgrade from :80 to :443
   {
     auto source =
         network::mojom::CSPSource::New("", "a.com", 80, "", false, false);
-    EXPECT_TRUE(Allow(source, GURL("https://a.com:443"), &context));
+    EXPECT_TRUE(Allow(*source, GURL("https://a.com:443"), *self_source));
     // Should not allow scheme upgrades unless both port and scheme are
     // upgraded.
-    EXPECT_FALSE(Allow(source, GURL("http://a.com:443"), &context));
+    EXPECT_FALSE(Allow(*source, GURL("http://a.com:443"), *self_source));
   }
 
   // Host is * but port is specified
   {
     auto source =
         network::mojom::CSPSource::New("http", "", 111, "", true, false);
-    EXPECT_TRUE(Allow(source, GURL("http://a.com:111"), &context));
-    EXPECT_FALSE(Allow(source, GURL("http://a.com:222"), &context));
+    EXPECT_TRUE(Allow(*source, GURL("http://a.com:111"), *self_source));
+    EXPECT_FALSE(Allow(*source, GURL("http://a.com:222"), *self_source));
   }
 }
 
 TEST(CSPSourceTest, AllowPath) {
-  CSPContext context;
-  context.SetSelf(url::Origin::Create(GURL("http://example.com")));
+  auto self_source = network::mojom::CSPSource::New("http", "example.com", 80,
+                                                    "", false, false);
 
   // Path to a file
   {
     auto source = network::mojom::CSPSource::New(
         "", "a.com", url::PORT_UNSPECIFIED, "/path/to/file", false, false);
-    EXPECT_TRUE(Allow(source, GURL("http://a.com/path/to/file"), &context));
-    EXPECT_FALSE(Allow(source, GURL("http://a.com/path/to/"), &context));
+    EXPECT_TRUE(
+        Allow(*source, GURL("http://a.com/path/to/file"), *self_source));
+    EXPECT_FALSE(Allow(*source, GURL("http://a.com/path/to/"), *self_source));
+    EXPECT_FALSE(Allow(*source, GURL("http://a.com/path/to/file/subpath"),
+                       *self_source));
     EXPECT_FALSE(
-        Allow(source, GURL("http://a.com/path/to/file/subpath"), &context));
-    EXPECT_FALSE(
-        Allow(source, GURL("http://a.com/path/to/something"), &context));
-    EXPECT_FALSE(Allow(source, GURL("http://a.com/"), &context));
-    EXPECT_FALSE(Allow(source, GURL("http://a.com"), &context));
+        Allow(*source, GURL("http://a.com/path/to/something"), *self_source));
+    EXPECT_FALSE(Allow(*source, GURL("http://a.com/"), *self_source));
+    EXPECT_FALSE(Allow(*source, GURL("http://a.com"), *self_source));
   }
 
   // Path to a directory
   {
     auto source = network::mojom::CSPSource::New(
         "", "a.com", url::PORT_UNSPECIFIED, "/path/to/", false, false);
-    EXPECT_TRUE(Allow(source, GURL("http://a.com/path/to/file"), &context));
-    EXPECT_TRUE(Allow(source, GURL("http://a.com/path/to/"), &context));
-    EXPECT_FALSE(Allow(source, GURL("http://a.com/path/"), &context));
-    EXPECT_FALSE(Allow(source, GURL("http://a.com/path/to"), &context));
-    EXPECT_FALSE(Allow(source, GURL("http://a.com/path/to"), &context));
-    EXPECT_FALSE(Allow(source, GURL("http://a.com/"), &context));
-    EXPECT_FALSE(Allow(source, GURL("http://a.com"), &context));
+    EXPECT_TRUE(
+        Allow(*source, GURL("http://a.com/path/to/file"), *self_source));
+    EXPECT_TRUE(Allow(*source, GURL("http://a.com/path/to/"), *self_source));
+    EXPECT_FALSE(Allow(*source, GURL("http://a.com/path/"), *self_source));
+    EXPECT_FALSE(Allow(*source, GURL("http://a.com/path/to"), *self_source));
+    EXPECT_FALSE(Allow(*source, GURL("http://a.com/path/to"), *self_source));
+    EXPECT_FALSE(Allow(*source, GURL("http://a.com/"), *self_source));
+    EXPECT_FALSE(Allow(*source, GURL("http://a.com"), *self_source));
   }
 
   // Empty path
   {
     auto source = network::mojom::CSPSource::New(
         "", "a.com", url::PORT_UNSPECIFIED, "", false, false);
-    EXPECT_TRUE(Allow(source, GURL("http://a.com/path/to/file"), &context));
-    EXPECT_TRUE(Allow(source, GURL("http://a.com/path/to/"), &context));
-    EXPECT_TRUE(Allow(source, GURL("http://a.com/"), &context));
-    EXPECT_TRUE(Allow(source, GURL("http://a.com"), &context));
+    EXPECT_TRUE(
+        Allow(*source, GURL("http://a.com/path/to/file"), *self_source));
+    EXPECT_TRUE(Allow(*source, GURL("http://a.com/path/to/"), *self_source));
+    EXPECT_TRUE(Allow(*source, GURL("http://a.com/"), *self_source));
+    EXPECT_TRUE(Allow(*source, GURL("http://a.com"), *self_source));
   }
 
   // Almost empty path
   {
     auto source = network::mojom::CSPSource::New(
         "", "a.com", url::PORT_UNSPECIFIED, "/", false, false);
-    EXPECT_TRUE(Allow(source, GURL("http://a.com/path/to/file"), &context));
-    EXPECT_TRUE(Allow(source, GURL("http://a.com/path/to/"), &context));
-    EXPECT_TRUE(Allow(source, GURL("http://a.com/"), &context));
-    EXPECT_TRUE(Allow(source, GURL("http://a.com"), &context));
+    EXPECT_TRUE(
+        Allow(*source, GURL("http://a.com/path/to/file"), *self_source));
+    EXPECT_TRUE(Allow(*source, GURL("http://a.com/path/to/"), *self_source));
+    EXPECT_TRUE(Allow(*source, GURL("http://a.com/"), *self_source));
+    EXPECT_TRUE(Allow(*source, GURL("http://a.com"), *self_source));
   }
 
   // Path encoded.
@@ -298,29 +327,39 @@
     auto source = network::mojom::CSPSource::New(
         "http", "a.com", url::PORT_UNSPECIFIED, "/Hello Günter", false, false);
     EXPECT_TRUE(
-        Allow(source, GURL("http://a.com/Hello%20G%C3%BCnter"), &context));
-    EXPECT_TRUE(Allow(source, GURL("http://a.com/Hello Günter"), &context));
+        Allow(*source, GURL("http://a.com/Hello%20G%C3%BCnter"), *self_source));
+    EXPECT_TRUE(
+        Allow(*source, GURL("http://a.com/Hello Günter"), *self_source));
   }
 
   // Host is * but path is specified.
   {
     auto source = network::mojom::CSPSource::New(
         "http", "", url::PORT_UNSPECIFIED, "/allowed-path", true, false);
-    EXPECT_TRUE(Allow(source, GURL("http://a.com/allowed-path"), &context));
-    EXPECT_FALSE(Allow(source, GURL("http://a.com/disallowed-path"), &context));
+    EXPECT_TRUE(
+        Allow(*source, GURL("http://a.com/allowed-path"), *self_source));
+    EXPECT_FALSE(
+        Allow(*source, GURL("http://a.com/disallowed-path"), *self_source));
   }
 }
 
 TEST(CSPSourceTest, RedirectMatching) {
-  CSPContext context;
   auto source = network::mojom::CSPSource::New("http", "a.com", 8000, "/bar/",
                                                false, false);
-  EXPECT_TRUE(Allow(source, GURL("http://a.com:8000/"), &context, true));
-  EXPECT_TRUE(Allow(source, GURL("http://a.com:8000/foo"), &context, true));
-  EXPECT_FALSE(Allow(source, GURL("https://a.com:8000/foo"), &context, true));
+
+  // Self doesn't match anything.
+  auto self_source = network::mojom::CSPSource::New(
+      "", "", url::PORT_UNSPECIFIED, "", false, false);
+
+  EXPECT_TRUE(Allow(*source, GURL("http://a.com:8000/"), *self_source, true));
+  EXPECT_TRUE(
+      Allow(*source, GURL("http://a.com:8000/foo"), *self_source, true));
   EXPECT_FALSE(
-      Allow(source, GURL("http://not-a.com:8000/foo"), &context, true));
-  EXPECT_FALSE(Allow(source, GURL("http://a.com:9000/foo/"), &context, false));
+      Allow(*source, GURL("https://a.com:8000/foo"), *self_source, true));
+  EXPECT_FALSE(
+      Allow(*source, GURL("http://not-a.com:8000/foo"), *self_source, true));
+  EXPECT_FALSE(
+      Allow(*source, GURL("http://a.com:9000/foo/"), *self_source, false));
 }
 
 TEST(CSPSourceTest, Intersect) {
@@ -373,14 +412,14 @@
     auto a = CSPSource(test.a);
     auto b = CSPSource(test.b);
 
-    auto a_intersect_b = CSPSourcesIntersect(a, b);
-    auto b_intersect_a = CSPSourcesIntersect(b, a);
+    auto a_intersect_b = CSPSourcesIntersect(*a, *b);
+    auto b_intersect_a = CSPSourcesIntersect(*b, *a);
     if (test.intersection) {
-      EXPECT_EQ(test.intersection, ToString(a_intersect_b))
+      EXPECT_EQ(test.intersection, ToString(*a_intersect_b))
           << "The intersection of " << test.a << " and " << test.b
           << " should be " << test.intersection;
       // Intersection should be symmetric.
-      EXPECT_EQ(test.intersection, ToString(b_intersect_a))
+      EXPECT_EQ(test.intersection, ToString(*b_intersect_a))
           << "The intersection of " << test.b << " and " << test.a
           << " should be " << test.intersection;
     } else {
@@ -416,9 +455,9 @@
     auto a = CSPSource(test.a);
     auto b = CSPSource(test.b);
 
-    EXPECT_FALSE(CSPSourceSubsumes(a, b))
+    EXPECT_FALSE(CSPSourceSubsumes(*a, *b))
         << test.a << " should not subsume " << test.b;
-    EXPECT_FALSE(CSPSourceSubsumes(b, a))
+    EXPECT_FALSE(CSPSourceSubsumes(*b, *a))
         << test.b << " should not subsume " << test.a;
   }
 }
@@ -466,22 +505,22 @@
     auto a = CSPSource(test.a);
     auto b = CSPSource(test.b);
 
-    EXPECT_EQ(CSPSourceSubsumes(a, b), test.expected_a_subsumes_b)
+    EXPECT_EQ(CSPSourceSubsumes(*a, *b), test.expected_a_subsumes_b)
         << test.a << " subsumes " << test.b << " should return "
         << test.expected_a_subsumes_b;
-    EXPECT_EQ(CSPSourceSubsumes(b, a), test.expected_b_subsumes_a)
+    EXPECT_EQ(CSPSourceSubsumes(*b, *a), test.expected_b_subsumes_a)
         << test.b << " subsumes " << test.a << " should return "
         << test.expected_b_subsumes_a;
 
     a->is_host_wildcard = true;
-    EXPECT_FALSE(CSPSourceSubsumes(b, a))
-        << test.b << " should not subsume " << ToString(a);
+    EXPECT_FALSE(CSPSourceSubsumes(*b, *a))
+        << test.b << " should not subsume " << ToString(*a);
 
     // If also |b| has a wildcard host, then the result should be the expected
     // one.
     b->is_host_wildcard = true;
-    EXPECT_EQ(CSPSourceSubsumes(b, a), test.expected_b_subsumes_a)
-        << ToString(b) << " subsumes " << ToString(a) << " should return "
+    EXPECT_EQ(CSPSourceSubsumes(*b, *a), test.expected_b_subsumes_a)
+        << ToString(*b) << " subsumes " << ToString(*a) << " should return "
         << test.expected_b_subsumes_a;
   }
 }
@@ -498,21 +537,21 @@
   auto source_d = CSPSource(d);
 
   // *.example.com subsumes www.example.com.
-  EXPECT_TRUE(CSPSourceSubsumes(source_a, source_b))
+  EXPECT_TRUE(CSPSourceSubsumes(*source_a, *source_b))
       << a << " should subsume " << b;
-  EXPECT_FALSE(CSPSourceSubsumes(source_b, source_a))
+  EXPECT_FALSE(CSPSourceSubsumes(*source_b, *source_a))
       << b << " should not subsume " << a;
 
   // *.example.com and example.com have no relations.
-  EXPECT_FALSE(CSPSourceSubsumes(source_a, source_c))
+  EXPECT_FALSE(CSPSourceSubsumes(*source_a, *source_c))
       << a << " should not subsume " << c;
-  EXPECT_FALSE(CSPSourceSubsumes(source_c, source_a))
+  EXPECT_FALSE(CSPSourceSubsumes(*source_c, *source_a))
       << c << " should not subsume " << a;
 
   // https://*.example.com and http://www.example.com have no relations.
-  EXPECT_FALSE(CSPSourceSubsumes(source_d, source_b))
+  EXPECT_FALSE(CSPSourceSubsumes(*source_d, *source_b))
       << d << " should not subsume " << b;
-  EXPECT_FALSE(CSPSourceSubsumes(source_b, source_d))
+  EXPECT_FALSE(CSPSourceSubsumes(*source_b, *source_d))
       << b << " should not subsume " << d;
 }
 
@@ -525,15 +564,15 @@
   auto source_b = CSPSource(b);
   auto source_c = CSPSource(c);
 
-  EXPECT_TRUE(CSPSourceSubsumes(source_a, source_b))
+  EXPECT_TRUE(CSPSourceSubsumes(*source_a, *source_b))
       << a << " should subsume " << b;
-  EXPECT_FALSE(CSPSourceSubsumes(source_b, source_a))
+  EXPECT_FALSE(CSPSourceSubsumes(*source_b, *source_a))
       << b << " should not subsume " << a;
 
   // https://example.com:* and http://example.com have no relations.
-  EXPECT_FALSE(CSPSourceSubsumes(source_b, source_c))
+  EXPECT_FALSE(CSPSourceSubsumes(*source_b, *source_c))
       << b << " should not subsume " << c;
-  EXPECT_FALSE(CSPSourceSubsumes(source_c, source_b))
+  EXPECT_FALSE(CSPSourceSubsumes(*source_c, *source_b))
       << c << " should not subsume " << b;
 }
 
@@ -564,7 +603,7 @@
   for (const auto& test : cases) {
     auto source_a = CSPSource(test.a);
     auto source_b = CSPSource(test.b);
-    EXPECT_EQ(CSPSourceSubsumes(source_a, source_b), test.expected)
+    EXPECT_EQ(CSPSourceSubsumes(*source_a, *source_b), test.expected)
         << test.a << " subsumes " << test.b << " should return "
         << test.expected;
   }
@@ -574,54 +613,58 @@
   {
     auto source = network::mojom::CSPSource::New(
         "http", "", url::PORT_UNSPECIFIED, "", false, false);
-    EXPECT_EQ("http:", ToString(source));
+    EXPECT_EQ("http:", ToString(*source));
   }
   {
     auto source = network::mojom::CSPSource::New(
         "http", "a.com", url::PORT_UNSPECIFIED, "", false, false);
-    EXPECT_EQ("http://a.com", ToString(source));
+    EXPECT_EQ("http://a.com", ToString(*source));
   }
   {
     auto source = network::mojom::CSPSource::New(
         "", "a.com", url::PORT_UNSPECIFIED, "", false, false);
-    EXPECT_EQ("a.com", ToString(source));
+    EXPECT_EQ("a.com", ToString(*source));
   }
   {
     auto source = network::mojom::CSPSource::New(
         "", "a.com", url::PORT_UNSPECIFIED, "", true, false);
-    EXPECT_EQ("*.a.com", ToString(source));
+    EXPECT_EQ("*.a.com", ToString(*source));
   }
   {
     auto source = network::mojom::CSPSource::New("", "", url::PORT_UNSPECIFIED,
                                                  "", true, false);
-    EXPECT_EQ("*", ToString(source));
+    EXPECT_EQ("*", ToString(*source));
   }
   {
     auto source =
         network::mojom::CSPSource::New("", "a.com", 80, "", false, false);
-    EXPECT_EQ("a.com:80", ToString(source));
+    EXPECT_EQ("a.com:80", ToString(*source));
   }
   {
     auto source = network::mojom::CSPSource::New(
         "", "a.com", url::PORT_UNSPECIFIED, "", false, true);
-    EXPECT_EQ("a.com:*", ToString(source));
+    EXPECT_EQ("a.com:*", ToString(*source));
   }
   {
     auto source = network::mojom::CSPSource::New(
         "", "a.com", url::PORT_UNSPECIFIED, "/path", false, false);
-    EXPECT_EQ("a.com/path", ToString(source));
+    EXPECT_EQ("a.com/path", ToString(*source));
   }
 }
 
 TEST(CSPSourceTest, UpgradeRequests) {
-  CSPContext context;
   auto source =
       network::mojom::CSPSource::New("http", "a.com", 80, "", false, false);
-  EXPECT_TRUE(Allow(source, GURL("http://a.com:80"), &context, true));
-  EXPECT_FALSE(Allow(source, GURL("https://a.com:80"), &context, true));
-  EXPECT_FALSE(Allow(source, GURL("http://a.com:443"), &context, true));
-  EXPECT_TRUE(Allow(source, GURL("https://a.com:443"), &context, true));
-  EXPECT_TRUE(Allow(source, GURL("https://a.com"), &context, true));
+
+  // Self doesn't match anything.
+  auto self_source = network::mojom::CSPSource::New(
+      "", "", url::PORT_UNSPECIFIED, "", false, false);
+
+  EXPECT_TRUE(Allow(*source, GURL("http://a.com:80"), *self_source, true));
+  EXPECT_FALSE(Allow(*source, GURL("https://a.com:80"), *self_source, true));
+  EXPECT_FALSE(Allow(*source, GURL("http://a.com:443"), *self_source, true));
+  EXPECT_TRUE(Allow(*source, GURL("https://a.com:443"), *self_source, true));
+  EXPECT_TRUE(Allow(*source, GURL("https://a.com"), *self_source, true));
 }
 
 }  // namespace content
diff --git a/services/network/public/cpp/is_potentially_trustworthy_unittest.cc b/services/network/public/cpp/is_potentially_trustworthy_unittest.cc
index 7f00f0c..2d77ed7 100644
--- a/services/network/public/cpp/is_potentially_trustworthy_unittest.cc
+++ b/services/network/public/cpp/is_potentially_trustworthy_unittest.cc
@@ -21,7 +21,11 @@
   return IsOriginAllowlisted(url::Origin::Create(GURL(str)));
 }
 
-bool IsPotentiallyTrustworthy(const char* str) {
+bool IsOriginPotentiallyTrustworthy(const char* str) {
+  return IsOriginPotentiallyTrustworthy(url::Origin::Create(GURL(str)));
+}
+
+bool IsUrlPotentiallyTrustworthy(const char* str) {
   return IsUrlPotentiallyTrustworthy(GURL(str));
 }
 
@@ -32,7 +36,7 @@
       allowlist, rejected_patterns);
 }
 
-TEST(IsPotentiallyTrustworthy, MainTest) {
+TEST(IsPotentiallyTrustworthy, Origin) {
   const url::Origin unique_origin;
   EXPECT_FALSE(IsOriginPotentiallyTrustworthy(unique_origin));
   const url::Origin opaque_origin =
@@ -40,85 +44,95 @@
           .DeriveNewOpaqueOrigin();
   EXPECT_FALSE(IsOriginPotentiallyTrustworthy(opaque_origin));
 
-  EXPECT_TRUE(IsPotentiallyTrustworthy("about:blank"));
-  EXPECT_TRUE(IsPotentiallyTrustworthy("about:blank?x=2"));
-  EXPECT_TRUE(IsPotentiallyTrustworthy("about:blank#ref"));
-  EXPECT_TRUE(IsPotentiallyTrustworthy("about:blank?x=2#ref"));
+  EXPECT_FALSE(IsOriginPotentiallyTrustworthy("about:blank"));
+  EXPECT_FALSE(IsOriginPotentiallyTrustworthy("about:blank#ref"));
+  EXPECT_FALSE(IsOriginPotentiallyTrustworthy("about:srcdoc"));
+  EXPECT_FALSE(IsOriginPotentiallyTrustworthy("javascript:alert('blah')"));
+  EXPECT_FALSE(IsOriginPotentiallyTrustworthy("data:test/plain;blah"));
+}
 
-  EXPECT_TRUE(IsPotentiallyTrustworthy("about:srcdoc"));
-  EXPECT_TRUE(IsPotentiallyTrustworthy("about:srcdoc?x=2"));
-  EXPECT_TRUE(IsPotentiallyTrustworthy("about:srcdoc#ref"));
-  EXPECT_TRUE(IsPotentiallyTrustworthy("about:srcdoc?x=2#ref"));
+TEST(IsPotentiallyTrustworthy, Url) {
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy("about:blank"));
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy("about:blank?x=2"));
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy("about:blank#ref"));
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy("about:blank?x=2#ref"));
 
-  EXPECT_FALSE(IsPotentiallyTrustworthy("about:about"));
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy("about:srcdoc"));
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy("about:srcdoc?x=2"));
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy("about:srcdoc#ref"));
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy("about:srcdoc?x=2#ref"));
+
+  EXPECT_FALSE(IsUrlPotentiallyTrustworthy("about:about"));
 
   // TODO(https://crbug.com/1119740): Should return true for data: URLs.
-  EXPECT_FALSE(IsPotentiallyTrustworthy("data:test/plain;blah"));
-  EXPECT_FALSE(IsPotentiallyTrustworthy("javascript:alert('blah')"));
+  EXPECT_FALSE(IsUrlPotentiallyTrustworthy("data:test/plain;blah"));
+  EXPECT_FALSE(IsUrlPotentiallyTrustworthy("javascript:alert('blah')"));
 
-  EXPECT_TRUE(IsPotentiallyTrustworthy("file:///test/fun.html"));
-  EXPECT_TRUE(IsPotentiallyTrustworthy("file:///test/"));
-  EXPECT_TRUE(IsPotentiallyTrustworthy("file://localhost/test/"));
-  EXPECT_TRUE(IsPotentiallyTrustworthy("file://otherhost/test/"));
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy("file:///test/fun.html"));
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy("file:///test/"));
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy("file://localhost/test/"));
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy("file://otherhost/test/"));
 
-  EXPECT_TRUE(IsPotentiallyTrustworthy("https://example.com/fun.html"));
-  EXPECT_FALSE(IsPotentiallyTrustworthy("http://example.com/fun.html"));
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy("https://example.com/fun.html"));
+  EXPECT_FALSE(IsUrlPotentiallyTrustworthy("http://example.com/fun.html"));
 
-  EXPECT_TRUE(IsPotentiallyTrustworthy("wss://example.com/fun.html"));
-  EXPECT_FALSE(IsPotentiallyTrustworthy("ws://example.com/fun.html"));
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy("wss://example.com/fun.html"));
+  EXPECT_FALSE(IsUrlPotentiallyTrustworthy("ws://example.com/fun.html"));
 
-  EXPECT_TRUE(IsPotentiallyTrustworthy("http://localhost/fun.html"));
-  EXPECT_TRUE(IsPotentiallyTrustworthy("http://localhost./fun.html"));
-  EXPECT_TRUE(IsPotentiallyTrustworthy("http://pumpkin.localhost/fun.html"));
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy("http://localhost/fun.html"));
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy("http://localhost./fun.html"));
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy("http://pumpkin.localhost/fun.html"));
   EXPECT_TRUE(
-      IsPotentiallyTrustworthy("http://crumpet.pumpkin.localhost/fun.html"));
+      IsUrlPotentiallyTrustworthy("http://crumpet.pumpkin.localhost/fun.html"));
   EXPECT_TRUE(
-      IsPotentiallyTrustworthy("http://pumpkin.localhost:8080/fun.html"));
-  EXPECT_TRUE(IsPotentiallyTrustworthy(
+      IsUrlPotentiallyTrustworthy("http://pumpkin.localhost:8080/fun.html"));
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy(
       "http://crumpet.pumpkin.localhost:3000/fun.html"));
-  EXPECT_FALSE(IsPotentiallyTrustworthy("http://localhost.com/fun.html"));
-  EXPECT_TRUE(IsPotentiallyTrustworthy("https://localhost.com/fun.html"));
+  EXPECT_FALSE(IsUrlPotentiallyTrustworthy("http://localhost.com/fun.html"));
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy("https://localhost.com/fun.html"));
 
-  EXPECT_TRUE(IsPotentiallyTrustworthy("http://127.0.0.1/fun.html"));
-  EXPECT_TRUE(IsPotentiallyTrustworthy("ftp://127.0.0.1/fun.html"));
-  EXPECT_TRUE(IsPotentiallyTrustworthy("http://127.3.0.1/fun.html"));
-  EXPECT_FALSE(IsPotentiallyTrustworthy("http://127.example.com/fun.html"));
-  EXPECT_TRUE(IsPotentiallyTrustworthy("https://127.example.com/fun.html"));
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy("http://127.0.0.1/fun.html"));
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy("ftp://127.0.0.1/fun.html"));
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy("http://127.3.0.1/fun.html"));
+  EXPECT_FALSE(IsUrlPotentiallyTrustworthy("http://127.example.com/fun.html"));
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy("https://127.example.com/fun.html"));
 
-  EXPECT_TRUE(IsPotentiallyTrustworthy("http://[::1]/fun.html"));
-  EXPECT_FALSE(IsPotentiallyTrustworthy("http://[::2]/fun.html"));
-  EXPECT_FALSE(IsPotentiallyTrustworthy("http://[::1].example.com/fun.html"));
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy("http://[::1]/fun.html"));
+  EXPECT_FALSE(IsUrlPotentiallyTrustworthy("http://[::2]/fun.html"));
+  EXPECT_FALSE(
+      IsUrlPotentiallyTrustworthy("http://[::1].example.com/fun.html"));
 
   // IPv4 mapped IPv6 literals for loopback.
-  EXPECT_FALSE(IsPotentiallyTrustworthy("http://[::ffff:127.0.0.1]/"));
-  EXPECT_FALSE(IsPotentiallyTrustworthy("http://[::ffff:7f00:1]"));
+  EXPECT_FALSE(IsUrlPotentiallyTrustworthy("http://[::ffff:127.0.0.1]/"));
+  EXPECT_FALSE(IsUrlPotentiallyTrustworthy("http://[::ffff:7f00:1]"));
 
   // IPv4 compatible IPv6 literal for loopback.
-  EXPECT_FALSE(IsPotentiallyTrustworthy("http://[::127.0.0.1]"));
+  EXPECT_FALSE(IsUrlPotentiallyTrustworthy("http://[::127.0.0.1]"));
 
-  EXPECT_FALSE(IsPotentiallyTrustworthy("http://loopback"));
+  EXPECT_FALSE(IsUrlPotentiallyTrustworthy("http://loopback"));
 
   // TODO(https://crbug.com/1153337): Return false?
-  EXPECT_TRUE(IsPotentiallyTrustworthy("http://localhost6"));
-  EXPECT_TRUE(IsPotentiallyTrustworthy("ftp://localhost6.localdomain6"));
-  EXPECT_TRUE(IsPotentiallyTrustworthy("http://localhost.localdomain"));
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy("http://localhost6"));
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy("ftp://localhost6.localdomain6"));
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy("http://localhost.localdomain"));
 
-  EXPECT_FALSE(
-      IsPotentiallyTrustworthy("filesystem:http://www.example.com/temporary/"));
-  EXPECT_FALSE(
-      IsPotentiallyTrustworthy("filesystem:ftp://www.example.com/temporary/"));
+  EXPECT_FALSE(IsUrlPotentiallyTrustworthy(
+      "filesystem:http://www.example.com/temporary/"));
+  EXPECT_FALSE(IsUrlPotentiallyTrustworthy(
+      "filesystem:ftp://www.example.com/temporary/"));
   EXPECT_TRUE(
-      IsPotentiallyTrustworthy("filesystem:ftp://127.0.0.1/temporary/"));
-  EXPECT_TRUE(IsPotentiallyTrustworthy(
+      IsUrlPotentiallyTrustworthy("filesystem:ftp://127.0.0.1/temporary/"));
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy(
       "filesystem:https://www.example.com/temporary/"));
 
+  EXPECT_FALSE(IsUrlPotentiallyTrustworthy(
+      "blob:http://www.example.com/guid-goes-here"));
   EXPECT_FALSE(
-      IsPotentiallyTrustworthy("blob:http://www.example.com/guid-goes-here"));
-  EXPECT_FALSE(
-      IsPotentiallyTrustworthy("blob:ftp://www.example.com/guid-goes-here"));
-  EXPECT_TRUE(IsPotentiallyTrustworthy("blob:ftp://127.0.0.1/guid-goes-here"));
+      IsUrlPotentiallyTrustworthy("blob:ftp://www.example.com/guid-goes-here"));
   EXPECT_TRUE(
-      IsPotentiallyTrustworthy("blob:https://www.example.com/guid-goes-here"));
+      IsUrlPotentiallyTrustworthy("blob:ftp://127.0.0.1/guid-goes-here"));
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy(
+      "blob:https://www.example.com/guid-goes-here"));
 }
 
 class SecureOriginAllowlistTest : public testing::Test {
@@ -131,8 +145,8 @@
 TEST_F(SecureOriginAllowlistTest, UnsafelyTreatInsecureOriginAsSecure) {
   EXPECT_FALSE(IsOriginAllowlisted("http://example.com/a.html"));
   EXPECT_FALSE(IsOriginAllowlisted("http://127.example.com/a.html"));
-  EXPECT_FALSE(IsPotentiallyTrustworthy("http://example.com/a.html"));
-  EXPECT_FALSE(IsPotentiallyTrustworthy("http://127.example.com/a.html"));
+  EXPECT_FALSE(IsUrlPotentiallyTrustworthy("http://example.com/a.html"));
+  EXPECT_FALSE(IsUrlPotentiallyTrustworthy("http://127.example.com/a.html"));
 
   // Add http://example.com and http://127.example.com to allowlist by
   // command-line and see if they are now considered secure origins.
@@ -146,13 +160,13 @@
   // They should be now allow-listed.
   EXPECT_TRUE(IsOriginAllowlisted("http://example.com/a.html"));
   EXPECT_TRUE(IsOriginAllowlisted("http://127.example.com/a.html"));
-  EXPECT_TRUE(IsPotentiallyTrustworthy("http://example.com/a.html"));
-  EXPECT_TRUE(IsPotentiallyTrustworthy("http://127.example.com/a.html"));
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy("http://example.com/a.html"));
+  EXPECT_TRUE(IsUrlPotentiallyTrustworthy("http://127.example.com/a.html"));
 
   // Check that similarly named sites are not considered secure.
-  EXPECT_FALSE(IsPotentiallyTrustworthy("http://128.example.com/a.html"));
+  EXPECT_FALSE(IsUrlPotentiallyTrustworthy("http://128.example.com/a.html"));
   EXPECT_FALSE(
-      IsPotentiallyTrustworthy("http://foobar.127.example.com/a.html"));
+      IsUrlPotentiallyTrustworthy("http://foobar.127.example.com/a.html"));
 
   // When port is not specified, default port is assumed.
   EXPECT_TRUE(IsOriginAllowlisted("http://example.com:80/a.html"));
@@ -209,7 +223,8 @@
     GURL input_url(test.test_input);
     url::Origin input_origin = url::Origin::Create(input_url);
     EXPECT_EQ(test.expected_secure, IsOriginAllowlisted(input_origin));
-    EXPECT_EQ(test.expected_secure, IsPotentiallyTrustworthy(test.test_input));
+    EXPECT_EQ(test.expected_secure,
+              IsUrlPotentiallyTrustworthy(test.test_input));
   }
 }
 
diff --git a/services/network/public/mojom/content_security_policy.mojom b/services/network/public/mojom/content_security_policy.mojom
index 03e4c4c..c4cc0c8 100644
--- a/services/network/public/mojom/content_security_policy.mojom
+++ b/services/network/public/mojom/content_security_policy.mojom
@@ -148,6 +148,10 @@
 };
 
 struct ContentSecurityPolicy {
+  // The origin used for matching the 'self' keyword.
+  // https://w3c.github.io/webappsec-csp/#framework-policy
+  CSPSource self_origin;
+
   // The raw, unparsed values of the specified CSP directives. Needed for
   // reporting.
   map<CSPDirectiveName, string> raw_directives;
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 8499cb5..ae51d21 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -2714,9 +2714,6 @@
         "test_id_prefix": "ninja://ui/touch_selection:ui_touch_selection_unittests/"
       },
       {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.unit_tests.filter"
-        ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -4407,9 +4404,6 @@
         "test_id_prefix": "ninja://ui/touch_selection:ui_touch_selection_unittests/"
       },
       {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.unit_tests.filter"
-        ],
         "isolate_profile_data": true,
         "merge": {
           "args": [],
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 36b110a7..07227be4 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -8516,8 +8516,7 @@
       },
       {
         "args": [
-          "--test-launcher-print-test-stdio=always",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.unit_tests.filter"
+          "--test-launcher-print-test-stdio=always"
         ],
         "merge": {
           "args": [],
@@ -10482,8 +10481,7 @@
       },
       {
         "args": [
-          "--test-launcher-print-test-stdio=always",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.unit_tests.filter"
+          "--test-launcher-print-test-stdio=always"
         ],
         "merge": {
           "args": [],
diff --git a/testing/buildbot/filters/chromeos.unit_tests.filter b/testing/buildbot/filters/chromeos.unit_tests.filter
index fec4cb0..31510467 100644
--- a/testing/buildbot/filters/chromeos.unit_tests.filter
+++ b/testing/buildbot/filters/chromeos.unit_tests.filter
@@ -1,4 +1,2 @@
-# TODO(crbug.com/970790): Enable this.
--InputMethodManagerImplTest.SetLoginDefaultWithAllowedKeyboardLayouts
 # TODO(crbug.com/970806): Enable this.
 -KeyboardShortcutViewerMetadataTest.ModifyAcceleratorShouldUpdateMetadata
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index c649fc908..1ffce50b 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -2707,9 +2707,6 @@
         },
       },
       'Linux Chromium OS ASan LSan Tests (1)': {
-        'args': [
-          '--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.unit_tests.filter',
-        ],
         # These are slow on the ASAN trybot for some reason.
         # crbug.com/794372
         'swarming': {
@@ -2717,9 +2714,6 @@
         },
       },
       'Linux ChromiumOS MSan Tests': {
-        'args': [
-          '--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.unit_tests.filter',
-        ],
         # These are very slow on the Chrome OS MSAN trybot for some reason.
         # crbug.com/865455
         'swarming': {
@@ -2752,17 +2746,11 @@
         ],
       },
       'linux-chromeos-dbg': {
-        'args': [
-          '--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.unit_tests.filter',
-        ],
         'swarming': {
           'shards': 2,
         },
       },
       'linux-chromeos-rel': {
-        'args': [
-          '--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.unit_tests.filter',
-        ],
         'swarming': {
           'shards': 2,
         },
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 407c1f3d..8b2879e 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -4864,7 +4864,8 @@
                         "OmniboxMaxZeroSuggestMatches",
                         "OmniboxOnFocusSuggestionsContextualWebOnContent",
                         "OmniboxTrendingZeroPrefixSuggestionsOnNTP",
-                        "OmniboxUIExperimentMaxAutocompleteMatches"
+                        "OmniboxUIExperimentMaxAutocompleteMatches",
+                        "OmniboxZeroSuggestCaching"
                     ]
                 }
             ]
diff --git a/third_party/android_deps/fetch_all.py b/third_party/android_deps/fetch_all.py
index 1fdb6eb2..b5f0c77 100755
--- a/third_party/android_deps/fetch_all.py
+++ b/third_party/android_deps/fetch_all.py
@@ -540,9 +540,6 @@
         Copy(_CHROMIUM_SRC, list(copied_paths.keys()), build_dir,
              list(copied_paths.values()))
 
-        if debug:
-            gradle_cmd.append('--debug')
-
         if not args.ignore_vulnerabilities:
             report_dst = os.path.join(abs_android_deps_dir,
                                       'vulnerability_reports')
diff --git a/third_party/blink/public/mojom/web_feature/web_feature.mojom b/third_party/blink/public/mojom/web_feature/web_feature.mojom
index c86612d..082d0b5 100644
--- a/third_party/blink/public/mojom/web_feature/web_feature.mojom
+++ b/third_party/blink/public/mojom/web_feature/web_feature.mojom
@@ -3062,6 +3062,8 @@
   kCrossOriginJsonTypeForScript = 3738,
   kSameOriginStrictNosniffWouldBlock = 3739,
   kCrossOriginStrictNosniffWouldBlock = 3740,
+  kCSSSelectorPseudoDir = 3741,
+  kCrossOriginSubframeWithoutEmbeddingControl = 3742,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/public/platform/web_content_security_policy_struct.h b/third_party/blink/public/platform/web_content_security_policy_struct.h
index d4d20a59..e971bd6 100644
--- a/third_party/blink/public/platform/web_content_security_policy_struct.h
+++ b/third_party/blink/public/platform/web_content_security_policy_struct.h
@@ -91,6 +91,7 @@
 struct WebContentSecurityPolicy {
   network::mojom::ContentSecurityPolicyType disposition;
   network::mojom::ContentSecurityPolicySource source;
+  WebContentSecurityPolicySourceExpression self_origin;
   WebVector<WebContentSecurityPolicyRawDirective> raw_directives;
   WebVector<WebContentSecurityPolicyDirective> directives;
   bool upgrade_insecure_requests;
diff --git a/third_party/blink/public/web/web_navigation_params.h b/third_party/blink/public/web/web_navigation_params.h
index 92fc4cca..13a9508d 100644
--- a/third_party/blink/public/web/web_navigation_params.h
+++ b/third_party/blink/public/web/web_navigation_params.h
@@ -143,10 +143,6 @@
   // checks.
   WebVector<WebContentSecurityPolicy> initiator_csp;
 
-  // The navigation initiator source to be used when comparing an URL against
-  // 'self'.
-  WebContentSecurityPolicySourceExpression initiator_self_source;
-
   // The navigation initiator, if any.
   CrossVariantMojoRemote<mojom::NavigationInitiatorInterfaceBase>
       navigation_initiator_remote;
diff --git a/third_party/blink/renderer/bindings/core/v8/generated.gni b/third_party/blink/renderer/bindings/core/v8/generated.gni
index 3cffd6d..01938ee0 100644
--- a/third_party/blink/renderer/bindings/core/v8/generated.gni
+++ b/third_party/blink/renderer/bindings/core/v8/generated.gni
@@ -76,6 +76,8 @@
   "$bindings_core_v8_output_dir/node_or_string_or_trusted_script.h",
   "$bindings_core_v8_output_dir/radio_node_list_or_element.cc",
   "$bindings_core_v8_output_dir/radio_node_list_or_element.h",
+  "$bindings_core_v8_output_dir/readable_stream_default_controller_or_readable_byte_stream_controller.cc",
+  "$bindings_core_v8_output_dir/readable_stream_default_controller_or_readable_byte_stream_controller.h",
   "$bindings_core_v8_output_dir/readable_stream_default_reader_or_readable_stream_byob_reader.cc",
   "$bindings_core_v8_output_dir/readable_stream_default_reader_or_readable_stream_byob_reader.h",
   "$bindings_core_v8_output_dir/request_or_usv_string.cc",
diff --git a/third_party/blink/renderer/bindings/generated_in_core.gni b/third_party/blink/renderer/bindings/generated_in_core.gni
index 3053c0b..7c07269 100644
--- a/third_party/blink/renderer/bindings/generated_in_core.gni
+++ b/third_party/blink/renderer/bindings/generated_in_core.gni
@@ -57,6 +57,12 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_resize_observer_callback.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_scroll_state_callback.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_scroll_state_callback.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_underlying_source_cancel_callback.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_underlying_source_cancel_callback.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_underlying_source_pull_callback.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_underlying_source_pull_callback.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_underlying_source_start_callback.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_underlying_source_start_callback.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_void_function.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_void_function.h",
 ]
@@ -333,6 +339,8 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_ua_data_values.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_ui_event_init.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_ui_event_init.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_underlying_source.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_underlying_source.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_validity_state_flags.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_validity_state_flags.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_wheel_event_init.cc",
diff --git a/third_party/blink/renderer/bindings/idl_in_core.gni b/third_party/blink/renderer/bindings/idl_in_core.gni
index 91b90a0..394b33d 100644
--- a/third_party/blink/renderer/bindings/idl_in_core.gni
+++ b/third_party/blink/renderer/bindings/idl_in_core.gni
@@ -502,7 +502,11 @@
           "//third_party/blink/renderer/core/streams/transform_stream.idl",
           "//third_party/blink/renderer/core/streams/transform_stream_default_controller.idl",
           "//third_party/blink/renderer/core/streams/underlying_sink_base.idl",
+          "//third_party/blink/renderer/core/streams/underlying_source.idl",
           "//third_party/blink/renderer/core/streams/underlying_source_base.idl",
+          "//third_party/blink/renderer/core/streams/underlying_source_cancel_callback.idl",
+          "//third_party/blink/renderer/core/streams/underlying_source_pull_callback.idl",
+          "//third_party/blink/renderer/core/streams/underlying_source_start_callback.idl",
           "//third_party/blink/renderer/core/streams/writable_stream.idl",
           "//third_party/blink/renderer/core/streams/writable_stream_default_controller.idl",
           "//third_party/blink/renderer/core/streams/writable_stream_default_writer.idl",
diff --git a/third_party/blink/renderer/core/OWNERS b/third_party/blink/renderer/core/OWNERS
index b3dab08..ef6c5dd 100644
--- a/third_party/blink/renderer/core/OWNERS
+++ b/third_party/blink/renderer/core/OWNERS
@@ -25,6 +25,7 @@
 fs@opera.com
 fserb@chromium.org
 futhark@chromium.org
+fwang@igalia.com
 haraken@chromium.org
 hayato@chromium.org
 hiroshige@chromium.org
diff --git a/third_party/blink/renderer/core/core_idl_files.gni b/third_party/blink/renderer/core/core_idl_files.gni
index ff73bfb..5210c5af 100644
--- a/third_party/blink/renderer/core/core_idl_files.gni
+++ b/third_party/blink/renderer/core/core_idl_files.gni
@@ -617,6 +617,9 @@
                     "dom/function_string_callback.idl",
                     "dom/idle_request_callback.idl",
                     "dom/void_function.idl",
+                    "streams/underlying_source_cancel_callback.idl",
+                    "streams/underlying_source_pull_callback.idl",
+                    "streams/underlying_source_start_callback.idl",
                   ],
                   "abspath")
 
@@ -749,6 +752,7 @@
                     "streams/readable_stream_get_reader_options.idl",
                     "streams/readable_writable_pair.idl",
                     "streams/stream_pipe_options.idl",
+                    "streams/underlying_source.idl",
                     "streams/queuing_strategy_init.idl",
                     "timing/measure_memory/memory_measurement.idl",
                     "timing/measure_memory/memory_breakdown_entry.idl",
diff --git a/third_party/blink/renderer/core/css/css_selector.cc b/third_party/blink/renderer/core/css/css_selector.cc
index eae5a8d1..2fe23d0 100644
--- a/third_party/blink/renderer/core/css/css_selector.cc
+++ b/third_party/blink/renderer/core/css/css_selector.cc
@@ -289,6 +289,7 @@
     case kPseudoIndeterminate:
     case kPseudoTarget:
     case kPseudoLang:
+    case kPseudoDir:
     case kPseudoNot:
     case kPseudoRoot:
     case kPseudoScope:
@@ -456,6 +457,7 @@
 const static NameToPseudoStruct kPseudoTypeWithArgumentsMap[] = {
     {"-webkit-any", CSSSelector::kPseudoAny},
     {"cue", CSSSelector::kPseudoCue},
+    {"dir", CSSSelector::kPseudoDir},
     {"host", CSSSelector::kPseudoHost},
     {"host-context", CSSSelector::kPseudoHostContext},
     {"is", CSSSelector::kPseudoIs},
@@ -501,6 +503,10 @@
   if (match == pseudo_type_map_end || match->string != name.GetString())
     return CSSSelector::kPseudoUnknown;
 
+  if (match->type == CSSSelector::kPseudoDir &&
+      !RuntimeEnabledFeatures::CSSPseudoDirEnabled())
+    return CSSSelector::kPseudoUnknown;
+
   if (match->type == CSSSelector::kPseudoFocusVisible &&
       !RuntimeEnabledFeatures::CSSFocusVisibleEnabled())
     return CSSSelector::kPseudoUnknown;
@@ -667,6 +673,7 @@
     case kPseudoDefault:
     case kPseudoDefined:
     case kPseudoDisabled:
+    case kPseudoDir:
     case kPseudoDoubleButton:
     case kPseudoDrag:
     case kPseudoEmpty:
@@ -836,6 +843,7 @@
           builder.Append(')');
           break;
         }
+        case kPseudoDir:
         case kPseudoLang:
         case kPseudoState:
           builder.Append('(');
diff --git a/third_party/blink/renderer/core/css/css_selector.h b/third_party/blink/renderer/core/css/css_selector.h
index f92f728b..7333575b 100644
--- a/third_party/blink/renderer/core/css/css_selector.h
+++ b/third_party/blink/renderer/core/css/css_selector.h
@@ -272,6 +272,7 @@
     kPseudoVideoPersistent,
     kPseudoVideoPersistentAncestor,
     kPseudoTargetText,
+    kPseudoDir,
   };
 
   enum class AttributeMatchType {
diff --git a/third_party/blink/renderer/core/css/parser/css_selector_parser.cc b/third_party/blink/renderer/core/css/parser/css_selector_parser.cc
index c6e016e..37e92d0 100644
--- a/third_party/blink/renderer/core/css/parser/css_selector_parser.cc
+++ b/third_party/blink/renderer/core/css/parser/css_selector_parser.cc
@@ -762,6 +762,7 @@
       selector->SetSelectorList(std::move(selector_list));
       return selector;
     }
+    case CSSSelector::kPseudoDir:
     case CSSSelector::kPseudoState: {
       const CSSParserToken& ident = block.ConsumeIncludingWhitespace();
       if (ident.GetType() != kIdentToken || !block.AtEnd())
@@ -1323,6 +1324,10 @@
         case CSSSelector::kPseudoReadWrite:
           feature = WebFeature::kCSSSelectorPseudoReadWrite;
           break;
+        case CSSSelector::kPseudoDir:
+          DCHECK(RuntimeEnabledFeatures::CSSPseudoDirEnabled());
+          feature = WebFeature::kCSSSelectorPseudoDir;
+          break;
         default:
           break;
       }
diff --git a/third_party/blink/renderer/core/css/rule_feature_set.cc b/third_party/blink/renderer/core/css/rule_feature_set.cc
index aa23290..c7dad52 100644
--- a/third_party/blink/renderer/core/css/rule_feature_set.cc
+++ b/third_party/blink/renderer/core/css/rule_feature_set.cc
@@ -128,6 +128,7 @@
     case CSSSelector::kPseudoModal:
     case CSSSelector::kPseudoBackdrop:
     case CSSSelector::kPseudoLang:
+    case CSSSelector::kPseudoDir:
     case CSSSelector::kPseudoNot:
     case CSSSelector::kPseudoPlaceholder:
     case CSSSelector::kPseudoResizer:
@@ -595,6 +596,7 @@
       case CSSSelector::kPseudoIndeterminate:
       case CSSSelector::kPseudoTarget:
       case CSSSelector::kPseudoLang:
+      case CSSSelector::kPseudoDir:
       case CSSSelector::kPseudoFullScreen:
       case CSSSelector::kPseudoFullScreenAncestor:
       case CSSSelector::kPseudoFullscreen:
diff --git a/third_party/blink/renderer/core/css/selector_checker.cc b/third_party/blink/renderer/core/css/selector_checker.cc
index a63926d..6b48bbf 100644
--- a/third_party/blink/renderer/core/css/selector_checker.cc
+++ b/third_party/blink/renderer/core/css/selector_checker.cc
@@ -1070,6 +1070,24 @@
         break;
       return true;
     }
+    case CSSSelector::kPseudoDir: {
+      const AtomicString& argument = selector.Argument();
+      if (argument.IsEmpty())
+        break;
+
+      TextDirection direction;
+      if (EqualIgnoringASCIICase(argument, "ltr"))
+        direction = TextDirection::kLtr;
+      else if (EqualIgnoringASCIICase(argument, "rtl"))
+        direction = TextDirection::kRtl;
+      else
+        break;
+
+      if (auto* html_element = DynamicTo<HTMLElement>(element)) {
+        return html_element->ComputeInheritedDirectionality() == direction;
+      }
+      break;
+    }
     case CSSSelector::kPseudoFullscreen:
     // fall through
     case CSSSelector::kPseudoFullScreen:
diff --git a/third_party/blink/renderer/core/css/style_engine.cc b/third_party/blink/renderer/core/css/style_engine.cc
index cd498e84..04e9904 100644
--- a/third_party/blink/renderer/core/css/style_engine.cc
+++ b/third_party/blink/renderer/core/css/style_engine.cc
@@ -1965,13 +1965,36 @@
   return initial_data_;
 }
 
-void StyleEngine::RecalcStyle() {
+void StyleEngine::UpdateStyleAndLayoutTreeForContainer(Element& container) {
+  DCHECK(!style_recalc_root_.GetRootNode());
+  DCHECK(!container.NeedsStyleRecalc());
+  DCHECK(!in_container_query_style_recalc_);
+
+  base::AutoReset<bool> cq_recalc(&in_container_query_style_recalc_, true);
+
+  style_recalc_root_.Update(nullptr, &container);
+  RecalcStyle({StyleRecalcChange::kRecalcContainerQueryDependent});
+
+  if (container.ChildNeedsReattachLayoutTree()) {
+    DCHECK(layout_tree_rebuild_root_.GetRootNode());
+    if (layout_tree_rebuild_root_.GetRootNode()->IsDocumentNode()) {
+      // Avoid traversing from outside the container root. We know none of the
+      // elements outside the subtree should be marked dirty in this pass, but
+      // we may have fallen back to the document root.
+      layout_tree_rebuild_root_.Clear();
+      layout_tree_rebuild_root_.Update(nullptr, &container);
+    }
+    RebuildLayoutTree();
+  }
+}
+
+void StyleEngine::RecalcStyle(StyleRecalcChange change) {
   DCHECK(GetDocument().documentElement());
   Element* root_element = &style_recalc_root_.RootElement();
   Element* parent = root_element->ParentOrShadowHostElement();
 
   SelectorFilterRootScope filter_scope(parent);
-  root_element->RecalcStyle({});
+  root_element->RecalcStyle(change);
 
   for (ContainerNode* ancestor = root_element->GetStyleRecalcParent(); ancestor;
        ancestor = ancestor->GetStyleRecalcParent()) {
@@ -2003,7 +2026,7 @@
 void StyleEngine::RebuildLayoutTree() {
   DCHECK(GetDocument().documentElement());
   DCHECK(!InRebuildLayoutTree());
-  in_layout_tree_rebuild_ = true;
+  base::AutoReset<bool> rebuild_scope(&in_layout_tree_rebuild_, true);
 
   // We need a root scope here in case we recalc style for ::first-letter
   // elements as part of UpdateFirstLetterPseudoElement.
@@ -2023,7 +2046,6 @@
     ancestor->ClearChildNeedsReattachLayoutTree();
   }
   layout_tree_rebuild_root_.Clear();
-  in_layout_tree_rebuild_ = false;
 }
 
 void StyleEngine::UpdateStyleAndLayoutTree() {
@@ -2108,7 +2130,7 @@
     DCHECK(allow_mark_style_dirty_from_recalc_);
     return;
   }
-  DCHECK(!in_layout_tree_rebuild_);
+  DCHECK(!InRebuildLayoutTree());
   if (in_dom_removal_) {
     ancestor = nullptr;
     dirty_node = document_;
diff --git a/third_party/blink/renderer/core/css/style_engine.h b/third_party/blink/renderer/core/css/style_engine.h
index be5762e..58d8d8e7 100644
--- a/third_party/blink/renderer/core/css/style_engine.h
+++ b/third_party/blink/renderer/core/css/style_engine.h
@@ -398,10 +398,16 @@
   void UpdateViewport();
   void UpdateViewportStyle();
   void UpdateStyleAndLayoutTree();
-  void RecalcStyle();
+  // To be called from layout when container queries change for the container.
+  void UpdateStyleAndLayoutTreeForContainer(Element& container);
+  void RecalcStyle() { RecalcStyle({}); }
+
   void ClearEnsuredDescendantStyles(Element& element);
   void RebuildLayoutTree();
   bool InRebuildLayoutTree() const { return in_layout_tree_rebuild_; }
+  bool InContainerQueryStyleRecalc() const {
+    return in_container_query_style_recalc_;
+  }
 
   void SetColorSchemeFromMeta(const CSSValue* color_scheme);
   const CSSValue* GetMetaColorSchemeValue() const { return meta_color_scheme_; }
@@ -531,6 +537,8 @@
   void ViewportDefiningElementDidChange();
   void PropagateWritingModeAndDirectionToHTMLRoot();
 
+  void RecalcStyle(StyleRecalcChange);
+
   Member<Document> document_;
 
   // True if this StyleEngine is for an HTML Import document.
@@ -582,6 +590,7 @@
 
   bool uses_rem_units_{false};
   bool in_layout_tree_rebuild_{false};
+  bool in_container_query_style_recalc_{false};
   bool in_dom_removal_{false};
   bool viewport_style_dirty_{false};
   bool fonts_need_update_{false};
diff --git a/third_party/blink/renderer/core/css/style_engine_test.cc b/third_party/blink/renderer/core/css/style_engine_test.cc
index f410045f..3242875 100644
--- a/third_party/blink/renderer/core/css/style_engine_test.cc
+++ b/third_party/blink/renderer/core/css/style_engine_test.cc
@@ -3764,4 +3764,67 @@
   ClearUseCounter(WebFeature::kCSSPseudoHostDynamicSpecificity);
 }
 
+namespace {
+
+void SetDependsOnContainerQueries(HTMLCollection& affected) {
+  for (Element* element : affected) {
+    if (const ComputedStyle* style = element->GetComputedStyle()) {
+      scoped_refptr<ComputedStyle> cloned_style = ComputedStyle::Clone(*style);
+      cloned_style->SetDependsOnContainerQueries(true);
+      element->SetComputedStyle(cloned_style);
+    }
+  }
+}
+
+}  // namespace
+
+TEST_F(StyleEngineTest, UpdateStyleAndLayoutTreeForContainer) {
+  GetDocument().body()->setInnerHTML(R"HTML(
+    <div id="container1" style="contain:layout">
+      <span class="affected"></span>
+      <div id="container2" style="contain:layout" class="affected">
+        <span class="affected"></span>
+        <span></span>
+        <span class="affected"></span>
+        <span></span>
+        <span class="affected"></span>
+        <div style="display:none" class="affected">
+          <span class="affected"></span>
+        </div>
+        <div style="display:none">
+          <span class="affected"></span>
+          <span class="affected"></span>
+        </div>
+      </div>
+      <span></span>
+      <div id="container3" style="contain:layout">
+        <span class="affected"></span>
+        <span class="affected"></span>
+      </div>
+    </div>
+  )HTML");
+
+  UpdateAllLifecyclePhases();
+
+  auto* container1 = GetDocument().getElementById("container1");
+  auto* container2 = GetDocument().getElementById("container2");
+  auto* affected = GetDocument().getElementsByClassName("affected");
+  ASSERT_TRUE(container1);
+  ASSERT_TRUE(container2);
+  ASSERT_TRUE(affected);
+  SetDependsOnContainerQueries(*affected);
+
+  unsigned start_count = GetStyleEngine().StyleForElementCount();
+  GetStyleEngine().UpdateStyleAndLayoutTreeForContainer(*container1);
+
+  // The first span.affected child and #container2
+  EXPECT_EQ(2u, GetStyleEngine().StyleForElementCount() - start_count);
+
+  start_count = GetStyleEngine().StyleForElementCount();
+  GetStyleEngine().UpdateStyleAndLayoutTreeForContainer(*container2);
+
+  // Three direct span.affected children, and the two display:none elements.
+  EXPECT_EQ(5u, GetStyleEngine().StyleForElementCount() - start_count);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/style_recalc.cc b/third_party/blink/renderer/core/css/style_recalc.cc
index 757a6a7..1c6a42c 100644
--- a/third_party/blink/renderer/core/css/style_recalc.cc
+++ b/third_party/blink/renderer/core/css/style_recalc.cc
@@ -9,12 +9,13 @@
 
 namespace blink {
 
-bool StyleRecalcChange::TraverseChildren(const Node& node) const {
-  return RecalcChildren() || node.ChildNeedsStyleRecalc();
+bool StyleRecalcChange::TraverseChildren(const Element& element) const {
+  return RecalcChildren() || RecalcContainerQueryDependent() ||
+         element.ChildNeedsStyleRecalc();
 }
 
-bool StyleRecalcChange::TraversePseudoElements(const Node& node) const {
-  return UpdatePseudoElements() || node.ChildNeedsStyleRecalc();
+bool StyleRecalcChange::TraversePseudoElements(const Element& element) const {
+  return UpdatePseudoElements() || element.ChildNeedsStyleRecalc();
 }
 
 bool StyleRecalcChange::TraverseChild(const Node& node) const {
@@ -28,11 +29,19 @@
     return true;
   if (node.GetForceReattachLayoutTree())
     return true;
-  if (propagate_ != kClearEnsured)
+  // Early exit before getting the computed style.
+  if (propagate_ != kClearEnsured && !RecalcContainerQueryDependent())
     return false;
-  if (const ComputedStyle* old_style = node.GetComputedStyle())
-    return old_style->IsEnsuredInDisplayNone();
-  return false;
+  if (const ComputedStyle* old_style = node.GetComputedStyle()) {
+    return (propagate_ == kClearEnsured &&
+            old_style->IsEnsuredInDisplayNone()) ||
+           (RecalcContainerQueryDependent() &&
+            old_style->DependsOnContainerQueries());
+  }
+  // Container queries may affect display:none elements, and we since we store
+  // that dependency on ComputedStyle we need to recalc style for display:none
+  // subtree roots.
+  return RecalcContainerQueryDependent();
 }
 
 bool StyleRecalcChange::ShouldUpdatePseudoElement(
@@ -40,4 +49,19 @@
   return UpdatePseudoElements() || pseudo_element.NeedsStyleRecalc();
 }
 
+bool StyleRecalcChange::RecalcContainerQueryDependentChildren(
+    const Element& element) const {
+  // We are at the container root for a container query recalc.
+  if (propagate_ == kRecalcContainerQueryDependent)
+    return true;
+  if (!RecalcContainerQueryDependent())
+    return false;
+  // Don't traverse into children if we hit a descendant container while
+  // recalculating container queries. If the queries for this container also
+  // changes, we will enter another container query recalc for this subtree from
+  // layout.
+  const ComputedStyle* style = element.GetComputedStyle();
+  return style && !style->IsContainerForContainerQueries();
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/style_recalc.h b/third_party/blink/renderer/core/css/style_recalc.h
index 6fb3c21..3b014d1 100644
--- a/third_party/blink/renderer/core/css/style_recalc.h
+++ b/third_party/blink/renderer/core/css/style_recalc.h
@@ -7,6 +7,7 @@
 
 namespace blink {
 
+class Element;
 class Node;
 class PseudoElement;
 
@@ -21,6 +22,11 @@
     // Need to traverse children in display:none or non-slotted/distributed
     // children of shadow hosts to clear ensured computed styles.
     kClearEnsured,
+    // Need to traverse descendants to invalidate style for container queries.
+    // This value is passed in for the container itself, it will translate into
+    // recalc_container_query_dependent_=true for descendants. We should not
+    // recalc style for the container itself.
+    kRecalcContainerQueryDependent,
     // Need to update existence and style for pseudo elements.
     kUpdatePseudoElements,
     // Need to recalculate style for children for inheritance. All changed
@@ -37,24 +43,25 @@
   StyleRecalcChange(const StyleRecalcChange&) = default;
   StyleRecalcChange(Propagate propagate) : propagate_(propagate) {}
 
-  StyleRecalcChange ForChildren() const {
-    return {RecalcDescendants() ? kRecalcDescendants : kNo, reattach_};
+  StyleRecalcChange ForChildren(const Element& element) const {
+    return {RecalcDescendants() ? kRecalcDescendants : kNo, reattach_,
+            RecalcContainerQueryDependentChildren(element)};
   }
   StyleRecalcChange ForPseudoElement() const {
     if (propagate_ == kUpdatePseudoElements)
-      return {kRecalcChildren, reattach_};
+      return {kRecalcChildren, reattach_, recalc_container_query_dependent_};
     return *this;
   }
   StyleRecalcChange EnsureAtLeast(Propagate propagate) const {
     if (propagate > propagate_)
-      return {propagate, reattach_};
-    return {propagate_, reattach_};
+      return {propagate, reattach_, recalc_container_query_dependent_};
+    return {propagate_, reattach_, recalc_container_query_dependent_};
   }
   StyleRecalcChange ForceRecalcDescendants() const {
-    return {kRecalcDescendants, reattach_};
+    return {kRecalcDescendants, reattach_, recalc_container_query_dependent_};
   }
   StyleRecalcChange ForceReattachLayoutTree() const {
-    return {propagate_, true};
+    return {propagate_, true, recalc_container_query_dependent_};
   }
 
   bool ReattachLayoutTree() const { return reattach_; }
@@ -62,20 +69,31 @@
   bool RecalcDescendants() const { return propagate_ == kRecalcDescendants; }
   bool UpdatePseudoElements() const { return propagate_ != kNo; }
   bool IndependentInherit() const { return propagate_ == kIndependentInherit; }
-  bool TraverseChildren(const Node&) const;
+  bool TraverseChildren(const Element&) const;
   bool TraverseChild(const Node&) const;
-  bool TraversePseudoElements(const Node&) const;
+  bool TraversePseudoElements(const Element&) const;
   bool ShouldRecalcStyleFor(const Node&) const;
   bool ShouldUpdatePseudoElement(const PseudoElement&) const;
 
  private:
-  StyleRecalcChange(Propagate propagate, bool reattach)
-      : propagate_(propagate), reattach_(reattach) {}
+  StyleRecalcChange(Propagate propagate,
+                    bool reattach,
+                    bool recalc_container_query_dependent)
+      : propagate_(propagate),
+        reattach_(reattach),
+        recalc_container_query_dependent_(recalc_container_query_dependent) {}
+
+  bool RecalcContainerQueryDependent() const {
+    return recalc_container_query_dependent_;
+  }
+  bool RecalcContainerQueryDependentChildren(const Element&) const;
 
   // To what extent do we need to update style for children.
   Propagate propagate_ = kNo;
   // Need to reattach layout tree if true.
   bool reattach_ = false;
+  // Force recalc of elements depending on container queries.
+  bool recalc_container_query_dependent_ = false;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index ffa8263..5681b9e 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -2086,6 +2086,8 @@
   // recalc.
   if (lifecycle_.GetState() == DocumentLifecycle::kInPreLayout)
     return false;
+  if (lifecycle_.GetState() == DocumentLifecycle::kInPerformLayout)
+    return false;
   if (!ShouldScheduleLayout())
     return false;
   return true;
@@ -8546,6 +8548,11 @@
   return find_in_page_active_match_node_;
 }
 
+bool Document::InStyleRecalc() const {
+  return lifecycle_.GetState() == DocumentLifecycle::kInStyleRecalc ||
+         style_engine_->InContainerQueryStyleRecalc();
+}
+
 template class CORE_TEMPLATE_EXPORT Supplement<Document>;
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index d74249f..815f14c 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -1345,9 +1345,7 @@
   void DidLoadAllPendingParserBlockingStylesheets();
   void DidRemoveAllPendingStylesheets();
 
-  bool InStyleRecalc() const {
-    return lifecycle_.GetState() == DocumentLifecycle::kInStyleRecalc;
-  }
+  bool InStyleRecalc() const;
 
   // Return a Locale for the default locale if the argument is null or empty.
   Locale& GetCachedLocale(const AtomicString& locale = g_null_atom);
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 16c47ad..5ffe395 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -2880,7 +2880,7 @@
   if (HasCustomStyleCallbacks())
     WillRecalcStyle(change);
 
-  StyleRecalcChange child_change = change.ForChildren();
+  StyleRecalcChange child_change = change.ForChildren(*this);
   if (change.ShouldRecalcStyleFor(*this)) {
     child_change = RecalcOwnStyle(change);
     if (GetStyleChangeType() == kSubtreeStyleChange)
@@ -3029,7 +3029,7 @@
   scoped_refptr<ComputedStyle> new_style;
   scoped_refptr<const ComputedStyle> old_style = GetComputedStyle();
 
-  StyleRecalcChange child_change = change.ForChildren();
+  StyleRecalcChange child_change = change.ForChildren(*this);
 
   if (ParentComputedStyle()) {
     if (old_style && change.IndependentInherit()) {
@@ -4960,6 +4960,32 @@
   return style.Display() == EDisplay::kContents;
 }
 
+bool Element::ComputeInheritedDirPseudoClass(TextDirection direction) const {
+  const Node* n = this;
+  // The dir property is inherited, so we iterate over the parents to find
+  // the first dir attribute.
+  do {
+    if (auto* element_node = DynamicTo<Element>(n)) {
+      AtomicString dir_attribute_value =
+          element_node->FastGetAttribute(html_names::kDirAttr);
+      if ((IsA<HTMLBDIElement>(*element_node) && !dir_attribute_value) ||
+          (IsHTMLElement() &&
+           EqualIgnoringASCIICase(dir_attribute_value, "auto"))) {
+        return element_node->MatchesDirPseudoClassForDirAutoAttribute(
+            direction);
+      }
+
+      if (EqualIgnoringASCIICase(dir_attribute_value, "ltr"))
+        return IsLtr(direction);
+      else if (EqualIgnoringASCIICase(dir_attribute_value, "rtl"))
+        return IsRtl(direction);
+    }
+    n = n->ParentOrShadowHostNode();
+  } while (n);
+
+  return IsLtr(direction);
+}
+
 AtomicString Element::ComputeInheritedLanguage() const {
   const Node* n = this;
   AtomicString value;
diff --git a/third_party/blink/renderer/core/dom/element.h b/third_party/blink/renderer/core/dom/element.h
index 528fcab..f1a350b 100644
--- a/third_party/blink/renderer/core/dom/element.h
+++ b/third_party/blink/renderer/core/dom/element.h
@@ -40,6 +40,7 @@
 #include "third_party/blink/renderer/core/html_names.h"
 #include "third_party/blink/renderer/core/trustedtypes/trusted_types_util.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/text/text_direction.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string_table.h"
@@ -609,6 +610,12 @@
     return GetV0CustomElementState() == kV0WaitingForUpgrade;
   }
 
+  bool ComputeInheritedDirPseudoClass(TextDirection direction) const;
+  virtual bool MatchesDirPseudoClassForDirAutoAttribute(
+      TextDirection direction) const {
+    return false;
+  }
+
   AtomicString ComputeInheritedLanguage() const;
   Locale& GetLocale() const;
 
diff --git a/third_party/blink/renderer/core/fetch/fetch_response_data_test.cc b/third_party/blink/renderer/core/fetch/fetch_response_data_test.cc
index ac21aee..a8c0df80 100644
--- a/third_party/blink/renderer/core/fetch/fetch_response_data_test.cc
+++ b/third_party/blink/renderer/core/fetch/fetch_response_data_test.cc
@@ -274,7 +274,8 @@
                                           "frame-ancestors 'none'");
 
   mojom::blink::FetchAPIResponsePtr fetch_api_response =
-      internal_response->PopulateFetchAPIResponse(KURL());
+      internal_response->PopulateFetchAPIResponse(
+          KURL("https://www.example.org"));
   auto& csp = fetch_api_response->parsed_headers->content_security_policy;
 
   EXPECT_EQ(csp.size(), 2U);
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 c45df56..edc386b 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
@@ -1431,6 +1431,10 @@
 
   auto policy = network::mojom::blink::ContentSecurityPolicy::New();
 
+  policy->self_origin =
+      policy_->GetSelfSource()
+          ? policy_->GetSelfSource()->ExposeForNavigationalChecks()
+          : nullptr;
   policy->use_reporting_api = use_reporting_api_;
   policy->report_endpoints = report_endpoints_;
   policy->header = network::mojom::blink::ContentSecurityPolicyHeader::New(
diff --git a/third_party/blink/renderer/core/frame/local_frame_client.h b/third_party/blink/renderer/core/frame/local_frame_client.h
index 40cb1dab2..f84f726 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client.h
+++ b/third_party/blink/renderer/core/frame/local_frame_client.h
@@ -167,7 +167,6 @@
       const base::Optional<WebImpression>& impression,
       WTF::Vector<network::mojom::blink::ContentSecurityPolicyPtr>
           initiator_csp,
-      network::mojom::blink::CSPSourcePtr initiator_self_source,
       network::mojom::IPAddressSpace,
       mojo::PendingRemote<mojom::blink::NavigationInitiator>) = 0;
 
diff --git a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
index 2541f527..c7caa0e 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
@@ -287,6 +287,7 @@
 
   return {policy->header->type,
           policy->header->source,
+          ConvertToPublic(std::move(policy->self_origin)),
           std::move(raw_directives),
           std::move(directives),
           policy->upgrade_insecure_requests,
@@ -627,7 +628,6 @@
     const String& href_translate,
     const base::Optional<WebImpression>& impression,
     WTF::Vector<network::mojom::blink::ContentSecurityPolicyPtr> initiator_csp,
-    network::mojom::blink::CSPSourcePtr initiator_self_source,
     network::mojom::IPAddressSpace initiator_address_space,
     mojo::PendingRemote<mojom::blink::NavigationInitiator>
         navigation_initiator) {
@@ -657,10 +657,6 @@
     navigation_info->initiator_csp.emplace_back(
         ConvertToPublic(std::move(csp_policy)));
   }
-  if (initiator_self_source) {
-    navigation_info->initiator_self_source =
-        ConvertToPublic(std::move(initiator_self_source));
-  }
   navigation_info->initiator_address_space = initiator_address_space;
   navigation_info->navigation_initiator_remote =
       std::move(navigation_initiator);
diff --git a/third_party/blink/renderer/core/frame/local_frame_client_impl.h b/third_party/blink/renderer/core/frame/local_frame_client_impl.h
index 02f98349..cb737778 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client_impl.h
+++ b/third_party/blink/renderer/core/frame/local_frame_client_impl.h
@@ -125,7 +125,6 @@
       const base::Optional<WebImpression>& impression,
       WTF::Vector<network::mojom::blink::ContentSecurityPolicyPtr>
           initiator_csp,
-      network::mojom::blink::CSPSourcePtr initiator_self_source,
       network::mojom::IPAddressSpace,
       mojo::PendingRemote<mojom::blink::NavigationInitiator>) override;
   void DispatchWillSendSubmitEvent(HTMLFormElement*) override;
diff --git a/third_party/blink/renderer/core/frame/use_counter_helper_test.cc b/third_party/blink/renderer/core/frame/use_counter_helper_test.cc
index 7a3f3c5..4604d2c 100644
--- a/third_party/blink/renderer/core/frame/use_counter_helper_test.cc
+++ b/third_party/blink/renderer/core/frame/use_counter_helper_test.cc
@@ -179,6 +179,17 @@
   EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSSelectorPseudoWhere));
 }
 
+TEST_F(UseCounterHelperTest, CSSSelectorPseudoDir) {
+  auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
+  Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
+  Document& document = dummy_page_holder->GetDocument();
+  WebFeature feature = WebFeature::kCSSSelectorPseudoDir;
+  EXPECT_FALSE(document.IsUseCounted(feature));
+  document.documentElement()->setInnerHTML(
+      "<style>:dir(ltr) { color: red; }</style>");
+  EXPECT_TRUE(document.IsUseCounted(feature));
+}
+
 TEST_F(UseCounterHelperTest, CSSGridLayoutPercentageColumnIndefiniteWidth) {
   auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
   Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
diff --git a/third_party/blink/renderer/core/html/html_element.cc b/third_party/blink/renderer/core/html/html_element.cc
index 47525bc..02a4c47 100644
--- a/third_party/blink/renderer/core/html/html_element.cc
+++ b/third_party/blink/renderer/core/html/html_element.cc
@@ -1216,13 +1216,31 @@
   }
 }
 
-void HTMLElement::CalculateAndAdjustDirectionality() {
+bool HTMLElement::CalculateAndAdjustDirectionality() {
   TextDirection text_direction = Directionality();
   const ComputedStyle* style = GetComputedStyle();
   if (style && style->Direction() != text_direction) {
     SetNeedsStyleRecalc(kLocalStyleChange,
                         StyleChangeReasonForTracing::Create(
                             style_change_reason::kWritingModeChange));
+    return true;
+  }
+  return false;
+}
+
+TextDirection HTMLElement::ComputeInheritedDirectionality() const {
+  const AtomicString& direction = FastGetAttribute(html_names::kDirAttr);
+  if (HasDirectionAuto()) {
+    return Directionality();
+  } else if (EqualIgnoringASCIICase(direction, "ltr")) {
+    return TextDirection::kLtr;
+  } else if (EqualIgnoringASCIICase(direction, "rtl")) {
+    return TextDirection::kRtl;
+  } else {
+    auto* parent =
+        DynamicTo<HTMLElement>(FlatTreeTraversal::ParentElement(*this));
+    return parent ? parent->ComputeInheritedDirectionality()
+                  : TextDirection::kLtr;
   }
 }
 
@@ -1237,7 +1255,13 @@
        element_to_adjust =
            FlatTreeTraversal::ParentElement(*element_to_adjust)) {
     if (ElementAffectsDirectionality(element_to_adjust)) {
-      To<HTMLElement>(element_to_adjust)->CalculateAndAdjustDirectionality();
+      if (To<HTMLElement>(element_to_adjust)
+              ->CalculateAndAdjustDirectionality() &&
+          RuntimeEnabledFeatures::CSSPseudoDirEnabled()) {
+        SetNeedsStyleRecalc(kLocalStyleChange,
+                            StyleChangeReasonForTracing::Create(
+                                style_change_reason::kPseudoClass));
+      }
       return;
     }
   }
@@ -1583,6 +1607,13 @@
 
   if (EqualIgnoringASCIICase(params.new_value, "auto"))
     CalculateAndAdjustDirectionality();
+
+  if (RuntimeEnabledFeatures::CSSPseudoDirEnabled()) {
+    SetNeedsStyleRecalc(
+        kSubtreeStyleChange,
+        StyleChangeReasonForTracing::Create(style_change_reason::kPseudoClass));
+    PseudoStateChanged(CSSSelector::kPseudoDir);
+  }
 }
 
 void HTMLElement::OnFormAttrChanged(const AttributeModificationParams& params) {
diff --git a/third_party/blink/renderer/core/html/html_element.h b/third_party/blink/renderer/core/html/html_element.h
index 67e9e66..58e01d96 100644
--- a/third_party/blink/renderer/core/html/html_element.h
+++ b/third_party/blink/renderer/core/html/html_element.h
@@ -153,6 +153,8 @@
   virtual FormAssociated* ToFormAssociatedOrNull() { return nullptr; }
   bool IsFormAssociatedCustomElement() const;
 
+  TextDirection ComputeInheritedDirectionality() const;
+
  protected:
   enum AllowPercentage { kDontAllowPercentageValues, kAllowPercentageValues };
   enum AllowZero { kDontAllowZeroValues, kAllowZeroValues };
@@ -185,7 +187,7 @@
   unsigned ParseBorderWidthAttribute(const AtomicString&) const;
 
   void ChildrenChanged(const ChildrenChange&) override;
-  void CalculateAndAdjustDirectionality();
+  bool CalculateAndAdjustDirectionality();
 
   InsertionNotificationRequest InsertedInto(ContainerNode&) override;
   void RemovedFrom(ContainerNode& insertion_point) override;
diff --git a/third_party/blink/renderer/core/html/html_frame_owner_element.cc b/third_party/blink/renderer/core/html/html_frame_owner_element.cc
index 23188bc..cc54e54d 100644
--- a/third_party/blink/renderer/core/html/html_frame_owner_element.cc
+++ b/third_party/blink/renderer/core/html/html_frame_owner_element.cc
@@ -409,8 +409,14 @@
 
   String fake_header =
       "HTTP/1.1 200 OK\nContent-Security-Policy: " + RequiredCsp();
+  // ParseHeaders needs a url to resolve report endpoints and for matching the
+  // keyword 'self'. However, the csp attribute does not allow report
+  // endpoints. Moreover, in the csp attribute, 'self' should not match the
+  // owner's url, but rather the frame src url. This is taken care by the
+  // Content-Security-Policy Embedded Enforcement algorithm, implemented in the
+  // AncestorThrottle. That's why we pass an empty url here.
   network::mojom::blink::ParsedHeadersPtr parsed_headers =
-      ParseHeaders(fake_header, GetDocument().Url());
+      ParseHeaders(fake_header, KURL());
 
   DCHECK_LE(parsed_headers->content_security_policy.size(), 1u);
 
diff --git a/third_party/blink/renderer/core/inspector/inspector_trace_events.cc b/third_party/blink/renderer/core/inspector/inspector_trace_events.cc
index 26d7b21..2a6bc46 100644
--- a/third_party/blink/renderer/core/inspector/inspector_trace_events.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_trace_events.cc
@@ -299,6 +299,7 @@
     DEFINE_STRING_MAPPING(PseudoEnabled)
     DEFINE_STRING_MAPPING(PseudoFullPageMedia)
     DEFINE_STRING_MAPPING(PseudoDefault)
+    DEFINE_STRING_MAPPING(PseudoDir)
     DEFINE_STRING_MAPPING(PseudoDisabled)
     DEFINE_STRING_MAPPING(PseudoOptional)
     DEFINE_STRING_MAPPING(PseudoPlaceholderShown)
diff --git a/third_party/blink/renderer/core/loader/empty_clients.cc b/third_party/blink/renderer/core/loader/empty_clients.cc
index ea24fab..4124bc72 100644
--- a/third_party/blink/renderer/core/loader/empty_clients.cc
+++ b/third_party/blink/renderer/core/loader/empty_clients.cc
@@ -105,7 +105,6 @@
     const String&,
     const base::Optional<WebImpression>&,
     WTF::Vector<network::mojom::blink::ContentSecurityPolicyPtr> initiator_csp,
-    network::mojom::blink::CSPSourcePtr initiator_csp_self,
     network::mojom::IPAddressSpace,
     mojo::PendingRemote<mojom::blink::NavigationInitiator>) {}
 
diff --git a/third_party/blink/renderer/core/loader/empty_clients.h b/third_party/blink/renderer/core/loader/empty_clients.h
index 0e07fb9..871023f 100644
--- a/third_party/blink/renderer/core/loader/empty_clients.h
+++ b/third_party/blink/renderer/core/loader/empty_clients.h
@@ -274,7 +274,6 @@
       const base::Optional<WebImpression>&,
       WTF::Vector<network::mojom::blink::ContentSecurityPolicyPtr>
           initiator_csp,
-      network::mojom::blink::CSPSourcePtr initiator_self_source,
       network::mojom::IPAddressSpace,
       mojo::PendingRemote<mojom::blink::NavigationInitiator>) override;
 
diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc
index 4bfab0f..ab66bd3 100644
--- a/third_party/blink/renderer/core/loader/frame_loader.cc
+++ b/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -727,19 +727,11 @@
 
   mojo::PendingRemote<mojom::blink::NavigationInitiator> navigation_initiator;
   WTF::Vector<network::mojom::blink::ContentSecurityPolicyPtr> initiator_csp;
-  network::mojom::blink::CSPSourcePtr initiator_self_source;
   if (origin_window && origin_window->GetContentSecurityPolicy()
                            ->ExperimentalFeaturesEnabled()) {
     ContentSecurityPolicy* origin_window_csp =
         origin_window->GetContentSecurityPolicy();
-    CSPSource* origin_window_csp_self_source =
-        origin_window_csp->GetSelfSource();
-
     initiator_csp = origin_window_csp->ExposeForNavigationalChecks();
-    if (origin_window_csp_self_source) {
-      initiator_self_source =
-          origin_window_csp_self_source->ExposeForNavigationalChecks();
-    }
     NavigationInitiatorImpl::From(*origin_window)
         .BindReceiver(navigation_initiator.InitWithNewPipeAndPassReceiver());
   }
@@ -839,8 +831,7 @@
       request.GetTriggeringEventInfo(), request.Form(),
       should_check_main_world_csp, request.GetBlobURLToken(),
       request.GetInputStartTime(), request.HrefTranslate().GetString(),
-      request.Impression(), std::move(initiator_csp),
-      std::move(initiator_self_source), initiator_address_space,
+      request.Impression(), std::move(initiator_csp), initiator_address_space,
       std::move(navigation_initiator));
 }
 
diff --git a/third_party/blink/renderer/core/streams/miscellaneous_operations.cc b/third_party/blink/renderer/core/streams/miscellaneous_operations.cc
index ffaeaa96..eb843c56 100644
--- a/third_party/blink/renderer/core/streams/miscellaneous_operations.cc
+++ b/third_party/blink/renderer/core/streams/miscellaneous_operations.cc
@@ -196,6 +196,48 @@
   TraceWrapperV8Reference<v8::Value> extra_arg_;
 };
 
+class JavaScriptByteStreamStartAlgorithm : public StreamStartAlgorithm {
+ public:
+  JavaScriptByteStreamStartAlgorithm(v8::Isolate* isolate,
+                                     v8::Local<v8::Function> method,
+                                     v8::Local<v8::Object> recv,
+                                     v8::Local<v8::Value> controller)
+      : recv_(isolate, recv),
+        method_(isolate, method),
+        controller_(isolate, controller) {}
+
+  v8::MaybeLocal<v8::Promise> Run(ScriptState* script_state,
+                                  ExceptionState& exception_state) override {
+    auto* isolate = script_state->GetIsolate();
+
+    auto value_maybe =
+        Call1(script_state, method_.NewLocal(isolate), recv_.NewLocal(isolate),
+              controller_.NewLocal(isolate), exception_state);
+    if (exception_state.HadException()) {
+      return v8::MaybeLocal<v8::Promise>();
+    }
+
+    v8::Local<v8::Value> value;
+    if (!value_maybe.ToLocal(&value)) {
+      exception_state.ThrowTypeError("internal error");
+      return v8::MaybeLocal<v8::Promise>();
+    }
+    return PromiseResolve(script_state, value);
+  }
+
+  void Trace(Visitor* visitor) const override {
+    visitor->Trace(recv_);
+    visitor->Trace(method_);
+    visitor->Trace(controller_);
+    StreamStartAlgorithm::Trace(visitor);
+  }
+
+ private:
+  TraceWrapperV8Reference<v8::Object> recv_;
+  TraceWrapperV8Reference<v8::Function> method_;
+  TraceWrapperV8Reference<v8::Value> controller_;
+};
+
 class JavaScriptStreamStartAlgorithm : public StreamStartAlgorithm {
  public:
   JavaScriptStreamStartAlgorithm(v8::Isolate* isolate,
@@ -343,10 +385,24 @@
       controller);
 }
 
+CORE_EXPORT StreamStartAlgorithm* CreateByteStreamStartAlgorithm(
+    ScriptState* script_state,
+    v8::Local<v8::Object> underlying_object,
+    v8::Local<v8::Value> method,
+    v8::Local<v8::Value> controller) {
+  return MakeGarbageCollected<JavaScriptByteStreamStartAlgorithm>(
+      script_state->GetIsolate(), method.As<v8::Function>(), underlying_object,
+      controller);
+}
+
 CORE_EXPORT StreamStartAlgorithm* CreateTrivialStartAlgorithm() {
   return MakeGarbageCollected<TrivialStartAlgorithm>();
 }
 
+CORE_EXPORT StreamAlgorithm* CreateTrivialStreamAlgorithm() {
+  return MakeGarbageCollected<TrivialStreamAlgorithm>();
+}
+
 CORE_EXPORT v8::MaybeLocal<v8::Value> CallOrNoop1(
     ScriptState* script_state,
     v8::Local<v8::Object> object,
@@ -381,6 +437,21 @@
   return result;
 }
 
+CORE_EXPORT v8::MaybeLocal<v8::Value> Call1(ScriptState* script_state,
+                                            v8::Local<v8::Function> method,
+                                            v8::Local<v8::Object> object,
+                                            v8::Local<v8::Value> arg0,
+                                            ExceptionState& exception_state) {
+  v8::TryCatch try_catch(script_state->GetIsolate());
+  v8::MaybeLocal<v8::Value> result =
+      method->Call(script_state->GetContext(), object, 1, &arg0);
+  if (result.IsEmpty()) {
+    exception_state.RethrowV8Exception(try_catch.Exception());
+    return v8::MaybeLocal<v8::Value>();
+  }
+  return result;
+}
+
 CORE_EXPORT v8::Local<v8::Promise> PromiseCall(ScriptState* script_state,
                                                v8::Local<v8::Function> method,
                                                v8::Local<v8::Object> recv,
@@ -562,4 +633,8 @@
                                            exception_state);
 }
 
+bool StrategyUnpacker::IsSizeUndefined() const {
+  return size_->IsUndefined();
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/streams/miscellaneous_operations.h b/third_party/blink/renderer/core/streams/miscellaneous_operations.h
index 2a58874..70dacef 100644
--- a/third_party/blink/renderer/core/streams/miscellaneous_operations.h
+++ b/third_party/blink/renderer/core/streams/miscellaneous_operations.h
@@ -68,10 +68,22 @@
     const char* method_name_for_error,
     v8::Local<v8::Value> controller);
 
+// Create a StreamStartAlgorithm from the "start" method on |underlying_object|
+// for readable byte streams.
+CORE_EXPORT StreamStartAlgorithm* CreateByteStreamStartAlgorithm(
+    ScriptState*,
+    v8::Local<v8::Object> underlying_object,
+    v8::Local<v8::Value> method,
+    v8::Local<v8::Value> controller);
+
 // Returns a startAlgorithm that always returns a promise resolved with
 // undefined.
 CORE_EXPORT StreamStartAlgorithm* CreateTrivialStartAlgorithm();
 
+// Returns a streamAlgorithm that always returns a promise resolved with
+// undefined.
+CORE_EXPORT StreamAlgorithm* CreateTrivialStreamAlgorithm();
+
 // Used in place of InvokeOrNoop in spec. Always takes 1 argument.
 // https://streams.spec.whatwg.org/#invoke-or-noop
 CORE_EXPORT v8::MaybeLocal<v8::Value> CallOrNoop1(ScriptState*,
@@ -81,6 +93,15 @@
                                                   v8::Local<v8::Value> arg0,
                                                   ExceptionState&);
 
+// Used in JavaScriptByteStreamStartAlgoirthm to call the method.
+// This is a variation of the CallOrNoop1 method where it is given the method
+// function already.
+CORE_EXPORT v8::MaybeLocal<v8::Value> Call1(ScriptState*,
+                                            v8::Local<v8::Function> method,
+                                            v8::Local<v8::Object> object,
+                                            v8::Local<v8::Value> arg0,
+                                            ExceptionState&);
+
 // https://streams.spec.whatwg.org/#promise-call
 // "PromiseCall(F, V, args)"
 // "F" is called |method| here
@@ -153,6 +174,8 @@
                           int default_value,
                           ExceptionState&) const;
 
+  bool IsSizeUndefined() const;
+
  private:
   v8::Local<v8::Value> size_;
   v8::Local<v8::Value> high_water_mark_;
diff --git a/third_party/blink/renderer/core/streams/readable_byte_stream_controller.cc b/third_party/blink/renderer/core/streams/readable_byte_stream_controller.cc
index ec76fac..f4f8b6b 100644
--- a/third_party/blink/renderer/core/streams/readable_byte_stream_controller.cc
+++ b/third_party/blink/renderer/core/streams/readable_byte_stream_controller.cc
@@ -4,51 +4,1306 @@
 
 #include "third_party/blink/renderer/core/streams/readable_byte_stream_controller.h"
 
+#include "base/numerics/checked_math.h"
+#include "base/numerics/clamped_math.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_array_buffer_view.h"
+#include "third_party/blink/renderer/core/streams/miscellaneous_operations.h"
+#include "third_party/blink/renderer/core/streams/promise_handler.h"
+#include "third_party/blink/renderer/core/streams/readable_stream.h"
 #include "third_party/blink/renderer/core/streams/readable_stream_byob_request.h"
+#include "third_party/blink/renderer/core/streams/stream_algorithms.h"
 #include "third_party/blink/renderer/core/streams/stream_promise_resolver.h"
+#include "third_party/blink/renderer/core/streams/underlying_source.h"
+#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h"
+#include "third_party/blink/renderer/core/typed_arrays/dom_data_view.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/bindings/v8_binding.h"
+#include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
+#include "v8/include/v8.h"
 
 namespace blink {
 
-ReadableStreamBYOBRequest* ReadableByteStreamController::byobRequest(
-    ExceptionState& exception_state) const {
-  ThrowUnimplemented(exception_state);
-  return nullptr;
+namespace {
+
+template <typename DOMType>
+DOMArrayBufferView* CreateAsArrayBufferView(DOMArrayBuffer* buffer,
+                                            size_t byte_offset,
+                                            size_t length) {
+  return DOMType::Create(buffer, byte_offset, length);
 }
 
-base::Optional<double> ReadableByteStreamController::desiredSize(
-    ExceptionState& exception_state) const {
-  ThrowUnimplemented(exception_state);
-  return base::nullopt;
+}  // namespace
+
+ReadableByteStreamController::QueueEntry::QueueEntry(DOMArrayBuffer* buffer,
+                                                     size_t byte_offset,
+                                                     size_t byte_length)
+    : buffer(buffer), byte_offset(byte_offset), byte_length(byte_length) {}
+
+void ReadableByteStreamController::QueueEntry::Trace(Visitor* visitor) const {
+  visitor->Trace(buffer);
+}
+
+ReadableByteStreamController::PullIntoDescriptor::PullIntoDescriptor(
+    DOMArrayBuffer* buffer,
+    size_t byte_offset,
+    size_t byte_length,
+    size_t bytes_filled,
+    size_t element_size,
+    ViewConstructorType view_constructor,
+    ReaderType reader_type)
+    : buffer(buffer),
+      byte_offset(byte_offset),
+      byte_length(byte_length),
+      bytes_filled(bytes_filled),
+      element_size(element_size),
+      view_constructor(view_constructor),
+      reader_type(reader_type) {}
+
+void ReadableByteStreamController::PullIntoDescriptor::Trace(
+    Visitor* visitor) const {
+  visitor->Trace(buffer);
+}
+
+// This constructor is used internally; it is not reachable from Javascript.
+ReadableByteStreamController::ReadableByteStreamController()
+    : queue_total_size_(queue_.size()) {}
+
+ReadableStreamBYOBRequest* ReadableByteStreamController::byobRequest() {
+  // https://streams.spec.whatwg.org/#rbs-controller-byob-request
+  // 1. If this.[[byobRequest]] is null and this.[[pendingPullIntos]] is not
+  // empty,
+  if (!byob_request_ && !pending_pull_intos_.IsEmpty()) {
+    //   a. Let firstDescriptor be this.[[pendingPullIntos]][0].
+    const PullIntoDescriptor* first_descriptor = pending_pull_intos_[0];
+    //   b. Let view be ! Construct(%Uint8Array%, « firstDescriptor’s buffer,
+    //   firstDescriptor’s byte offset + firstDescriptor’s bytes filled,
+    //   firstDescriptor’s byte length − firstDescriptor’s bytes filled »).
+    DOMUint8Array* const view = DOMUint8Array::Create(
+        first_descriptor->buffer,
+        first_descriptor->byte_offset + first_descriptor->bytes_filled,
+        first_descriptor->byte_length - first_descriptor->bytes_filled);
+    //   c. Let byobRequest be a new ReadableStreamBYOBRequest.
+    //   d. Set byobRequest.[[controller]] to this.
+    //   e. Set byobRequest.[[view]] to view.
+    //   f. Set this.[[byobRequest]] to byobRequest.
+    byob_request_ = MakeGarbageCollected<ReadableStreamBYOBRequest>(
+        this, NotShared<DOMUint8Array>(view));
+  }
+  // 2. Return this.[[byobRequest]].
+  return byob_request_;
+}
+
+base::Optional<double> ReadableByteStreamController::desiredSize() {
+  // https://streams.spec.whatwg.org/#rbs-controller-desired-size
+  // 1. Return ! ReadableByteStreamControllerGetDesiredSize(this).
+  return GetDesiredSize(this);
+}
+
+base::Optional<double> ReadableByteStreamController::GetDesiredSize(
+    ReadableByteStreamController* controller) {
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-get-desired-size
+  // 1. Let state be controller.[[stream]].[[state]].
+  switch (controller->controlled_readable_stream_->state_) {
+      // 2. If state is "errored", return null.
+    case ReadableStream::kErrored:
+      return base::nullopt;
+
+      // 3. If state is "closed", return 0.
+    case ReadableStream::kClosed:
+      return 0.0;
+
+    case ReadableStream::kReadable:
+      // 4. Return controller.[[strategyHWM]]] - controller.[[queueTotalSize]].
+      return controller->strategy_high_water_mark_ -
+             controller->queue_total_size_;
+  }
 }
 
 void ReadableByteStreamController::close(ScriptState* script_state,
                                          ExceptionState& exception_state) {
-  ThrowUnimplemented(exception_state);
-  return;
+  // https://streams.spec.whatwg.org/#rbs-controller-close
+  // 1. If this.[[closeRequested]] is true, throw a TypeError exception.
+  if (close_requested_) {
+    exception_state.ThrowTypeError(
+        "Cannot close a readable stream that has already been requested "
+        "to be closed");
+    return;
+  }
+
+  // 2. If this.[[stream]].[[state]] is not "readable", throw a TypeError
+  // exception.
+  if (controlled_readable_stream_->state_ != ReadableStream::kReadable) {
+    exception_state.ThrowTypeError(
+        "Cannot close a readable stream that is not readable");
+    return;
+  }
+
+  // 3. Perform ? ReadableByteStreamControllerClose(this).
+  Close(script_state, this, exception_state);
 }
 
 void ReadableByteStreamController::enqueue(ScriptState* script_state,
                                            NotShared<DOMArrayBufferView> chunk,
                                            ExceptionState& exception_state) {
-  ThrowUnimplemented(exception_state);
-  return;
+  // https://streams.spec.whatwg.org/#rbs-controller-enqueue
+  // 1. If chunk.[[ByteLength]] is 0, throw a TypeError exception.
+  if (chunk->byteLength() == 0) {
+    exception_state.ThrowTypeError("chunk is empty");
+    return;
+  }
+
+  // 2. If chunk.[[ViewedArrayBuffer]].[[ArrayBufferByteLength]] is 0, throw a
+  // TypeError exception.
+  if (chunk->buffer()->ByteLength() == 0) {
+    exception_state.ThrowTypeError("chunk's buffer is empty");
+    return;
+  }
+
+  // 3. If this.[[closeRequested]] is true, throw a TypeError exception.
+  if (close_requested_) {
+    exception_state.ThrowTypeError("close requested already");
+    return;
+  }
+
+  // 4. If this.[[stream]].[[state]] is not "readable", throw a TypeError
+  // exception.
+  if (controlled_readable_stream_->state_ != ReadableStream::kReadable) {
+    exception_state.ThrowTypeError("stream is not readable");
+    return;
+  }
+
+  // 5. Return ! ReadableByteStreamControllerEnqueue(this, chunk).
+  Enqueue(script_state, this, chunk, exception_state);
+}
+
+void ReadableByteStreamController::error(ScriptState* script_state) {
+  error(script_state, ScriptValue(script_state->GetIsolate(),
+                                  v8::Undefined(script_state->GetIsolate())));
 }
 
 void ReadableByteStreamController::error(ScriptState* script_state,
-                                         ExceptionState& exception_state) {
-  ThrowUnimplemented(exception_state);
-  return;
+                                         const ScriptValue& e) {
+  // https://streams.spec.whatwg.org/#rbs-controller-error
+  // 1. Perform ! ReadableByteStreamControllerError(this, e).
+  Error(script_state, this, e.V8Value());
 }
 
-void ReadableByteStreamController::error(ScriptState* script_state,
-                                         ScriptValue e,
-                                         ExceptionState& exception_state) {
-  ThrowUnimplemented(exception_state);
-  return;
+void ReadableByteStreamController::Close(
+    ScriptState* script_state,
+    ReadableByteStreamController* controller,
+    ExceptionState& exception_state) {
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-close
+  // 1. Let stream be controller.[[stream]].
+  ReadableStream* const stream = controller->controlled_readable_stream_;
+
+  // 2. If controller.[[closeRequested]] is true or stream.[[state]] is not
+  // "readable", return.
+  if (controller->close_requested_ ||
+      stream->state_ != ReadableStream::kReadable) {
+    return;
+  }
+
+  // 3. If controller.[[queueTotalSize]] > 0,
+  if (controller->queue_total_size_ > 0) {
+    //   a. Set controller.[[closeRequested]] to true.
+    controller->close_requested_ = true;
+    //   b. Return.
+    return;
+  }
+
+  // 4. If controller.[[pendingPullIntos]] is not empty,
+  if (!controller->pending_pull_intos_.IsEmpty()) {
+    //   a. Let firstPendingPullInto be controller.[[pendingPullIntos]][0].
+    const PullIntoDescriptor* first_pending_pull_into =
+        controller->pending_pull_intos_[0];
+    //   b. If firstPendingPullInto’s bytes filled > 0,
+    if (first_pending_pull_into->bytes_filled > 0) {
+      //     i. Let e be a new TypeError exception.
+      exception_state.ThrowTypeError("Cannot close while responding");
+      v8::Local<v8::Value> e = exception_state.GetException();
+      //     ii. Perform ! ReadableByteStreamControllerError(controller, e).
+      Error(script_state, controller, e);
+      //     iii. Throw e.
+      return;
+    }
+  }
+
+  // 5. Perform ! ReadableByteStreamControllerClearAlgorithms(controller).
+  ClearAlgorithms(controller);
+
+  // 6. Perform ! ReadableStreamClose(stream).
+  ReadableStream::Close(script_state, stream);
+}
+
+void ReadableByteStreamController::Error(
+    ScriptState* script_state,
+    ReadableByteStreamController* controller,
+    v8::Local<v8::Value> e) {
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-error
+  // 1. Let stream by controller.[[stream]].
+  ReadableStream* const stream = controller->controlled_readable_stream_;
+
+  // 2. If stream.[[state]] is not "readable", return.
+  if (stream->state_ != ReadableStream::kReadable) {
+    return;
+  }
+
+  // 3. Perform ! ReadableByteStreamControllerClearPendingPullIntos(controller).
+  ClearPendingPullIntos(controller);
+
+  // 4. Perform ! ResetQueue(controller).
+  ResetQueue(controller);
+
+  // 5. Perform ! ReadableByteStreamControllerClearAlgorithms(controller).
+  ClearAlgorithms(controller);
+
+  // 6. Perform ! ReadableStreamError(stream, e).
+  ReadableStream::Error(script_state, stream, e);
+}
+
+void ReadableByteStreamController::Enqueue(
+    ScriptState* script_state,
+    ReadableByteStreamController* controller,
+    NotShared<DOMArrayBufferView> chunk,
+    ExceptionState& exception_state) {
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-enqueue
+  // 1. Let stream be controller.[[stream]].i
+  ReadableStream* const stream = controller->controlled_readable_stream_;
+
+  // 2. If controller.[[closeRequested]] is true or stream.[[state]] is not
+  // "readable", return.
+  if (controller->close_requested_ ||
+      stream->state_ != ReadableStream::kReadable) {
+    return;
+  }
+
+  // 3. Let buffer be chunk.[[ViewedArrayBuffer]].
+  DOMArrayBuffer* const buffer = chunk->buffer();
+
+  // 4. Let byteOffset be chunk.[[ByteOffset]].
+  const size_t byte_offset = chunk->byteOffset();
+
+  // 5. Let byteLength be chunk.[[ByteLength]].
+  const size_t byte_length = chunk->byteLength();
+
+  // 6. Let transferredBuffer be ! TransferArrayBuffer(buffer).
+  DOMArrayBuffer* const transferred_buffer =
+      TransferArrayBuffer(script_state, buffer, exception_state);
+
+  // 7. If ! ReadableStreamHasDefaultReader(stream) is true
+  if (ReadableStream::HasDefaultReader(stream)) {
+    //   a. If ! ReadableStreamGetNumReadRequests(stream) is 0,
+    if (ReadableStream::GetNumReadRequests(stream) == 0) {
+      //     i. Perform !
+      //     ReadableByteStreamControllerEnqueueChunkToQueue(controller,
+      //     transferredBuffer, byteOffset, byteLength).
+      EnqueueChunkToQueue(controller, transferred_buffer, byte_offset,
+                          byte_length);
+    } else {
+      // b. Otherwise,
+      //     i. Assert: controller.[[queue]] is empty.
+      DCHECK(controller->queue_.IsEmpty());
+      //     ii. Let transferredView be ! Construct(%Uint8Array%, «
+      //     transferredBuffer, byteOffset, byteLength »).
+      v8::Local<v8::Value> const transferred_view = v8::Uint8Array::New(
+          ToV8(transferred_buffer, script_state).As<v8::ArrayBuffer>(),
+          byte_offset, byte_length);
+      //     iii. Perform ! ReadableStreamFulfillReadRequest(stream,
+      //     transferredView, false).
+      ReadableStream::FulfillReadRequest(script_state, stream, transferred_view,
+                                         false);
+    }
+  }
+
+  // 8. Otherwise, if ! ReadableStreamHasBYOBReader(stream) is true,
+  else if (ReadableStream::HasBYOBReader(stream)) {
+    //   a. Perform !
+    //   ReadableByteStreamControllerEnqueueChunkToQueue(controller,
+    //   transferredBuffer, byteOffset, byteLength).
+    EnqueueChunkToQueue(controller, transferred_buffer, byte_offset,
+                        byte_length);
+    //   b. Perform !
+    //   ReadableByteStreamControllerProcessPullIntoDescriptorsUsing
+    //   Queue(controller).
+    ProcessPullIntoDescriptorsUsingQueue(script_state, controller);
+  } else {
+    // 9. Otherwise,
+    //   a. Assert: ! IsReadableStreamLocked(stream) is false.
+    DCHECK(!ReadableStream::IsLocked(stream));
+    //   b. Perform !
+    //   ReadableByteStreamControllerEnqueueChunkToQueue(controller,
+    //   transferredBuffer, byteOffset, byteLength).
+    EnqueueChunkToQueue(controller, transferred_buffer, byte_offset,
+                        byte_length);
+  }
+
+  // 10. Perform ! ReadableByteStreamControllerCallPullIfNeeded(controller).
+  CallPullIfNeeded(script_state, controller);
+}
+
+void ReadableByteStreamController::EnqueueChunkToQueue(
+    ReadableByteStreamController* controller,
+    DOMArrayBuffer* buffer,
+    size_t byte_offset,
+    size_t byte_length) {
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-enqueue-chunk-to-queue
+  // 1. Append a new readable byte stream queue entry with buffer buffer, byte
+  // offset byteOffset, and byte length byteLength to controller.[[queue]].
+  QueueEntry* const entry =
+      MakeGarbageCollected<QueueEntry>(buffer, byte_offset, byte_length);
+  controller->queue_.push_back(entry);
+  // 2. Set controller.[[queueTotalSize]] to controller.[[queueTotalSize]] +
+  // byteLength.
+  controller->queue_total_size_ += byte_length;
+}
+
+void ReadableByteStreamController::ProcessPullIntoDescriptorsUsingQueue(
+    ScriptState* script_state,
+    ReadableByteStreamController* controller) {
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-process-pull-into-descriptors-using-queue
+  // 1. Assert: controller.[[closeRequested]] is false.
+  DCHECK(!controller->close_requested_);
+  // 2. While controller.[[pendingPullIntos]] is not empty,
+  while (!controller->pending_pull_intos_.IsEmpty()) {
+    //   a. If controller.[[queueTotalSize]] is 0, return.
+    if (controller->queue_total_size_ == 0) {
+      return;
+    }
+    //   b. Let pullIntoDescriptor be controller.[[pendingPullIntos]][0].
+    PullIntoDescriptor* const pull_into_descriptor =
+        controller->pending_pull_intos_[0];
+    //   c. If ! ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(
+    //   controller, pullIntoDescriptor) is true,
+    if (FillPullIntoDescriptorFromQueue(controller, pull_into_descriptor)) {
+      //     i. Perform !
+      //     ReadableByteStreamControllerShiftPendingPullInto(controller).
+      ShiftPendingPullInto(controller);
+      //     ii. Perform ! ReadableByteStreamControllerCommitPullIntoDescriptor(
+      //     controller.[[stream]], pullIntoDescriptor).
+      CommitPullIntoDescriptor(script_state,
+                               controller->controlled_readable_stream_,
+                               pull_into_descriptor);
+    }
+  }
+}
+
+void ReadableByteStreamController::CallPullIfNeeded(
+    ScriptState* script_state,
+    ReadableByteStreamController* controller) {
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-call-pull-if-needed
+  // 1. Let shouldPull be !
+  // ReadableByteStreamControllerShouldCallPull(controller).
+  const bool should_pull = ShouldCallPull(controller);
+  // 2. If shouldPull is false, return.
+  if (!should_pull) {
+    return;
+  }
+  // 3. If controller.[[pulling]] is true,
+  if (controller->pulling_) {
+    //   a. Set controller.[[pullAgain]] to true.
+    controller->pull_again_ = true;
+    //   b. Return.
+    return;
+  }
+  // 4. Assert: controller.[[pullAgain]] is false.
+  DCHECK(!controller->pull_again_);
+  // 5. Set controller.[[pulling]] to true.
+  controller->pulling_ = true;
+  // 6. Let pullPromise be the result of performing
+  // controller.[[pullAlgorithm]].
+  auto pull_promise =
+      controller->pull_algorithm_->Run(script_state, 0, nullptr);
+
+  class ResolveFunction final : public PromiseHandler {
+   public:
+    ResolveFunction(ScriptState* script_state,
+                    ReadableByteStreamController* controller)
+        : PromiseHandler(script_state), controller_(controller) {}
+
+    void CallWithLocal(v8::Local<v8::Value>) override {
+      // 7. Upon fulfillment of pullPromise,
+      //   a. Set controller.[[pulling]] to false.
+      controller_->pulling_ = false;
+      //   b. If controller.[[pullAgain]] is true,
+      if (controller_->pull_again_) {
+        //     i. Set controller.[[pullAgain]] to false.
+        controller_->pull_again_ = false;
+        //     ii. Perform !
+        //     ReadableByteStreamControllerCallPullIfNeeded(controller).
+        CallPullIfNeeded(GetScriptState(), controller_);
+      }
+    }
+
+    void Trace(Visitor* visitor) const override {
+      visitor->Trace(controller_);
+      PromiseHandler::Trace(visitor);
+    }
+
+   private:
+    const Member<ReadableByteStreamController> controller_;
+  };
+
+  class RejectFunction final : public PromiseHandler {
+   public:
+    RejectFunction(ScriptState* script_state,
+                   ReadableByteStreamController* controller)
+        : PromiseHandler(script_state), controller_(controller) {}
+
+    void CallWithLocal(v8::Local<v8::Value> e) override {
+      // 8. Upon rejection of pullPromise with reason e,
+      //   a. Perform ! ReadableByteStreamControllerError(controller, e).
+      Error(GetScriptState(), controller_, e);
+    }
+
+    void Trace(Visitor* visitor) const override {
+      visitor->Trace(controller_);
+      PromiseHandler::Trace(visitor);
+    }
+
+   private:
+    const Member<ReadableByteStreamController> controller_;
+  };
+
+  StreamThenPromise(
+      script_state->GetContext(), pull_promise,
+      MakeGarbageCollected<ResolveFunction>(script_state, controller),
+      MakeGarbageCollected<RejectFunction>(script_state, controller));
+}
+
+ReadableByteStreamController::PullIntoDescriptor*
+ReadableByteStreamController::ShiftPendingPullInto(
+    ReadableByteStreamController* controller) {
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-shift-pending-pull-into
+  // 1. Let descriptor be controller.[[pendingPullIntos]][0].
+  PullIntoDescriptor* const descriptor = controller->pending_pull_intos_[0];
+  // 2. Remove descriptor from controller.[[pendingPullIntos]].
+  controller->pending_pull_intos_.pop_front();
+  // 3. Perform ! ReadableByteStreamControllerInvalidateBYOBRequest(controller).
+  InvalidateBYOBRequest(controller);
+  // 4. Return descriptor.
+  return descriptor;
+}
+
+bool ReadableByteStreamController::ShouldCallPull(
+    ReadableByteStreamController* controller) {
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-should-call-pull
+  // 1. Let stream be controller.[[stream]].
+  ReadableStream* const stream = controller->controlled_readable_stream_;
+  // 2. If stream.[[state]] is not "readable", return false.
+  if (stream->state_ != ReadableStream::kReadable) {
+    return false;
+  }
+  // 3. If controller.[[closeRequested]] is true, return false.
+  if (controller->close_requested_) {
+    return false;
+  }
+  // 4. If controller.[[started]] is false, return false.
+  if (!controller->started_) {
+    return false;
+  }
+  // 5. If ! ReadableStreamHasDefaultReader(stream) is true and !
+  // ReadableStreamGetNumReadRequests(stream) > 0, return true.
+  if (ReadableStream::HasDefaultReader(stream) &&
+      ReadableStream::GetNumReadRequests(stream) > 0) {
+    return true;
+  }
+  // 6. If ! ReadableStreamHasBYOBReader(stream) is true and !
+  // ReadableStreamGetNumReadIntoRequests(stream) > 0, return true.
+  if (ReadableStream::HasBYOBReader(stream) &&
+      ReadableStream::GetNumReadIntoRequests(stream) > 0) {
+    return true;
+  }
+  // 7. Let desiredSize be !
+  // ReadableByteStreamControllerGetDesiredSize(controller).
+  const base::Optional<double> desired_size = GetDesiredSize(controller);
+  // 8. Assert: desiredSize is not null.
+  DCHECK(desired_size);
+  // 9. If desiredSize > 0, return true.
+  if (*desired_size > 0) {
+    return true;
+  }
+  // 10. Return false.
+  return false;
+}
+
+void ReadableByteStreamController::CommitPullIntoDescriptor(
+    ScriptState* script_state,
+    ReadableStream* stream,
+    PullIntoDescriptor* pull_into_descriptor) {
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-commit-pull-into-descriptor
+  // 1. Assert: stream.[[state]] is not "errored".
+  DCHECK_NE(stream->state_, ReadableStream::kErrored);
+  // 2. Let done be false.
+  bool done = false;
+  // 3. If stream.[[state]] is "closed",
+  if (stream->state_ == ReadableStream::kClosed) {
+    //   a. Assert: pullIntoDescriptor’s bytes filled is 0.
+    DCHECK_EQ(pull_into_descriptor->bytes_filled, 0u);
+    //   b. Set done to true.
+    done = true;
+  }
+  // 4. Let filledView be !
+  // ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor).
+  auto* filled_view = ConvertPullIntoDescriptor(pull_into_descriptor);
+  // 5. If pullIntoDescriptor’s reader type is "default",
+  if (pull_into_descriptor->reader_type == ReaderType::kDefault) {
+    //   a. Perform ! ReadableStreamFulfillReadRequest(stream, filledView,
+    //   done).
+    ReadableStream::FulfillReadRequest(script_state, stream,
+                                       ToV8(filled_view, script_state), done);
+  } else {
+    // 6. Otherwise,
+    //   a. Assert: pullIntoDescriptor’s reader type is "byob".
+    DCHECK_EQ(pull_into_descriptor->reader_type, ReaderType::kBYOB);
+    //   b. Perform ! ReadableStreamFulfillReadIntoRequest(stream, filledView,
+    //   done).
+    ReadableStream::FulfillReadIntoRequest(script_state, stream, filled_view,
+                                           done);
+  }
+}
+
+DOMArrayBufferView* ReadableByteStreamController::ConvertPullIntoDescriptor(
+    PullIntoDescriptor* pull_into_descriptor) {
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-convert-pull-into-descriptor
+  // 1. Let bytesFilled be pullIntoDescriptor’s bytes filled.
+  const size_t bytes_filled = pull_into_descriptor->bytes_filled;
+  // 2. Let elementSize be pullIntoDescriptor’s element size.
+  const size_t element_size = pull_into_descriptor->element_size;
+  // 3. Assert: bytesFilled ≤ pullIntoDescriptor’s byte length.
+  DCHECK_LE(bytes_filled, pull_into_descriptor->byte_length);
+  // 4. Assert: bytesFilled mod elementSize is 0.
+  DCHECK_EQ(bytes_filled % element_size, 0u);
+  // 5. Return ! Construct(pullIntoDescriptor’s view constructor, «
+  // pullIntoDescriptor’s buffer, pullIntoDescriptor’s byte offset, bytesFilled
+  // ÷ elementSize »).
+  return pull_into_descriptor->view_constructor(
+      pull_into_descriptor->buffer, pull_into_descriptor->byte_offset,
+      (bytes_filled / element_size));
+}
+
+void ReadableByteStreamController::ClearPendingPullIntos(
+    ReadableByteStreamController* controller) {
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-clear-pending-pull-intos
+  // 1. Perform ! ReadableByteStreamControllerInvalidateBYOBRequest(controller).
+  InvalidateBYOBRequest(controller);
+  // 2. Set controller.[[pendingPullIntos]] to a new empty list.
+  controller->pending_pull_intos_.clear();
+}
+
+void ReadableByteStreamController::ClearAlgorithms(
+    ReadableByteStreamController* controller) {
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-clear-algorithms
+  // 1. Set controller.[[pullAlgorithm]] to undefined.
+  controller->pull_algorithm_ = nullptr;
+
+  // 2. Set controller.[[cancelAlgorithm]] to undefined.
+  controller->cancel_algorithm_ = nullptr;
+}
+
+void ReadableByteStreamController::InvalidateBYOBRequest(
+    ReadableByteStreamController* controller) {
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-invalidate-byob-request
+  // 1. If controller.[[byobRequest]] is null, return.
+  if (!controller->byob_request_) {
+    return;
+  }
+  // 2. Set controller.[[byobRequest]].[[controller]] to undefined.
+  controller->byob_request_->controller_ = nullptr;
+  // 3. Set controller.[[byobRequest]].[[view]] to null.
+  controller->byob_request_->view_ = NotShared<DOMArrayBufferView>(nullptr);
+  // 4. Set controller.[[byobRequest]] to null.
+  controller->byob_request_ = nullptr;
+}
+
+void ReadableByteStreamController::SetUp(
+    ScriptState* script_state,
+    ReadableStream* stream,
+    ReadableByteStreamController* controller,
+    StreamStartAlgorithm* start_algorithm,
+    StreamAlgorithm* pull_algorithm,
+    StreamAlgorithm* cancel_algorithm,
+    double high_water_mark,
+    size_t auto_allocate_chunk_size,
+    ExceptionState& exception_state) {
+  // https://streams.spec.whatwg.org/#set-up-readable-byte-stream-controller
+  // 1. Assert: stream.[[controller]] is undefined.
+  DCHECK(!stream->readable_stream_controller_);
+  // 2. If autoAllocateChunkSize is not undefined,
+  if (auto_allocate_chunk_size) {
+    //   a. Assert: ! IsInteger(autoAllocateChunkSize) is true.
+    //   b. Assert: autoAllocateChunkSize is positive.
+    //   Due to autoAllocateChunkSize having the [EnforceRange] attribute, it
+    //   can never be negative.
+    DCHECK_GT(auto_allocate_chunk_size, 0u);
+  }
+  // 3. Set controller.[[stream]] to stream.
+  controller->controlled_readable_stream_ = stream;
+  // 4. Set controller.[[pullAgain]] and controller.[[pulling]] to false.
+  DCHECK(!controller->pull_again_);
+  DCHECK(!controller->pulling_);
+  // 5. Set controller.[[byobRequest]] to null.
+  DCHECK(!controller->byob_request_);
+  // 6. Perform ! ResetQueue(controller).
+  ResetQueue(controller);
+  // 7. Set controller.[[closeRequested]] and controller.[[started]] to false.
+  DCHECK(!controller->close_requested_);
+  DCHECK(!controller->started_);
+  // 8. Set controller.[[strategyHWM]] to highWaterMark.
+  controller->strategy_high_water_mark_ = high_water_mark;
+  // 9. Set controller.[[pullAlgorithm]] to pullAlgorithm.
+  controller->pull_algorithm_ = pull_algorithm;
+  // 10. Set controller.[[cancelAlgorithm]] to cancelAlgorithm.
+  controller->cancel_algorithm_ = cancel_algorithm;
+  // 11. Set controller.[[autoAllocateChunkSize]] to autoAllocateChunkSize.
+  controller->auto_allocate_chunk_size_ = auto_allocate_chunk_size;
+  // 12. Set controller.[[pendingPullIntos]] to a new empty list.
+  DCHECK(controller->pending_pull_intos_.IsEmpty());
+  // 13. Set stream.[[controller]] to controller.
+  stream->readable_stream_controller_ = controller;
+  // 14. Let startResult be the result of performing startAlgorithm.
+  // 15. Let startPromise be a promise resolved with startResult.
+  // The conversion of startResult to a promise happens inside start_algorithm
+  // in this implementation.
+  v8::Local<v8::Promise> start_promise;
+  if (!start_algorithm->Run(script_state, exception_state)
+           .ToLocal(&start_promise)) {
+    if (!exception_state.HadException()) {
+      exception_state.ThrowException(
+          static_cast<int>(DOMExceptionCode::kInvalidStateError),
+          "start algorithm failed with no exception thrown");
+    }
+    return;
+  }
+  DCHECK(!exception_state.HadException());
+
+  class ResolveFunction final : public PromiseHandler {
+   public:
+    ResolveFunction(ScriptState* script_state,
+                    ReadableByteStreamController* controller)
+        : PromiseHandler(script_state), controller_(controller) {}
+
+    void CallWithLocal(v8::Local<v8::Value>) override {
+      // 16. Upon fulfillment of startPromise,
+      //   a. Set controller.[[started]] to true.
+      controller_->started_ = true;
+      //   b. Assert: controller.[[pulling]] is false.
+      DCHECK(!controller_->pulling_);
+      //   c. Assert: controller.[[pullAgain]] is false.
+      DCHECK(!controller_->pull_again_);
+      //   d. Perform !
+      //   ReadableByteStreamControllerCallPullIfNeeded(controller).
+      CallPullIfNeeded(GetScriptState(), controller_);
+    }
+
+    void Trace(Visitor* visitor) const override {
+      visitor->Trace(controller_);
+      PromiseHandler::Trace(visitor);
+    }
+
+   private:
+    const Member<ReadableByteStreamController> controller_;
+  };
+
+  class RejectFunction final : public PromiseHandler {
+   public:
+    RejectFunction(ScriptState* script_state,
+                   ReadableByteStreamController* controller)
+        : PromiseHandler(script_state), controller_(controller) {}
+
+    void CallWithLocal(v8::Local<v8::Value> r) override {
+      // 17. Upon rejection of startPromise with reason r,
+      //   a. Perform ! ReadableByteStreamControllerError(controller, r).
+      Error(GetScriptState(), controller_, r);
+    }
+
+    void Trace(Visitor* visitor) const override {
+      visitor->Trace(controller_);
+      PromiseHandler::Trace(visitor);
+    }
+
+   private:
+    const Member<ReadableByteStreamController> controller_;
+  };
+
+  StreamThenPromise(
+      script_state->GetContext(), start_promise,
+      MakeGarbageCollected<ResolveFunction>(script_state, controller),
+      MakeGarbageCollected<RejectFunction>(script_state, controller));
+}
+
+void ReadableByteStreamController::SetUpFromUnderlyingSource(
+    ScriptState* script_state,
+    ReadableStream* stream,
+    v8::Local<v8::Object> underlying_source,
+    UnderlyingSource* underlying_source_dict,
+    double high_water_mark,
+    ExceptionState& exception_state) {
+  // https://streams.spec.whatwg.org/#set-up-readable-byte-stream-controller-from-underlying-source
+  // 1. Let controller be a new ReadableByteStreamController.
+  ReadableByteStreamController* controller =
+      MakeGarbageCollected<ReadableByteStreamController>();
+  // 2. Let startAlgorithm be an algorithm that returns undefined.
+  StreamStartAlgorithm* start_algorithm = CreateTrivialStartAlgorithm();
+  // 3. Let pullAlgorithm be an algorithm that returns a promise resolved with
+  // undefined.
+  StreamAlgorithm* pull_algorithm = CreateTrivialStreamAlgorithm();
+  // 4. Let cancelAlgorithm be an algorithm that returns a promise resolved with
+  // undefined.
+  StreamAlgorithm* cancel_algorithm = CreateTrivialStreamAlgorithm();
+
+  const auto controller_value = ToV8(controller, script_state);
+  // 5. If underlyingSourceDict["start"] exists, then set startAlgorithm to an
+  // algorithm which returns the result of invoking
+  // underlyingSourceDict["start"] with argument list « controller » and
+  // callback this value underlyingSource.
+  if (underlying_source_dict->hasStart()) {
+    start_algorithm = CreateByteStreamStartAlgorithm(
+        script_state, underlying_source,
+        ToV8(underlying_source_dict->start(), script_state), controller_value);
+  }
+  // 6. If underlyingSourceDict["pull"] exists, then set pullAlgorithm to an
+  // algorithm which returns the result of invoking underlyingSourceDict["pull"]
+  // with argument list « controller » and callback this value underlyingSource.
+  if (underlying_source_dict->hasPull()) {
+    pull_algorithm = CreateAlgorithmFromResolvedMethod(
+        script_state, underlying_source,
+        ToV8(underlying_source_dict->pull(), script_state), controller_value);
+  }
+  // 7. If underlyingSourceDict["cancel"] exists, then set cancelAlgorithm to an
+  // algorithm which takes an argument reason and returns the result of invoking
+  // underlyingSourceDict["cancel"] with argument list « reason » and callback
+  // this value underlyingSource.
+  if (underlying_source_dict->hasCancel()) {
+    cancel_algorithm = CreateAlgorithmFromResolvedMethod(
+        script_state, underlying_source,
+        ToV8(underlying_source_dict->cancel(), script_state), controller_value);
+  }
+  // 8. Let autoAllocateChunkSize be
+  // underlyingSourceDict["autoAllocateChunkSize"], if it exists, or undefined
+  // otherwise.
+  size_t auto_allocate_chunk_size =
+      underlying_source_dict->hasAutoAllocateChunkSize()
+          ? static_cast<size_t>(underlying_source_dict->autoAllocateChunkSize())
+          : 0u;
+  // 9. If autoAllocateChunkSize is 0, then throw a TypeError exception.
+  if (underlying_source_dict->hasAutoAllocateChunkSize() &&
+      auto_allocate_chunk_size == 0) {
+    exception_state.ThrowTypeError("autoAllocateChunkSize cannot be 0");
+    return;
+  }
+  // 10. Perform ? SetUpReadableByteStreamController(stream, controller,
+  // startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark,
+  // autoAllocateChunkSize).
+  SetUp(script_state, stream, controller, start_algorithm, pull_algorithm,
+        cancel_algorithm, high_water_mark, auto_allocate_chunk_size,
+        exception_state);
+}
+
+void ReadableByteStreamController::FillHeadPullIntoDescriptor(
+    ReadableByteStreamController* controller,
+    size_t size,
+    PullIntoDescriptor* pull_into_descriptor) {
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-fill-head-pull-into-descriptor
+  // 1. Assert: either controller.[[pendingPullIntos]] is empty, or
+  // controller.[[pendingPullIntos]][0] is pullIntoDescriptor.
+  DCHECK(controller->pending_pull_intos_.IsEmpty() ||
+         controller->pending_pull_intos_[0] == pull_into_descriptor);
+  // 2. Perform ! ReadableByteStreamControllerInvalidateBYOBRequest(controller).
+  InvalidateBYOBRequest(controller);
+  // 3. Set pullIntoDescriptor’s bytes filled to bytes filled + size.
+  pull_into_descriptor->bytes_filled =
+      base::CheckAdd(pull_into_descriptor->bytes_filled, size).ValueOrDie();
+}
+
+bool ReadableByteStreamController::FillPullIntoDescriptorFromQueue(
+    ReadableByteStreamController* controller,
+    PullIntoDescriptor* pull_into_descriptor) {
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-fill-pull-into-descriptor-from-queue
+  // 1. Let elementSize be pullIntoDescriptor.[[elementSize]].
+  const size_t element_size = pull_into_descriptor->element_size;
+  // 2. Let currentAlignedBytes be pullIntoDescriptor's bytes filled −
+  // (pullIntoDescriptor's bytes filled mod elementSize).
+  const size_t current_aligned_bytes =
+      pull_into_descriptor->bytes_filled -
+      (pull_into_descriptor->bytes_filled % element_size);
+  // 3. Let maxBytesToCopy be min(controller.[[queueTotalSize]],
+  // pullIntoDescriptor’s byte length − pullIntoDescriptor’s bytes filled).
+  // The subtraction will not underflow because bytes length will always be more
+  // than or equal to bytes filled.
+  const size_t max_bytes_to_copy = std::min(
+      static_cast<size_t>(controller->queue_total_size_),
+      pull_into_descriptor->byte_length - pull_into_descriptor->bytes_filled);
+  // 4. Let maxBytesFilled be pullIntoDescriptor’s bytes filled +
+  // maxBytesToCopy.
+  // This addition will not overflow because maxBytesToCopy can be at most
+  // queue_total_size_. Both bytes_filled and queue_total_size_ refer to
+  // actually allocated memory, so together they cannot exceed size_t.
+  const size_t max_bytes_filled =
+      pull_into_descriptor->bytes_filled + max_bytes_to_copy;
+  // 5. Let maxAlignedBytes be maxBytesFilled − (maxBytesFilled mod
+  // elementSize).
+  // This subtraction will not underflow because the modulus operator is
+  // guaranteed to return a value less than or equal to the first argument.
+  const size_t max_aligned_bytes =
+      max_bytes_filled - (max_bytes_filled % element_size);
+  // 6. Let totalBytesToCopyRemaining be maxBytesToCopy.
+  size_t total_bytes_to_copy_remaining = max_bytes_to_copy;
+  // 7. Let ready be false;
+  bool ready = false;
+  // 8. If maxAlignedBytes > currentAlignedBytes,
+  if (max_aligned_bytes > current_aligned_bytes) {
+    // a. Set totalBytesToCopyRemaining to maxAlignedBytes −
+    // pullIntoDescriptor’s bytes filled.
+    total_bytes_to_copy_remaining =
+        base::CheckSub(max_aligned_bytes, pull_into_descriptor->bytes_filled)
+            .ValueOrDie();
+    // b. Set ready to true.
+    ready = true;
+  }
+  // 9. Let queue be controller.[[queue]].
+  HeapDeque<Member<QueueEntry>>& queue = controller->queue_;
+  // 10. While totalBytesToCopyRemaining > 0,
+  while (total_bytes_to_copy_remaining > 0) {
+    // a. Let headOfQueue be queue[0].
+    QueueEntry* head_of_queue = queue[0];
+    // b. Let bytesToCopy be min(totalBytesToCopyRemaining,
+    // headOfQueue’s byte length).
+    size_t bytes_to_copy =
+        std::min(total_bytes_to_copy_remaining, head_of_queue->byte_length);
+    // c. Let destStart be pullIntoDescriptor’s byte offset +
+    // pullIntoDescriptor’s bytes filled.
+    // This addition will not overflow because byte offset and bytes filled
+    // refer to actually allocated memory, so together they cannot exceed
+    // size_t.
+    size_t dest_start =
+        pull_into_descriptor->byte_offset + pull_into_descriptor->bytes_filled;
+    // d. Perform ! CopyDataBlockBytes(pullIntoDescriptor’s
+    // buffer.[[ArrayBufferData]], destStart, headOfQueue’s
+    // buffer.[[ArrayBufferData]], headOfQueue’s byte offset, bytesToCopy).
+    memcpy(
+        static_cast<char*>(pull_into_descriptor->buffer->Data()) + dest_start,
+        static_cast<char*>(head_of_queue->buffer->Data()) +
+            head_of_queue->byte_offset,
+        bytes_to_copy);
+    // e. If headOfQueue’s byte length is bytesToCopy,
+    if (head_of_queue->byte_length == bytes_to_copy) {
+      //   i. Remove queue[0].
+      queue.pop_front();
+    } else {
+      // f. Otherwise,
+      //   i. Set headOfQueue’s byte offset to headOfQueue’s byte offset +
+      //   bytesToCopy.
+      head_of_queue->byte_offset =
+          base::CheckAdd(head_of_queue->byte_offset, bytes_to_copy)
+              .ValueOrDie();
+      //   ii. Set headOfQueue’s byte length to headOfQueue’s byte
+      //   length − bytesToCopy.
+      head_of_queue->byte_length =
+          base::CheckSub(head_of_queue->byte_length, bytes_to_copy)
+              .ValueOrDie();
+    }
+    // g. Set controller.[[queueTotalSize]] to controller.[[queueTotalSize]] −
+    // bytesToCopy.
+    controller->queue_total_size_ =
+        base::CheckSub(controller->queue_total_size_, bytes_to_copy)
+            .ValueOrDie();
+    // h. Perform !
+    // ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller,
+    // bytesToCopy, pullIntoDescriptor).
+    FillHeadPullIntoDescriptor(controller, bytes_to_copy, pull_into_descriptor);
+    // i. Set totalBytesToCopyRemaining to totalBytesToCopyRemaining −
+    // bytesToCopy.
+    // This subtraction will not underflow because bytes_to_copy will always be
+    // greater than or equal to total_bytes_to_copy_remaining.
+    total_bytes_to_copy_remaining -= bytes_to_copy;
+  }
+  // 11. If ready is false,
+  if (!ready) {
+    // a. Assert: controller.[[queueTotalSize]] is 0.
+    DCHECK_EQ(controller->queue_total_size_, 0u);
+    // b. Assert: pullIntoDescriptor’s bytes filled > 0.
+    DCHECK_GT(pull_into_descriptor->bytes_filled, 0.0);
+    // c. Assert: pullIntoDescriptor’s bytes filled < pullIntoDescriptor’s
+    // element size.
+    DCHECK_LT(pull_into_descriptor->bytes_filled,
+              pull_into_descriptor->element_size);
+  }
+  // 12. Return ready.
+  return ready;
+}
+
+void ReadableByteStreamController::PullInto(
+    ScriptState* script_state,
+    ReadableByteStreamController* controller,
+    NotShared<DOMArrayBufferView> view,
+    ReadableStreamBYOBReader::ReadIntoRequest* read_into_request,
+    ExceptionState& exception_state) {
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-pull-into
+  // 1. Let stream be controller.[[stream]].
+  ReadableStream* const stream = controller->controlled_readable_stream_;
+  // 2. Let elementSize be 1.
+  size_t element_size = 1;
+  // 3. Let ctor be %DataView%.
+  auto* ctor = &CreateAsArrayBufferView<DOMDataView>;
+  // 4. If view has a [[TypedArrayName]] internal slot (i.e., it is not a
+  // DataView),
+  if (view->GetType() != DOMArrayBufferView::kTypeDataView) {
+    //   a. Set elementSize to be the element size specified in the typed array
+    //   constructors table for view.[[TypedArrayName]].
+    element_size = view->TypeSize();
+    //   b. Set ctor to the constructor specified in the typed array
+    //   constructors table for view.[[TypedArrayName]].
+    switch (view->GetType()) {
+      case DOMArrayBufferView::kTypeInt8:
+        ctor = &CreateAsArrayBufferView<DOMInt8Array>;
+        break;
+      case DOMArrayBufferView::kTypeUint8:
+        ctor = &CreateAsArrayBufferView<DOMUint8Array>;
+        break;
+      case DOMArrayBufferView::kTypeUint8Clamped:
+        ctor = &CreateAsArrayBufferView<DOMUint8ClampedArray>;
+        break;
+      case DOMArrayBufferView::kTypeInt16:
+        ctor = &CreateAsArrayBufferView<DOMInt16Array>;
+        break;
+      case DOMArrayBufferView::kTypeUint16:
+        ctor = &CreateAsArrayBufferView<DOMUint16Array>;
+        break;
+      case DOMArrayBufferView::kTypeInt32:
+        ctor = &CreateAsArrayBufferView<DOMInt32Array>;
+        break;
+      case DOMArrayBufferView::kTypeUint32:
+        ctor = &CreateAsArrayBufferView<DOMUint32Array>;
+        break;
+      case DOMArrayBufferView::kTypeFloat32:
+        ctor = &CreateAsArrayBufferView<DOMFloat32Array>;
+        break;
+      case DOMArrayBufferView::kTypeFloat64:
+        ctor = &CreateAsArrayBufferView<DOMFloat64Array>;
+        break;
+      case DOMArrayBufferView::kTypeBigInt64:
+        ctor = &CreateAsArrayBufferView<DOMBigInt64Array>;
+        break;
+      case DOMArrayBufferView::kTypeBigUint64:
+        ctor = &CreateAsArrayBufferView<DOMBigUint64Array>;
+        break;
+      case DOMArrayBufferView::kTypeDataView:
+        NOTREACHED();
+    }
+  }
+  // 5. Let byteOffset be view.[[ByteOffset]].
+  const size_t byte_offset = view->byteOffset();
+  // 6. Let byteLength be view.[[ByteLength]].
+  const size_t byte_length = view->byteLength();
+  // 7. Let buffer be ! TransferArrayBuffer(view.[[ViewedArrayBuffer]]).
+  DOMArrayBuffer* buffer =
+      TransferArrayBuffer(script_state, view->buffer(), exception_state);
+  // 8. Let pullIntoDescriptor be a new pull-into descriptor with buffer buffer,
+  // byte offset byteOffset, byte length byteLength, bytes filled 0, element
+  // size elementSize, view construcot ctor, and reader type "byob".
+  PullIntoDescriptor* pull_into_descriptor =
+      MakeGarbageCollected<PullIntoDescriptor>(buffer, byte_offset, byte_length,
+                                               0, element_size, ctor,
+                                               ReaderType::kBYOB);
+  // 9. If controller.[[pendingPullIntos]] is not empty,
+  if (!controller->pending_pull_intos_.IsEmpty()) {
+    //   a. Append pullIntoDescriptor to controller.[[pendingPullIntos]].
+    controller->pending_pull_intos_.push_back(pull_into_descriptor);
+    //   b. Perform ! ReadableStreamAddReadIntoRequest(stream, readIntoRequest).
+    ReadableStream::AddReadIntoRequest(script_state, stream, read_into_request);
+    //   c. Return.
+    return;
+  }
+  // 10. If stream.[[state]] is "closed",
+  if (stream->state_ == ReadableStream::kClosed) {
+    //   a. Let emptyView be ! Construct(ctor, « pullIntoDescriptor’s buffer,
+    //   pullIntoDescriptor’s byte offset, 0 »).
+    DOMArrayBufferView* emptyView = ctor(pull_into_descriptor->buffer,
+                                         pull_into_descriptor->byte_offset, 0);
+    //   b. Perform readIntoRequest’s close steps, given emptyView.
+    read_into_request->CloseSteps(script_state, emptyView);
+    //   c. Return.
+    return;
+  }
+  // 11. If controller.[[queueTotalSize]] > 0,
+  if (controller->queue_total_size_ > 0) {
+    //   a. If !
+    //   ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller,
+    //   pullIntoDescriptor) is true,
+    if (FillPullIntoDescriptorFromQueue(controller, pull_into_descriptor)) {
+      //     i. Let filledView be !
+      //     ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor).
+      DOMArrayBufferView* filled_view =
+          ConvertPullIntoDescriptor(pull_into_descriptor);
+      //     ii. Perform !
+      //     ReadableByteStreamControllerHandleQueueDrain(controller).
+      HandleQueueDrain(script_state, controller);
+      //     iii. Perform readIntoRequest’s chunk steps, given filledView.
+      read_into_request->ChunkSteps(script_state, filled_view);
+      //     iv. Return.
+      return;
+    }
+    //   b. If controller.[[closeRequested]] is true,
+    if (controller->close_requested_) {
+      //     i. Let e be a TypeError exception.
+      v8::Local<v8::Value> e = V8ThrowException::CreateTypeError(
+          script_state->GetIsolate(), "close requested");
+      //     ii. Perform ! ReadableByteStreamControllerError(controller, e).
+      controller->Error(script_state, controller, e);
+      //     iii. Perform readIntoRequest’s error steps, given e.
+      read_into_request->ErrorSteps(script_state, e);
+      //     iv. Return.
+      return;
+    }
+  }
+  // 12. Append pullIntoDescriptor to controller.[[pendingPullIntos]].
+  controller->pending_pull_intos_.push_back(pull_into_descriptor);
+  // 13. Perform ! ReadableStreamAddReadIntoRequest(stream, readIntoRequest).
+  ReadableStream::AddReadIntoRequest(script_state, stream, read_into_request);
+  // 14. Perform ! ReadableByteStreamControllerCallPullIfNeeded(controller).
+  CallPullIfNeeded(script_state, controller);
+}
+
+void ReadableByteStreamController::HandleQueueDrain(
+    ScriptState* script_state,
+    ReadableByteStreamController* controller) {
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-handle-queue-drain
+  // 1. Assert: controller.[[stream]].[[state]] is "readable".
+  DCHECK_EQ(controller->controlled_readable_stream_->state_,
+            ReadableStream::kReadable);
+  // 2. If controller.[[queueTotalSize]] is 0 and controller.[[closeRequested]]
+  // is true,
+  if (!controller->queue_total_size_ && controller->close_requested_) {
+    //   a. Perform ! ReadableByteStreamControllerClearAlgorithms(controller).
+    ClearAlgorithms(controller);
+    //   b. Perform ! ReadableStreamClose(controller.[[stream]]).
+    ReadableStream::Close(script_state,
+                          controller->controlled_readable_stream_);
+  } else {
+    // 3. Otherwise,
+    //   a. Perform ! ReadableByteStreamControllerCallPullIfNeeded(controller).
+    CallPullIfNeeded(script_state, controller);
+  }
+}
+
+void ReadableByteStreamController::ResetQueue(
+    ReadableByteStreamController* controller) {
+  // https://streams.spec.whatwg.org/#reset-queue
+  // 1. Assert: container has [[queue]] and [[queueTotalSize]] internal slots.
+  // 2. Set container.[[queue]] to a new empty list.
+  controller->queue_.clear();
+  // 3. Set container.[[queueTotalSize]] to 0.
+  controller->queue_total_size_ = 0;
+}
+
+void ReadableByteStreamController::Respond(
+    ScriptState* script_state,
+    ReadableByteStreamController* controller,
+    size_t bytes_written,
+    ExceptionState& exception_state) {
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond
+  // 1. Assert: controller.[[pendingPullIntos]] is not empty.
+  DCHECK(!controller->pending_pull_intos_.IsEmpty());
+  // 2. Perform ? ReadableByteStreamControllerRespondInternal(controller,
+  // bytesWritten).
+  RespondInternal(script_state, controller, bytes_written, exception_state);
+}
+
+void ReadableByteStreamController::RespondInClosedState(
+    ScriptState* script_state,
+    ReadableByteStreamController* controller,
+    PullIntoDescriptor* first_descriptor,
+    ExceptionState& exception_state) {
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-in-closed-state
+  // 1. Set firstDescriptor’s buffer to ! TransferArrayBuffer(firstDescriptor’s
+  // buffer).
+  first_descriptor->buffer = TransferArrayBuffer(
+      script_state, first_descriptor->buffer, exception_state);
+  // 2. Assert: firstDescriptor’s bytes filled is 0.
+  DCHECK_EQ(first_descriptor->bytes_filled, 0u);
+  // 3. Let stream be controller.[[stream]].
+  ReadableStream* const stream = controller->controlled_readable_stream_;
+  // 4. If ! ReadableStreamHasBYOBReader(stream) is true,
+  if (ReadableStream::HasBYOBReader(stream)) {
+    //   a. While ! ReadableStreamGetNumReadIntoRequests(stream) > 0,
+    while (ReadableStream::GetNumReadIntoRequests(stream) > 0) {
+      //     i. Let pullIntoDescriptor be !
+      //     ReadableByteStreamControllerShiftPendingPullInto(controller).
+      PullIntoDescriptor* pull_into_descriptor =
+          ShiftPendingPullInto(controller);
+      //     ii. Perform !
+      //     ReadableByteStreamControllerCommitPullIntoDescriptor(stream,
+      //     pullIntoDescriptor).
+      CommitPullIntoDescriptor(script_state, stream, pull_into_descriptor);
+    }
+  }
+}
+
+void ReadableByteStreamController::RespondInReadableState(
+    ScriptState* script_state,
+    ReadableByteStreamController* controller,
+    size_t bytes_written,
+    PullIntoDescriptor* pull_into_descriptor,
+    ExceptionState& exception_state) {
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-in-readable-state
+  // 1. If pullIntoDescriptor’s bytes filled + bytesWritten >
+  // pullIntoDescriptor’s byte length, throw a RangeError exception.
+  if (base::ClampAdd(pull_into_descriptor->bytes_filled, bytes_written) >
+      pull_into_descriptor->byte_length) {
+    exception_state.ThrowRangeError(
+        "Cannot respond because buffer will overflow if written to");
+    return;
+  }
+  // 2. Perform !
+  // ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller,
+  // bytesWritten, pullIntoDescriptor).
+  FillHeadPullIntoDescriptor(controller, bytes_written, pull_into_descriptor);
+  // 3. If pullIntoDescriptor’s bytes filled < pullIntoDescriptor’s element
+  // size, return.
+  if (pull_into_descriptor->bytes_filled < pull_into_descriptor->element_size) {
+    return;
+  }
+  // 4. Perform ! ReadableByteStreamControllerShiftPendingPullInto(controller).
+  ShiftPendingPullInto(controller);
+  // 5. Let remainderSize be pullIntoDescriptor’s bytes filled mod
+  // pullIntoDescriptor’s element size.
+  const size_t remainder_size =
+      pull_into_descriptor->bytes_filled % pull_into_descriptor->element_size;
+  // 6. If remainderSize > 0,
+  if (remainder_size > 0) {
+    //   a. Let end be pullIntoDescriptor’s byte offset + pullIntoDescriptor’s
+    //   bytes filled.
+    //   This addition will not overflow because byte offset and bytes filled
+    //   refer to actually allocated memory, so together they cannot exceed
+    //   size_t.
+    size_t end =
+        pull_into_descriptor->byte_offset + pull_into_descriptor->bytes_filled;
+    //   b. Let remainder be ? CloneArrayBuffer(pullIntoDescriptor’s
+    //   buffer, end − remainderSize, remainderSize, %ArrayBuffer%).
+    DOMArrayBuffer* const remainder = DOMArrayBuffer::Create(
+        static_cast<char*>(pull_into_descriptor->buffer->Data()) + end -
+            remainder_size,
+        remainder_size);
+    //   c. Perform !
+    //   ReadableByteStreamControllerEnqueueChunkToQueue(controller, remainder,
+    //   0, remainder.[[ByteLength]]).
+    EnqueueChunkToQueue(controller, remainder, 0, remainder->ByteLength());
+  }
+  // 7. Set pullIntoDescriptor’s buffer to !
+  // TransferArrayBuffer(pullIntoDescriptor’s buffer).
+  pull_into_descriptor->buffer = TransferArrayBuffer(
+      script_state, pull_into_descriptor->buffer, exception_state);
+  // 8. Set pullIntoDescriptor’s bytes filled to pullIntoDescriptor’s bytes
+  // filled − remainderSize.
+  pull_into_descriptor->bytes_filled =
+      pull_into_descriptor->bytes_filled - remainder_size;
+  // 9. Perform !
+  // ReadableByteStreamControllerCommitPullIntoDescriptor(controller.[[stream]],
+  // pullIntoDescriptor).
+  CommitPullIntoDescriptor(script_state,
+                           controller->controlled_readable_stream_,
+                           pull_into_descriptor);
+  // 10. Perform !
+  // ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller).
+  ProcessPullIntoDescriptorsUsingQueue(script_state, controller);
+}
+
+void ReadableByteStreamController::RespondInternal(
+    ScriptState* script_state,
+    ReadableByteStreamController* controller,
+    size_t bytes_written,
+    ExceptionState& exception_state) {
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-internal
+  // 1. Let firstDescriptor be controller.[[pendingPullIntos]][0].
+  PullIntoDescriptor* const first_descriptor =
+      controller->pending_pull_intos_[0];
+  // 2. Let state be controller.[[stream]].[[state]].
+  const ReadableStream::State state =
+      controller->controlled_readable_stream_->state_;
+  // 3. If state is "closed",
+  if (state == ReadableStream::kClosed) {
+    //   a. If bytesWritten is not 0, throw a TypeError exception.
+    if (bytes_written != 0) {
+      exception_state.ThrowTypeError("bytes written is not 0");
+      return;
+    }
+    //   b. Perform !
+    //   ReadableByteStreamControllerRespondInClosedState(controller,
+    //   firstDescriptor).
+    RespondInClosedState(script_state, controller, first_descriptor,
+                         exception_state);
+  } else {
+    // 4. Otherwise,
+    //   a. Assert: state is "readable".
+    DCHECK_EQ(state, ReadableStream::kReadable);
+    //   b. Perform ?
+    //   ReadableByteStreamControllerRespondInReadableState(controller,
+    //   bytesWritten, firstDescriptor).
+    RespondInReadableState(script_state, controller, bytes_written,
+                           first_descriptor, exception_state);
+  }
+  // 5. Perform ! ReadableByteStreamControllerCallPullIfNeeded(controller).
+  CallPullIfNeeded(script_state, controller);
+}
+
+void ReadableByteStreamController::RespondWithNewView(
+    ScriptState* script_state,
+    ReadableByteStreamController* controller,
+    NotShared<DOMArrayBufferView> view,
+    ExceptionState& exception_state) {
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-with-new-view
+  // 1. Assert: controller.[[pendingPullIntos]] is not empty.
+  DCHECK(!controller->pending_pull_intos_.IsEmpty());
+  // 2. Let firstDescriptor be controller.[[pendingPullIntos]][0].
+  PullIntoDescriptor* first_descriptor = controller->pending_pull_intos_[0];
+  // 3. If firstDescriptor’s byte offset + firstDescriptor’ bytes filled is not
+  // view.[[ByteOffset]], throw a RangeError exception.
+  // We don't expect this addition to overflow as the bytes are expected to be
+  // equal.
+  if (first_descriptor->byte_offset + first_descriptor->bytes_filled !=
+      view->byteOffset()) {
+    exception_state.ThrowRangeError(
+        "First descriptor's byte offset and bytes filled is not the same as "
+        "the view's byte offset");
+    return;
+  }
+  // 4. If firstDescriptor’s byte length is not view.[[ByteLength]], throw a
+  // RangeError exception.
+  if (first_descriptor->byte_length != view->byteLength()) {
+    exception_state.ThrowRangeError("byte lengths are not equal");
+    return;
+  }
+  // 5. Set firstDescriptor’s buffer to view.[[ViewedArrayBuffer]].
+  first_descriptor->buffer = view->buffer();
+  // 6. Perform ? ReadableByteStreamControllerRespondInternal(controller,
+  // view.[[ByteLength]]).
+  RespondInternal(script_state, controller, view->byteLength(),
+                  exception_state);
+}
+
+DOMArrayBuffer* ReadableByteStreamController::TransferArrayBuffer(
+    ScriptState* script_state,
+    DOMArrayBuffer* buffer,
+    ExceptionState& exception_state) {
+  ArrayBufferContents contents;
+  if (buffer->IsDetachable(script_state->GetIsolate()) &&
+      buffer->Transfer(script_state->GetIsolate(), contents)) {
+    return DOMArrayBuffer::Create(std::move(contents));
+  }
+  exception_state.ThrowTypeError("not able to transfer array buffer");
+  return nullptr;
+}
+
+void ReadableByteStreamController::Trace(Visitor* visitor) const {
+  visitor->Trace(byob_request_);
+  visitor->Trace(cancel_algorithm_);
+  visitor->Trace(controlled_readable_stream_);
+  visitor->Trace(pending_pull_intos_);
+  visitor->Trace(pull_algorithm_);
+  visitor->Trace(queue_);
+  ScriptWrappable::Trace(visitor);
 }
 
 //
@@ -58,25 +1313,95 @@
 v8::Local<v8::Promise> ReadableByteStreamController::CancelSteps(
     ScriptState* script_state,
     v8::Local<v8::Value> reason) {
-  ExceptionState exception_state(script_state->GetIsolate(),
-                                 ExceptionState::kExecutionContext, nullptr,
-                                 nullptr);
-  ThrowUnimplemented(exception_state);
-  return v8::Local<v8::Promise>();
+  // https://streams.spec.whatwg.org/#rbs-controller-private-cancel
+  // 1. If this.[[pendingPullIntos]] is not empty,
+  if (!pending_pull_intos_.IsEmpty()) {
+    //   a. Let firstDescriptor be this.[[pendingPullIntos]][0].
+    PullIntoDescriptor* first_descriptor = pending_pull_intos_[0];
+    //   b. Set firstDescriptor’s bytes filled to 0.
+    first_descriptor->bytes_filled = 0;
+  }
+  // 2. Perform ! ResetQueue(this).
+  ResetQueue(this);
+  // 3. Let result be the result of performing this.[[cancelAlgorithm]], passing
+  // in reason.
+  auto result = cancel_algorithm_->Run(script_state, 1, &reason);
+  // 4. Perform ! ReadableByteStreamControllerClearAlgorithms(this).
+  ClearAlgorithms(this);
+  // 5. Return result.
+  return result;
 }
 
 StreamPromiseResolver* ReadableByteStreamController::PullSteps(
     ScriptState* script_state) {
-  ExceptionState exception_state(script_state->GetIsolate(),
-                                 ExceptionState::kExecutionContext, nullptr,
-                                 nullptr);
-  ThrowUnimplemented(exception_state);
-  return nullptr;
-}
+  // https://whatpr.org/streams/1029.html#rbs-controller-private-pull
+  // TODO: This function follows an old version of the spec referenced above, so
+  // it needs to be updated to the new version on
+  // https://streams.spec.whatwg.org when the ReadableStreamDefaultReader
+  // implementation is updated.
+  // 1. Let stream be this.[[controlledReadableByteStream]].
+  ReadableStream* const stream = controlled_readable_stream_;
+  // 2. Assert: ! ReadableStreamHasDefaultReader(stream) is true.
+  DCHECK(ReadableStream::HasDefaultReader(stream));
+  // 3. If this.[[queueTotalSize]] > 0,
+  if (queue_total_size_ > 0) {
+    //   a. Assert: ! ReadableStreamGetNumReadRequests(stream) is 0.
+    DCHECK_EQ(ReadableStream::GetNumReadRequests(stream), 0);
+    //   b. Let entry be the first element of this.[[queue]].
+    QueueEntry* entry = queue_[0];
+    //   c. Remove entry from this.[[queue]], shifting all other elements
+    //   downward (so that the second becomes the first, and so on).
+    queue_.pop_front();
+    //   d. Set this.[[queueTotalSize]] to this.[[queueTotalSize]] −
+    //   entry.[[byteLength]].
+    queue_total_size_ -= entry->byte_length;
+    //   e. Perform ! ReadableByteStreamControllerHandleQueueDrain(this).
+    HandleQueueDrain(script_state, this);
+    //   f. Let view be ! Construct(%Uint8Array%, « entry.[[buffer]],
+    //   entry.[[byteOffset]], entry.[[byteLength]] »).
+    DOMUint8Array* view = DOMUint8Array::Create(
+        entry->buffer, entry->byte_offset, entry->byte_length);
+    //   g. Return a promise resolved with !
+    //   ReadableStreamCreateReadResult(view, false,
+    //   stream.[[reader]].[[forAuthorCode]]).
+    ReadableStreamGenericReader* reader = stream->reader_;
+    return StreamPromiseResolver::CreateResolved(
+        script_state,
+        ReadableStream::CreateReadResult(
+            script_state, ToV8(view, script_state), false,
+            To<ReadableStreamDefaultReader>(reader)->for_author_code_));
+  }
+  // 4. Let autoAllocateChunkSize be this.[[autoAllocateChunkSize]].
+  const size_t auto_allocate_chunk_size = auto_allocate_chunk_size_;
+  // 5. If autoAllocateChunkSize is not undefined,
+  if (auto_allocate_chunk_size) {
+    //   a. Let buffer be Construct(%ArrayBuffer%, « autoAllocateChunkSize »).
+    auto* buffer = DOMArrayBuffer::Create(auto_allocate_chunk_size, 1);
+    //   b. If buffer is an abrupt completion, return a promise rejected with
+    //   buffer.[[Value]].
+    //   This is not needed as DOMArrayBuffer::Create() is designed to
+    //   crash if it cannot allocate the memory.
 
-void ReadableByteStreamController::ThrowUnimplemented(
-    ExceptionState& exception_state) {
-  exception_state.ThrowTypeError("unimplemented");
+    //   c. Let pullIntoDescriptor be Record {[[buffer]]: buffer.[[Value]],
+    //   [[byteOffset]]: 0, [[byteLength]]: autoAllocateChunkSize,
+    //   [[bytesFilled]]: 0, [[elementSize]]: 1, [[ctor]]: %Uint8Array%,
+    //   [[readerType]]: "default"}.
+    auto* ctor = &CreateAsArrayBufferView<DOMUint8Array>;
+    PullIntoDescriptor* pull_into_descriptor =
+        MakeGarbageCollected<PullIntoDescriptor>(buffer, 0,
+                                                 auto_allocate_chunk_size, 0, 1,
+                                                 ctor, ReaderType::kDefault);
+    //   d. Append pullIntoDescriptor as the last element of
+    //   this.[[pendingPullIntos]].
+    pending_pull_intos_.push_back(pull_into_descriptor);
+  }
+  // 6. Let promise be ! ReadableStreamAddReadRequest(stream).
+  StreamPromiseResolver* promise =
+      ReadableStream::AddReadRequest(script_state, stream);
+  // 7. Perform ! ReadableByteStreamControllerCallPullIfNeeded(this).
+  CallPullIfNeeded(script_state, this);
+  // 8. Return promise.
+  return promise;
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/streams/readable_byte_stream_controller.h b/third_party/blink/renderer/core/streams/readable_byte_stream_controller.h
index 84d1e38..faf5fa3d 100644
--- a/third_party/blink/renderer/core/streams/readable_byte_stream_controller.h
+++ b/third_party/blink/renderer/core/streams/readable_byte_stream_controller.h
@@ -7,28 +7,40 @@
 
 #include "base/optional.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
+#include "third_party/blink/renderer/core/streams/readable_stream_byob_reader.h"
 #include "third_party/blink/renderer/core/streams/readable_stream_controller.h"
 #include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
 #include "v8/include/v8.h"
 
 namespace blink {
 
+class DOMArrayBuffer;
 class DOMArrayBufferView;
 class ExceptionState;
+class ReadableStream;
 class ReadableStreamBYOBRequest;
 class ScriptState;
+class StreamAlgorithm;
+class StreamStartAlgorithm;
 class StreamPromiseResolver;
+class UnderlyingSource;
 
 class ReadableByteStreamController : public ReadableStreamController {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
+  ReadableByteStreamController();
+
   // https://streams.spec.whatwg.org/#rbs-controller-byob-request
-  ReadableStreamBYOBRequest* byobRequest(ExceptionState&) const;
+  ReadableStreamBYOBRequest* byobRequest();
 
   // https://streams.spec.whatwg.org/#rbs-controller-desired-size
-  base::Optional<double> desiredSize(ExceptionState&) const;
+  base::Optional<double> desiredSize();
+
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-get-desired-size
+  static base::Optional<double> GetDesiredSize(ReadableByteStreamController*);
 
   // https://streams.spec.whatwg.org/#rbs-controller-close
   void close(ScriptState*, ExceptionState&);
@@ -39,8 +51,192 @@
                ExceptionState&);
 
   // https://streams.spec.whatwg.org/#rbs-controller-error
-  void error(ScriptState*, ExceptionState&);
-  void error(ScriptState*, ScriptValue e, ExceptionState&);
+  void error(ScriptState*);
+  void error(ScriptState*, const ScriptValue& e);
+
+  bool IsByteStreamController() const override { return true; }
+  bool IsDefaultController() const override { return false; }
+
+  void Trace(Visitor*) const override;
+
+ private:
+  friend class ReadableStream;
+  friend class ReadableStreamBYOBReader;
+  friend class ReadableStreamBYOBRequest;
+
+  // https://streams.spec.whatwg.org/#readable-byte-stream-queue-entry
+  struct QueueEntry final : public GarbageCollected<QueueEntry> {
+    explicit QueueEntry(DOMArrayBuffer* buffer,
+                        size_t byte_offset,
+                        size_t byte_length);
+
+    const Member<DOMArrayBuffer> buffer;
+    size_t byte_offset;
+    size_t byte_length;
+
+    void Trace(Visitor*) const;
+  };
+
+  enum class ReaderType { kDefault, kBYOB };
+
+  // https://streams.spec.whatwg.org/#pull-into-descriptor
+  struct PullIntoDescriptor final
+      : public GarbageCollected<PullIntoDescriptor> {
+    // A function pointer is used to represent the view constructor
+    // to accommodate for different array types as specified by the
+    // ArrayBufferViewConstructorAdaptor.
+    using ViewConstructorType = DOMArrayBufferView* (*)(DOMArrayBuffer*,
+                                                        size_t,
+                                                        size_t);
+
+    explicit PullIntoDescriptor(DOMArrayBuffer* buffer,
+                                size_t byte_offset,
+                                size_t byte_length,
+                                size_t bytes_filled,
+                                size_t element_size,
+                                ViewConstructorType view_constructor,
+                                ReaderType reader_type);
+
+    Member<DOMArrayBuffer> buffer;
+    size_t byte_offset;
+    const size_t byte_length;
+    size_t bytes_filled;
+    const size_t element_size;
+    const ViewConstructorType view_constructor;
+    const ReaderType reader_type;
+
+    void Trace(Visitor*) const;
+  };
+
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-close
+  void Close(ScriptState*, ReadableByteStreamController*, ExceptionState&);
+
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-error
+  static void Error(ScriptState*,
+                    ReadableByteStreamController*,
+                    v8::Local<v8::Value> e);
+
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-enqueue
+  void Enqueue(ScriptState*,
+               ReadableByteStreamController*,
+               NotShared<DOMArrayBufferView> chunk,
+               ExceptionState&);
+
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-enqueue-chunk-to-queue
+  static void EnqueueChunkToQueue(ReadableByteStreamController*,
+                                  DOMArrayBuffer*,
+                                  size_t byte_offset,
+                                  size_t byte_length);
+
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-process-pull-into-descriptors-using-queue
+  static void ProcessPullIntoDescriptorsUsingQueue(
+      ScriptState*,
+      ReadableByteStreamController*);
+
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-call-pull-if-needed
+  static void CallPullIfNeeded(ScriptState*, ReadableByteStreamController*);
+
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-shift-pending-pull-into
+  static PullIntoDescriptor* ShiftPendingPullInto(
+      ReadableByteStreamController*);
+
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-should-call-pull
+  static bool ShouldCallPull(ReadableByteStreamController*);
+
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-commit-pull-into-descriptor
+  static void CommitPullIntoDescriptor(ScriptState*,
+                                       ReadableStream*,
+                                       PullIntoDescriptor*);
+
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-convert-pull-into-descriptor
+  static DOMArrayBufferView* ConvertPullIntoDescriptor(PullIntoDescriptor*);
+
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-clear-pending-pull-intos
+  static void ClearPendingPullIntos(ReadableByteStreamController*);
+
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-clear-algorithms
+  static void ClearAlgorithms(ReadableByteStreamController*);
+
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-invalidate-byob-request
+  static void InvalidateBYOBRequest(ReadableByteStreamController*);
+
+  // https://streams.spec.whatwg.org/#set-up-readable-byte-stream-controller
+  static void SetUp(ScriptState*,
+                    ReadableStream*,
+                    ReadableByteStreamController*,
+                    StreamStartAlgorithm* start_algorithm,
+                    StreamAlgorithm* pull_algorithm,
+                    StreamAlgorithm* cancel_algorithm,
+                    double high_water_mark,
+                    size_t auto_allocate_chunk_size,
+                    ExceptionState&);
+
+  // https://streams.spec.whatwg.org/#set-up-readable-byte-stream-controller-from-underlying-source
+  static void SetUpFromUnderlyingSource(
+      ScriptState*,
+      ReadableStream*,
+      v8::Local<v8::Object> underlying_source,
+      UnderlyingSource* underlying_source_dict,
+      double high_water_mark,
+      ExceptionState&);
+
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-fill-head-pull-into-descriptor
+  static void FillHeadPullIntoDescriptor(ReadableByteStreamController*,
+                                         size_t size,
+                                         PullIntoDescriptor*);
+
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-fill-pull-into-descriptor-from-queue
+  static bool FillPullIntoDescriptorFromQueue(ReadableByteStreamController*,
+                                              PullIntoDescriptor*);
+
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-pull-into
+  static void PullInto(ScriptState*,
+                       ReadableByteStreamController*,
+                       NotShared<DOMArrayBufferView> view,
+                       ReadableStreamBYOBReader::ReadIntoRequest*,
+                       ExceptionState&);
+
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-handle-queue-drain
+  static void HandleQueueDrain(ScriptState*, ReadableByteStreamController*);
+
+  // https://streams.spec.whatwg.org/#reset-queue
+  static void ResetQueue(ReadableByteStreamController*);
+
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond
+  static void Respond(ScriptState*,
+                      ReadableByteStreamController*,
+                      size_t bytes_written,
+                      ExceptionState&);
+
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-in-closed-state
+  static void RespondInClosedState(ScriptState*,
+                                   ReadableByteStreamController*,
+                                   PullIntoDescriptor* first_descriptor,
+                                   ExceptionState&);
+
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-in-readable-state
+  static void RespondInReadableState(ScriptState*,
+                                     ReadableByteStreamController*,
+                                     size_t bytes_written,
+                                     PullIntoDescriptor*,
+                                     ExceptionState&);
+
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-internal
+  static void RespondInternal(ScriptState*,
+                              ReadableByteStreamController*,
+                              size_t bytes_written,
+                              ExceptionState&);
+
+  // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-with-new-view
+  static void RespondWithNewView(ScriptState*,
+                                 ReadableByteStreamController*,
+                                 NotShared<DOMArrayBufferView> view,
+                                 ExceptionState&);
+
+  // https://streams.spec.whatwg.org/#transfer-array-buffer
+  static DOMArrayBuffer* TransferArrayBuffer(ScriptState*,
+                                             DOMArrayBuffer* buffer,
+                                             ExceptionState&);
 
   // https://streams.spec.whatwg.org/#rbs-controller-private-cancel
   v8::Local<v8::Promise> CancelSteps(ScriptState*,
@@ -49,8 +245,27 @@
   // https://streams.spec.whatwg.org/#rbs-controller-private-pull
   StreamPromiseResolver* PullSteps(ScriptState*) override;
 
- private:
-  static void ThrowUnimplemented(ExceptionState&);
+  // autoAllocateChunkSize is encoded as 0 when it is undefined
+  size_t auto_allocate_chunk_size_ = 0u;
+  Member<ReadableStreamBYOBRequest> byob_request_;
+  Member<StreamAlgorithm> cancel_algorithm_;
+  bool close_requested_ = false;
+  bool pull_again_ = false;
+  Member<StreamAlgorithm> pull_algorithm_;
+  bool pulling_ = false;
+  HeapDeque<Member<PullIntoDescriptor>> pending_pull_intos_;
+  HeapDeque<Member<QueueEntry>> queue_;
+  double queue_total_size_;
+  bool started_ = false;
+  double strategy_high_water_mark_ = 0.0;
+  Member<ReadableStream> controlled_readable_stream_;
+};
+
+template <>
+struct DowncastTraits<ReadableByteStreamController> {
+  static bool AllowFrom(const ReadableStreamController& controller) {
+    return controller.IsByteStreamController();
+  }
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/streams/readable_byte_stream_controller.idl b/third_party/blink/renderer/core/streams/readable_byte_stream_controller.idl
index db8ac02b..1e2db3ea 100644
--- a/third_party/blink/renderer/core/streams/readable_byte_stream_controller.idl
+++ b/third_party/blink/renderer/core/streams/readable_byte_stream_controller.idl
@@ -7,10 +7,10 @@
     Exposed=(Window,Worker,Worklet),
     RuntimeEnabled=ReadableByteStream
 ] interface ReadableByteStreamController {
-    [RaisesException] readonly attribute ReadableStreamBYOBRequest? byobRequest;
-    [RaisesException] readonly attribute double? desiredSize;
+    readonly attribute ReadableStreamBYOBRequest? byobRequest;
+    readonly attribute double? desiredSize;
 
     [CallWith=ScriptState, RaisesException] void close();
     [CallWith=ScriptState, RaisesException] void enqueue(ArrayBufferView chunk);
-    [CallWith=ScriptState, RaisesException] void error(optional any e);
+    [CallWith=ScriptState] void error(optional any e);
 };
diff --git a/third_party/blink/renderer/core/streams/readable_stream.cc b/third_party/blink/renderer/core/streams/readable_stream.cc
index 5af2489..8e54f5d3 100644
--- a/third_party/blink/renderer/core/streams/readable_stream.cc
+++ b/third_party/blink/renderer/core/streams/readable_stream.cc
@@ -14,12 +14,15 @@
 #include "third_party/blink/renderer/bindings/core/v8/v8_readable_writable_pair.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_stream_pipe_options.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_underlying_source.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_writable_stream.h"
 #include "third_party/blink/renderer/core/dom/abort_signal.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/frame/web_feature.h"
 #include "third_party/blink/renderer/core/streams/miscellaneous_operations.h"
 #include "third_party/blink/renderer/core/streams/promise_handler.h"
+#include "third_party/blink/renderer/core/streams/readable_byte_stream_controller.h"
+#include "third_party/blink/renderer/core/streams/readable_stream_controller.h"
 #include "third_party/blink/renderer/core/streams/readable_stream_default_controller.h"
 #include "third_party/blink/renderer/core/streams/readable_stream_generic_reader.h"
 #include "third_party/blink/renderer/core/streams/readable_stream_transferring_optimizer.h"
@@ -39,6 +42,7 @@
 #include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/heap/visitor.h"
 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
 #include "third_party/blink/renderer/platform/wtf/deque.h"
 
@@ -1012,7 +1016,11 @@
   }
 
   for (int branch = 0; branch < 2; ++branch) {
-    controller_[branch] = branch_[branch]->readable_stream_controller_;
+    ReadableStreamController* controller =
+        branch_[branch]->readable_stream_controller_;
+    // We just created the branches above. It is obvious that the controllers
+    // are default controllers.
+    controller_[branch] = To<ReadableStreamDefaultController>(controller);
   }
 
   class RejectFunction final : public PromiseHandler {
@@ -1236,17 +1244,13 @@
     ReadableStreamDefaultReaderOrReadableStreamBYOBReader& return_value,
     ExceptionState& exception_state) {
   // https://streams.spec.whatwg.org/#rs-get-reader
-  // Since byob readers are not completely implemented yet, this function should
-  // just call the default getReader().
-  // TODO(nidhijaju): Add assertion options["mode"] is "byob" and return
-  // ? AcquireReadableStreamBYOBReader(this) according to spec, once byob
-  // readers have been implemented.
   if (options->hasMode()) {
     DCHECK_EQ(options->mode(), "byob");
-    exception_state.ThrowTypeError("byob not implemented");
-    return;
+    return_value.SetReadableStreamBYOBReader(
+        AcquireBYOBReader(script_state, this, exception_state));
+  } else {
+    getReader(script_state, return_value, exception_state);
   }
-  getReader(script_state, return_value, exception_state);
 }
 
 ReadableStreamDefaultReader* ReadableStream::GetDefaultReaderForTesting(
@@ -1407,14 +1411,35 @@
 
     // 6. If typeString is "bytes",
     if (type_string == V8AtomicString(isolate, "bytes")) {
-      // TODO(ricea): Implement bytes type.
-      exception_state.ThrowRangeError("bytes type is not yet implemented");
+      if (!RuntimeEnabledFeatures::ReadableByteStreamEnabled()) {
+        exception_state.ThrowRangeError("bytes type is not yet implemented");
+        return;
+      }
+      UnderlyingSource* underlying_source_dict = UnderlyingSource::Create();
+      V8UnderlyingSource::ToImpl(script_state->GetIsolate(),
+                                 raw_underlying_source.V8Value(),
+                                 underlying_source_dict, exception_state);
+      if (!strategy_unpacker.IsSizeUndefined()) {
+        exception_state.ThrowRangeError(
+            "Cannot create byte stream with size() defined on the strategy");
+        return;
+      }
+      double high_water_mark =
+          strategy_unpacker.GetHighWaterMark(script_state, 0, exception_state);
+      if (exception_state.HadException()) {
+        return;
+      }
+      ReadableByteStreamController::SetUpFromUnderlyingSource(
+          script_state, this, underlying_source, underlying_source_dict,
+          high_water_mark, exception_state);
       return;
     }
 
     // 8. Otherwise, throw a RangeError exception.
-    exception_state.ThrowRangeError("Invalid type is specified");
-    return;
+    else {
+      exception_state.ThrowRangeError("Invalid type is specified");
+      return;
+    }
   }
 
   // 7. Otherwise, if type is undefined,
@@ -1467,6 +1492,23 @@
   return reader;
 }
 
+ReadableStreamBYOBReader* ReadableStream::AcquireBYOBReader(
+    ScriptState* script_state,
+    ReadableStream* stream,
+    ExceptionState& exception_state) {
+  // https://streams.spec.whatwg.org/#acquire-readable-stream-byob-reader
+  // 1. Let reader be a new ReadableStreamBYOBReader.
+  // 2. Perform ? SetUpBYOBReader(reader, stream).
+  auto* reader = MakeGarbageCollected<ReadableStreamBYOBReader>(
+      script_state, stream, exception_state);
+  if (exception_state.HadException()) {
+    return nullptr;
+  }
+
+  // 3. Return reader.
+  return reader;
+}
+
 void ReadableStream::Initialize(ReadableStream* stream) {
   // Fields are initialised by the constructor, so we only check that they were
   // initialised correctly.
@@ -1611,13 +1653,28 @@
 // Abstract Operations Used By Controllers
 //
 
+void ReadableStream::AddReadIntoRequest(
+    ScriptState* script_state,
+    ReadableStream* stream,
+    ReadableStreamBYOBReader::ReadIntoRequest* readRequest) {
+  // https://streams.spec.whatwg.org/#readable-stream-add-read-into-request
+  // 1. Assert: stream.[[reader]] implements ReadableStreamBYOBReader.
+  DCHECK(stream->reader_->IsBYOBReader());
+  // 2. Assert: stream.[[state]] is "readable" or "closed".
+  DCHECK(stream->state_ == kReadable || stream->state_ == kClosed);
+  // 3. Append readRequest to stream.[[reader]].[[readIntoRequests]].
+  ReadableStreamGenericReader* reader = stream->reader_;
+  ReadableStreamBYOBReader* byob_reader = To<ReadableStreamBYOBReader>(reader);
+  byob_reader->read_into_requests_.push_back(readRequest);
+}
+
 StreamPromiseResolver* ReadableStream::AddReadRequest(ScriptState* script_state,
                                                       ReadableStream* stream) {
   // https://streams.spec.whatwg.org/#readable-stream-add-read-request
   // 1. Assert: ! IsReadableStreamDefaultReader(stream.[[reader]]) is true.
   ReadableStreamGenericReader* reader = stream->reader_;
   ReadableStreamDefaultReader* default_reader =
-      static_cast<ReadableStreamDefaultReader*>(reader);
+      To<ReadableStreamDefaultReader>(reader);
   DCHECK(default_reader);
 
   // 2. Assert: stream.[[state]] is "readable".
@@ -1699,30 +1756,28 @@
     return;
   }
 
-  // TODO(ricea): Support BYOB readers.
   // 5. If ! IsReadableStreamDefaultReader(reader) is true,
-  // TODO(nidhijaju): Add a check that the reader is a default reader once BYOB
-  // readers have been implemented, so the static_cast can be changed later on.
-  //   a. Repeat for each readRequest that is an element of reader.
-  //      [[readRequests]],
-  HeapDeque<Member<StreamPromiseResolver>> requests;
-  requests.Swap(
-      static_cast<ReadableStreamDefaultReader*>(reader)->read_requests_);
-  for (StreamPromiseResolver* promise : requests) {
-    //   i. Resolve readRequest.[[promise]] with !
-    //      ReadableStreamCreateReadResult(undefined, true, reader.
-    //      [[forAuthorCode]]).
-    promise->Resolve(
-        script_state,
-        CreateReadResult(script_state,
-                         v8::Undefined(script_state->GetIsolate()), true,
-                         static_cast<ReadableStreamDefaultReader*>(reader)
-                             ->for_author_code_));
+  if (reader->IsDefaultReader()) {
+    //   a. Repeat for each readRequest that is an element of reader.
+    //      [[readRequests]],
+    HeapDeque<Member<StreamPromiseResolver>> requests;
+    requests.Swap(To<ReadableStreamDefaultReader>(reader)->read_requests_);
+    bool for_author_code =
+        To<ReadableStreamDefaultReader>(reader)->for_author_code_;
+    for (StreamPromiseResolver* promise : requests) {
+      //   i. Resolve readRequest.[[promise]] with !
+      //      ReadableStreamCreateReadResult(undefined, true, reader.
+      //      [[forAuthorCode]]).
+      promise->Resolve(
+          script_state,
+          CreateReadResult(script_state,
+                           v8::Undefined(script_state->GetIsolate()), true,
+                           for_author_code));
+    }
+
+    //   b. Set reader.[[readRequests]] to an empty List.
+    //      This is not required since we've already called Swap().
   }
-
-  //   b. Set reader.[[readRequests]] to an empty List.
-  //      This is not required since we've already called Swap().
-
   // 6. Resolve reader.[[closedPromise]] with undefined.
   reader->closed_promise_->ResolveWithUndefined(script_state);
 }
@@ -1777,45 +1832,86 @@
                            ReadableStream* stream,
                            v8::Local<v8::Value> e) {
   // https://streams.spec.whatwg.org/#readable-stream-error
-  // 2. Assert: stream.[[state]] is "readable".
+  // 1. Assert: stream.[[state]] is "readable".
   CHECK_EQ(stream->state_, kReadable);
   auto* isolate = script_state->GetIsolate();
 
-  // 3. Set stream.[[state]] to "errored".
+  // 2. Set stream.[[state]] to "errored".
   stream->state_ = kErrored;
 
-  // 4. Set stream.[[storedError]] to e.
+  // 3. Set stream.[[storedError]] to e.
   stream->stored_error_.Set(isolate, e);
 
-  // 5. Let reader be stream.[[reader]].
+  // 4. Let reader be stream.[[reader]].
   ReadableStreamGenericReader* reader = stream->reader_;
 
-  // 6. If reader is undefined, return.
+  // 5. If reader is undefined, return.
   if (!reader) {
     return;
   }
 
-  // 7. If ! IsReadableStreamDefaultReader(reader) is true,
-  // TODO(ricea): Support BYOB readers.
+  // 6. If ! IsReadableStreamDefaultReader(reader) is true,
   //   a. Repeat for each readRequest that is an element of reader.
   //      [[readRequests]],
-  ReadableStreamDefaultReader* default_reader =
-      static_cast<ReadableStreamDefaultReader*>(reader);
-  for (StreamPromiseResolver* promise : default_reader->read_requests_) {
-    //   i. Reject readRequest.[[promise]] with e.
-    promise->Reject(script_state, e);
+  if (reader->IsDefaultReader()) {
+    ReadableStreamDefaultReader* default_reader =
+        To<ReadableStreamDefaultReader>(reader);
+    for (StreamPromiseResolver* promise : default_reader->read_requests_) {
+      //   i. Reject readRequest.[[promise]] with e.
+      promise->Reject(script_state, e);
+    }
+
+    //   b. Set reader.[[readRequests]] to a new empty List.
+    default_reader->read_requests_.clear();
   }
 
-  //   b. Set reader.[[readRequests]] to a new empty List.
-  default_reader->read_requests_.clear();
+  // 7. Otherwise,
+  else {
+    // a. Assert: reader implements ReadableStreamBYOBReader.
+    DCHECK(reader->IsBYOBReader());
+    // b. For each readIntoRequest of reader.[[readIntoRequests]],
+    ReadableStreamBYOBReader* byob_reader =
+        To<ReadableStreamBYOBReader>(reader);
+    for (ReadableStreamBYOBReader::ReadIntoRequest* request :
+         byob_reader->read_into_requests_) {
+      // i. Perform readIntoRequests' error steps, given e.
+      request->ErrorSteps(script_state, e);
+    }
+    // c. Set reader.[[readIntoRequests]] to a new empty list.
+    byob_reader->read_into_requests_.clear();
+  }
 
-  // 9. Reject reader.[[closedPromise]] with e.
+  // 8. Reject reader.[[closedPromise]] with e.
   reader->closed_promise_->Reject(script_state, e);
 
-  // 10. Set reader.[[closedPromise]].[[PromiseIsHandled]] to true.
+  // 9. Set reader.[[closedPromise]].[[PromiseIsHandled]] to true.
   reader->closed_promise_->MarkAsHandled(isolate);
 }
 
+void ReadableStream::FulfillReadIntoRequest(ScriptState* script_state,
+                                            ReadableStream* stream,
+                                            DOMArrayBufferView* chunk,
+                                            bool done) {
+  // https://streams.spec.whatwg.org/#readable-stream-fulfill-read-into-request
+  // 1. Let reader be stream.[[reader]].
+  ReadableStreamGenericReader* reader = stream->reader_;
+  ReadableStreamBYOBReader* byob_reader = To<ReadableStreamBYOBReader>(reader);
+  // 2. Assert: reader.[[readIntoRequests]] is not empty.
+  DCHECK(!byob_reader->read_into_requests_.IsEmpty());
+  // 3. Let readIntoRequest be reader.[[readIntoRequests]][0].
+  ReadableStreamBYOBReader::ReadIntoRequest* read_into_request =
+      byob_reader->read_into_requests_[0];
+  // 4. Remove readIntoRequest from reader.[[readIntoRequests]].
+  byob_reader->read_into_requests_.pop_front();
+  // 5. If done is true, perform readIntoRequest’s close steps, given chunk.
+  if (done) {
+    read_into_request->CloseSteps(script_state, chunk);
+  } else {
+    // 6. Otherwise, perform readIntoRequest’s chunk steps, given chunk.
+    read_into_request->ChunkSteps(script_state, chunk);
+  }
+}
+
 void ReadableStream::FulfillReadRequest(ScriptState* script_state,
                                         ReadableStream* stream,
                                         v8::Local<v8::Value> chunk,
@@ -1824,7 +1920,7 @@
   // 1. Let reader be stream.[[reader]].
   ReadableStreamGenericReader* reader = stream->reader_;
   ReadableStreamDefaultReader* default_reader =
-      static_cast<ReadableStreamDefaultReader*>(reader);
+      To<ReadableStreamDefaultReader>(reader);
 
   // 2. Let readRequest be the first element of reader.[[readRequests]].
   StreamPromiseResolver* read_request = default_reader->read_requests_.front();
@@ -1841,12 +1937,48 @@
                                           default_reader->for_author_code_));
 }
 
+int ReadableStream::GetNumReadIntoRequests(const ReadableStream* stream) {
+  // https://streams.spec.whatwg.org/#readable-stream-get-num-read-into-requests
+  // 1. Return stream.[[reader]].[[readIntoRequests]]'s size.
+  ReadableStreamGenericReader* reader = stream->reader_;
+  return To<ReadableStreamBYOBReader>(reader)->read_into_requests_.size();
+}
+
 int ReadableStream::GetNumReadRequests(const ReadableStream* stream) {
   // https://streams.spec.whatwg.org/#readable-stream-get-num-read-requests
   // 1. Return the number of elements in stream.[[reader]].[[readRequests]].
   ReadableStreamGenericReader* reader = stream->reader_;
-  return static_cast<ReadableStreamDefaultReader*>(reader)
-      ->read_requests_.size();
+  return To<ReadableStreamDefaultReader>(reader)->read_requests_.size();
+}
+
+bool ReadableStream::HasBYOBReader(const ReadableStream* stream) {
+  // https://streams.spec.whatwg.org/#readable-stream-has-byob-reader
+  // 1. Let reader be stream.[[reader]].
+  ReadableStreamGenericReader* reader = stream->reader_;
+
+  // 2. If reader is undefined, return false.
+  if (!reader) {
+    return false;
+  }
+
+  // 3. If reader implements ReadableStreamBYOBReader, return true.
+  // 4. Return false.
+  return reader->IsBYOBReader();
+}
+
+bool ReadableStream::HasDefaultReader(const ReadableStream* stream) {
+  // https://streams.spec.whatwg.org/#readable-stream-has-default-reader
+  // 1. Let reader be stream.[[reader]].
+  ReadableStreamGenericReader* reader = stream->reader_;
+
+  // 2. If reader is undefined, return false.
+  if (!reader) {
+    return false;
+  }
+
+  // 3. If reader implements ReadableStreamDefaultReader, return true.
+  // 4. Return false.
+  return reader->IsDefaultReader();
 }
 
 //
diff --git a/third_party/blink/renderer/core/streams/readable_stream.h b/third_party/blink/renderer/core/streams/readable_stream.h
index f64038c..7bf0f04 100644
--- a/third_party/blink/renderer/core/streams/readable_stream.h
+++ b/third_party/blink/renderer/core/streams/readable_stream.h
@@ -10,6 +10,7 @@
 
 #include "base/optional.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
+#include "third_party/blink/renderer/core/streams/readable_stream_byob_reader.h"
 #include "third_party/blink/renderer/core/streams/readable_stream_default_reader.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
@@ -21,6 +22,8 @@
 class AbortSignal;
 class ExceptionState;
 class MessagePort;
+class ReadableByteStreamController;
+class ReadableStreamController;
 class ReadableStreamDefaultController;
 class ReadableStreamDefaultReaderOrReadableStreamBYOBReader;
 class ReadableStreamGetReaderOptions;
@@ -211,6 +214,11 @@
                                                            bool for_author_code,
                                                            ExceptionState&);
 
+  // https://streams.spec.whatwg.org/#acquire-readable-stream-byob-reader
+  static ReadableStreamBYOBReader* AcquireBYOBReader(ScriptState*,
+                                                     ReadableStream*,
+                                                     ExceptionState&);
+
   //
   // Functions exported for use by TransformStream. Not part of the standard.
   //
@@ -227,7 +235,7 @@
     return stream->state_ == kErrored;
   }
 
-  ReadableStreamDefaultController* GetController() {
+  ReadableStreamController* GetController() {
     return readable_stream_controller_;
   }
 
@@ -239,6 +247,8 @@
   void Trace(Visitor*) const override;
 
  private:
+  friend class ReadableByteStreamController;
+  friend class ReadableStreamBYOBReader;
   friend class ReadableStreamDefaultController;
   friend class ReadableStreamDefaultReader;
   friend class ReadableStreamGenericReader;
@@ -257,6 +267,10 @@
   // https://streams.spec.whatwg.org/#initialize-readable-stream
   static void Initialize(ReadableStream*);
 
+  static void AddReadIntoRequest(ScriptState*,
+                                 ReadableStream*,
+                                 ReadableStreamBYOBReader::ReadIntoRequest*);
+
   // https://streams.spec.whatwg.org/#readable-stream-add-read-request
   static StreamPromiseResolver* AddReadRequest(ScriptState*, ReadableStream*);
 
@@ -277,15 +291,30 @@
   // https://streams.spec.whatwg.org/#readable-stream-error
   static void Error(ScriptState*, ReadableStream*, v8::Local<v8::Value> e);
 
+  // https://streams.spec.whatwg.org/#readable-stream-fulfill-read-into-request
+  static void FulfillReadIntoRequest(ScriptState*,
+                                     ReadableStream*,
+                                     DOMArrayBufferView* chunk,
+                                     bool done);
+
   // https://streams.spec.whatwg.org/#readable-stream-fulfill-read-request
   static void FulfillReadRequest(ScriptState*,
                                  ReadableStream*,
                                  v8::Local<v8::Value> chunk,
                                  bool done);
 
+  // https://streams.spec.whatwg.org/#readable-stream-get-num-read-into-requests
+  static int GetNumReadIntoRequests(const ReadableStream*);
+
   // https://streams.spec.whatwg.org/#readable-stream-get-num-read-requests
   static int GetNumReadRequests(const ReadableStream*);
 
+  // https://streams.spec.whatwg.org/#readable-stream-has-byob-reader
+  static bool HasBYOBReader(const ReadableStream*);
+
+  // https://streams.spec.whatwg.org/#readable-stream-has-default-reader
+  static bool HasDefaultReader(const ReadableStream*);
+
   //
   // TODO(ricea): Functions for transferable streams.
   //
@@ -299,7 +328,7 @@
 
   bool is_disturbed_ = false;
   State state_ = kReadable;
-  Member<ReadableStreamDefaultController> readable_stream_controller_;
+  Member<ReadableStreamController> readable_stream_controller_;
   Member<ReadableStreamGenericReader> reader_;
   TraceWrapperV8Reference<v8::Value> stored_error_;
   std::unique_ptr<ReadableStreamTransferringOptimizer> transferring_optimizer_;
diff --git a/third_party/blink/renderer/core/streams/readable_stream.idl b/third_party/blink/renderer/core/streams/readable_stream.idl
index acb9cdf..b0bb862 100644
--- a/third_party/blink/renderer/core/streams/readable_stream.idl
+++ b/third_party/blink/renderer/core/streams/readable_stream.idl
@@ -4,8 +4,10 @@
 
 // https://streams.spec.whatwg.org/#rs-class
 typedef (ReadableStreamDefaultReader or ReadableStreamBYOBReader) ReadableStreamReader;
+typedef (ReadableStreamDefaultController or ReadableByteStreamController) ReadableStreamController;
 
 enum ReadableStreamReaderMode { "byob" };
+enum ReadableStreamType { "bytes" };
 
 [
     Exposed=(Window,Worker,Worklet)
diff --git a/third_party/blink/renderer/core/streams/readable_stream_byob_reader.cc b/third_party/blink/renderer/core/streams/readable_stream_byob_reader.cc
index f801a0d..1dba45d 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_byob_reader.cc
+++ b/third_party/blink/renderer/core/streams/readable_stream_byob_reader.cc
@@ -5,28 +5,64 @@
 #include "third_party/blink/renderer/core/streams/readable_stream_byob_reader.h"
 
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/core/streams/readable_stream.h"
+#include "third_party/blink/renderer/core/streams/readable_stream_controller.h"
 #include "third_party/blink/renderer/core/streams/stream_promise_resolver.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/bindings/to_v8.h"
 #include "third_party/blink/renderer/platform/bindings/v8_binding.h"
 
 namespace blink {
 
+ReadableStreamBYOBReader::ReadIntoRequest::ReadIntoRequest(
+    StreamPromiseResolver* resolver)
+    : resolver_(resolver) {}
+
+void ReadableStreamBYOBReader::ReadIntoRequest::ChunkSteps(
+    ScriptState* script_state,
+    DOMArrayBufferView* chunk) const {
+  resolver_->Resolve(script_state,
+                     ReadableStream::CreateReadResult(
+                         script_state, ToV8(chunk, script_state), false, true));
+}
+
+void ReadableStreamBYOBReader::ReadIntoRequest::CloseSteps(
+    ScriptState* script_state,
+    DOMArrayBufferView* chunk) const {
+  resolver_->Resolve(script_state,
+                     ReadableStream::CreateReadResult(
+                         script_state, ToV8(chunk, script_state), true, true));
+}
+
+void ReadableStreamBYOBReader::ReadIntoRequest::ErrorSteps(
+    ScriptState* script_state,
+    v8::Local<v8::Value> e) const {
+  resolver_->Reject(script_state, e);
+}
+
+void ReadableStreamBYOBReader::ReadIntoRequest::Trace(Visitor* visitor) const {
+  visitor->Trace(resolver_);
+}
+
 ReadableStreamBYOBReader* ReadableStreamBYOBReader::Create(
     ScriptState* script_state,
     ReadableStream* stream,
     ExceptionState& exception_state) {
-  ThrowUnimplemented(exception_state);
-  return nullptr;
+  auto* reader = MakeGarbageCollected<ReadableStreamBYOBReader>(
+      script_state, stream, exception_state);
+  if (exception_state.HadException()) {
+    return nullptr;
+  }
+  return reader;
 }
 
 ReadableStreamBYOBReader::ReadableStreamBYOBReader(
     ScriptState* script_state,
     ReadableStream* stream,
     ExceptionState& exception_state) {
-  ThrowUnimplemented(exception_state);
-  return;
+  SetUpBYOBReader(script_state, this, stream, exception_state);
 }
 
 ReadableStreamBYOBReader::~ReadableStreamBYOBReader() = default;
@@ -34,26 +70,135 @@
 ScriptPromise ReadableStreamBYOBReader::read(ScriptState* script_state,
                                              NotShared<DOMArrayBufferView> view,
                                              ExceptionState& exception_state) {
-  return RejectUnimplemented(script_state);
+  // https://streams.spec.whatwg.org/#byob-reader-read
+  // 1. If view.[[ByteLength]] is 0, return a promise rejected with a TypeError
+  // exception.
+  if (view->byteLength() == 0) {
+    exception_state.ThrowTypeError(
+        "This readable stream reader cannot be used to read as the view has "
+        "byte length equal to 0");
+    return ScriptPromise();
+  }
+
+  // 2. If view.[[ViewedArrayBuffer]].[[ArrayBufferByteLength]] is 0, return a
+  // promise rejected with a TypeError exception.
+  if (view->buffer()->ByteLength() == 0) {
+    exception_state.ThrowTypeError(
+        "This readable stream reader cannot be used to read as the viewed "
+        "array buffer has 0 byte length");
+    return ScriptPromise();
+  }
+
+  // 3. If this.[[stream]] is undefined, return a promise rejected with a
+  // TypeError exception.
+  if (!owner_readable_stream_) {
+    exception_state.ThrowTypeError(
+        "This readable stream reader has been released and cannot be used to "
+        "read from its previous owner stream");
+    return ScriptPromise();
+  }
+
+  // 4. Let promise be a new promise.
+  auto* promise = MakeGarbageCollected<StreamPromiseResolver>(script_state);
+
+  // 5. Let readIntoRequest be a new read-into request with the following items:
+  //    chunk steps, given chunk
+  //      1. Resolve promise with «[ "value" → chunk, "done" → false ]».
+  //    close steps, given chunk
+  //      1. Resolve promise with «[ "value" → chunk, "done" → true ]».
+  //    error steps, given e
+  //      1. Reject promise with e.
+  auto* read_into_request = MakeGarbageCollected<ReadIntoRequest>(promise);
+
+  // 6. Perform ! ReadableStreamBYOBReaderRead(this, view, readIntoRequest).
+  Read(script_state, this, view, read_into_request, exception_state);
+  // 7. Return promise.
+  return promise->GetScriptPromise(script_state);
+}
+
+void ReadableStreamBYOBReader::Read(ScriptState* script_state,
+                                    ReadableStreamBYOBReader* reader,
+                                    NotShared<DOMArrayBufferView> view,
+                                    ReadIntoRequest* read_into_request,
+                                    ExceptionState& exception_state) {
+  // https://streams.spec.whatwg.org/#readable-stream-byob-reader-read
+  // 1. Let stream be reader.[[stream]].
+  ReadableStream* stream = reader->owner_readable_stream_;
+
+  // 2. Assert: stream is not undefined.
+  DCHECK(stream);
+
+  // 3. Set stream.[[disturbed]] to true.
+  stream->is_disturbed_ = true;
+
+  // 4. If stream.[[state]] is "errored", perform readIntoRequest's error steps
+  // given stream.[[storedError]].
+  if (stream->state_ == ReadableStream::kErrored) {
+    read_into_request->ErrorSteps(
+        script_state, stream->GetStoredError(script_state->GetIsolate()));
+  } else {
+    // 5. Otherwise, perform !
+    // ReadableByteStreamControllerPullInto(stream.[[controller]], view,
+    // readIntoRequest).
+    ReadableStreamController* controller = stream->readable_stream_controller_;
+    ReadableByteStreamController::PullInto(
+        script_state, To<ReadableByteStreamController>(controller), view,
+        read_into_request, exception_state);
+  }
 }
 
 void ReadableStreamBYOBReader::releaseLock(ScriptState* script_state,
                                            ExceptionState& exception_state) {
-  ThrowUnimplemented(exception_state);
-  return;
+  // https://streams.spec.whatwg.org/#byob-reader-release-lock
+  // 1. If this.[[stream]] is undefined, return.
+  if (!owner_readable_stream_) {
+    return;
+  }
+
+  // 2. If this.[[readIntoRequests]] is not empty, throw a TypeError exception.
+  if (read_into_requests_.size() > 0) {
+    exception_state.ThrowTypeError(
+        "Cannot release a readable stream reader when it still has outstanding "
+        "read() calls that have not yet settled");
+    return;
+  }
+
+  // 3. Perform ! ReadableStreamReaderGenericRelease(this).
+  GenericRelease(script_state, this);
 }
 
-void ReadableStreamBYOBReader::ThrowUnimplemented(
+void ReadableStreamBYOBReader::SetUpBYOBReader(
+    ScriptState* script_state,
+    ReadableStreamBYOBReader* reader,
+    ReadableStream* stream,
     ExceptionState& exception_state) {
-  exception_state.ThrowTypeError("unimplemented");
+  // https://streams.spec.whatwg.org/#set-up-readable-stream-byob-reader
+  // If ! IsReadableStreamLocked(stream) is true, throw a TypeError exception.
+  if (ReadableStream::IsLocked(stream)) {
+    exception_state.ThrowTypeError(
+        "ReadableStreamBYOBReader constructor can only accept readable streams "
+        "that are not yet locked to a reader");
+    return;
+  }
+
+  // If stream.[[controller]] does not implement ReadableByteStreamController,
+  // throw a TypeError exception.
+  if (!stream->readable_stream_controller_->IsByteStreamController()) {
+    exception_state.ThrowTypeError(
+        "Cannot use a BYOB reader with a non-byte stream");
+    return;
+  }
+
+  // Perform ! ReadableStreamReaderGenericInitialize(reader, stream).
+  ReadableStreamGenericReader::GenericInitialize(script_state, reader, stream);
+
+  // Set reader.[[readIntoRequests]] to a new empty list.
+  DCHECK_EQ(reader->read_into_requests_.size(), 0u);
 }
 
-ScriptPromise ReadableStreamBYOBReader::RejectUnimplemented(
-    ScriptState* script_state) {
-  return StreamPromiseResolver::CreateRejected(
-             script_state, v8::Exception::TypeError(V8String(
-                               script_state->GetIsolate(), "unimplemented")))
-      ->GetScriptPromise(script_state);
+void ReadableStreamBYOBReader::Trace(Visitor* visitor) const {
+  visitor->Trace(read_into_requests_);
+  ReadableStreamGenericReader::Trace(visitor);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/streams/readable_stream_byob_reader.h b/third_party/blink/renderer/core/streams/readable_stream_byob_reader.h
index 1d9d421..fb7ac5b 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_byob_reader.h
+++ b/third_party/blink/renderer/core/streams/readable_stream_byob_reader.h
@@ -9,13 +9,16 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/streams/readable_stream_generic_reader.h"
 #include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
+#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
 
 namespace blink {
 
 class ExceptionState;
 class ScriptPromise;
 class ScriptState;
+class StreamPromiseResolver;
 class ReadableStream;
 class DOMArrayBufferView;
 
@@ -34,6 +37,9 @@
                            ExceptionState&);
   ~ReadableStreamBYOBReader() override;
 
+  bool IsDefaultReader() const override { return false; }
+  bool IsBYOBReader() const override { return true; }
+
   // https://streams.spec.whatwg.org/#byob-reader-read
   ScriptPromise read(ScriptState*,
                      NotShared<DOMArrayBufferView> view,
@@ -42,11 +48,51 @@
   // https://streams.spec.whatwg.org/#byob-reader-release-lock
   void releaseLock(ScriptState*, ExceptionState&);
 
+  // https://streams.spec.whatwg.org/#set-up-readable-stream-byob-reader
+  static void SetUpBYOBReader(ScriptState*,
+                              ReadableStreamBYOBReader* reader,
+                              ReadableStream* stream,
+                              ExceptionState&);
+
+  void Trace(Visitor*) const override;
+
  private:
+  friend class ReadableByteStreamController;
   friend class ReadableStream;
-  static void ThrowUnimplemented(ExceptionState&);
-  static ScriptPromise RejectUnimplemented(ScriptState*);
+
+  class ReadIntoRequest : public GarbageCollected<ReadIntoRequest> {
+   public:
+    explicit ReadIntoRequest(StreamPromiseResolver* resolver);
+
+    void ChunkSteps(ScriptState*, DOMArrayBufferView* chunk) const;
+    void CloseSteps(ScriptState*, DOMArrayBufferView* chunk) const;
+    void ErrorSteps(ScriptState*, v8::Local<v8::Value> e) const;
+
+    void Trace(Visitor*) const;
+
+   private:
+    friend class ReadableStream;
+
+    Member<StreamPromiseResolver> resolver_;
+  };
+
+  // https://streams.spec.whatwg.org/#readable-stream-byob-reader-read
+  static void Read(ScriptState*,
+                   ReadableStreamBYOBReader*,
+                   NotShared<DOMArrayBufferView> view,
+                   ReadIntoRequest*,
+                   ExceptionState&);
+
+  HeapDeque<Member<ReadIntoRequest>> read_into_requests_;
 };
+
+template <>
+struct DowncastTraits<ReadableStreamBYOBReader> {
+  static bool AllowFrom(const ReadableStreamGenericReader& reader) {
+    return reader.IsBYOBReader();
+  }
+};
+
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_READABLE_STREAM_BYOB_READER_H_
diff --git a/third_party/blink/renderer/core/streams/readable_stream_byob_request.cc b/third_party/blink/renderer/core/streams/readable_stream_byob_request.cc
index 86bf059..3c446df6 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_byob_request.cc
+++ b/third_party/blink/renderer/core/streams/readable_stream_byob_request.cc
@@ -11,30 +11,77 @@
 
 namespace blink {
 
+ReadableStreamBYOBRequest::ReadableStreamBYOBRequest(
+    ReadableByteStreamController* controller,
+    NotShared<DOMUint8Array> view)
+    : controller_(controller), view_(view) {}
+
 NotShared<DOMArrayBufferView> ReadableStreamBYOBRequest::view(
     ExceptionState& exception_state) const {
-  ThrowUnimplemented(exception_state);
-  return NotShared<DOMArrayBufferView>();
+  // https://streams.spec.whatwg.org/#rs-byob-request-view
+  // 1. Return this.[[view]].
+  return view_;
 }
 
 void ReadableStreamBYOBRequest::respond(ScriptState* script_state,
-                                        uint64_t bytesWritten,
+                                        uint64_t bytes_written,
                                         ExceptionState& exception_state) {
-  ThrowUnimplemented(exception_state);
-  return;
+  // https://streams.spec.whatwg.org/#rs-byob-request-respond
+  // 1. If this.[[controller]] is undefined, throw a TypeError exception.
+  if (!controller_) {
+    exception_state.ThrowTypeError(
+        "Cannot respond to an invalidated ReadableStreamBYOBRequest");
+    return;
+  }
+  // 2. If IsDetachedBuffer(this.[[view]].[[ArrayBuffer]]) is true, throw a
+  // TypeError exception.
+  if (view_->buffer()->IsDetached()) {
+    exception_state.ThrowTypeError("ArrayBufferView is detached");
+    return;
+  }
+  // 3. Assert: this.[[view]].[[ByteLength]] > 0.
+  DCHECK_GT(view_->byteLength(), 0u);
+  // 4. Assert: this.[[view]].[[ViewedArrayBuffer]].[[ByteLength]] > 0.
+  DCHECK_GT(view_->buffer()->ByteLength(), 0.0);
+  // 5. Perform ? ReadableByteStreamControllerRespond(this.[[controller]],
+  // bytesWritten).
+  ReadableByteStreamController::Respond(script_state, controller_,
+                                        static_cast<size_t>(bytes_written),
+                                        exception_state);
 }
 
 void ReadableStreamBYOBRequest::respondWithNewView(
     ScriptState* script_state,
     NotShared<DOMArrayBufferView> view,
     ExceptionState& exception_state) {
-  ThrowUnimplemented(exception_state);
-  return;
+  // https://streams.spec.whatwg.org/#rs-byob-request-respond-with-new-view
+  // 1. If view.[[ByteLength]] is 0, throw a TypeError exception.
+  if (view->byteLength() == 0) {
+    exception_state.ThrowTypeError("ArrayBufferView is empty");
+    return;
+  }
+  // 2. If view.[[ViewedArrayBuffer]].[[ArrayBufferByteLength]] is 0, throw a
+  // TypeError exception.
+  if (view->buffer()->ByteLength() == 0) {
+    exception_state.ThrowTypeError("ArrayBuffer is empty");
+    return;
+  }
+  // 3. If this.[[controller]] is undefined, throw a TypeError exception.
+  if (!controller_) {
+    exception_state.ThrowTypeError(
+        "Cannot respond to an invalidated ReadableStreamBYOBRequest");
+    return;
+  }
+  // 4. Return ?
+  // ReadableByteStreamControllerRespondWithNewView(this.[[controller]], view).
+  ReadableByteStreamController::RespondWithNewView(script_state, controller_,
+                                                   view, exception_state);
 }
 
-void ReadableStreamBYOBRequest::ThrowUnimplemented(
-    ExceptionState& exception_state) {
-  exception_state.ThrowTypeError("unimplemented");
+void ReadableStreamBYOBRequest::Trace(Visitor* visitor) const {
+  visitor->Trace(controller_);
+  visitor->Trace(view_);
+  ScriptWrappable::Trace(visitor);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/streams/readable_stream_byob_request.h b/third_party/blink/renderer/core/streams/readable_stream_byob_request.h
index 7f65ecaf..16304775 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_byob_request.h
+++ b/third_party/blink/renderer/core/streams/readable_stream_byob_request.h
@@ -5,6 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_READABLE_STREAM_BYOB_REQUEST_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_READABLE_STREAM_BYOB_REQUEST_H_
 
+#include "third_party/blink/renderer/core/streams/readable_byte_stream_controller.h"
 #include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 
@@ -18,19 +19,27 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
+  ReadableStreamBYOBRequest(ReadableByteStreamController*,
+                            NotShared<DOMUint8Array> view);
+
   // https://streams.spec.whatwg.org/#rs-byob-request-view
   NotShared<DOMArrayBufferView> view(ExceptionState&) const;
 
   // https://streams.spec.whatwg.org/#rs-byob-request-respond
-  void respond(ScriptState*, uint64_t bytesWritten, ExceptionState&);
+  void respond(ScriptState*, uint64_t bytes_written, ExceptionState&);
 
   // https://streams.spec.whatwg.org/#rs-byob-request-respond-with-new-view
   void respondWithNewView(ScriptState*,
                           NotShared<DOMArrayBufferView> view,
                           ExceptionState&);
 
+  void Trace(Visitor*) const override;
+
  private:
-  static void ThrowUnimplemented(ExceptionState&);
+  friend class ReadableByteStreamController;
+
+  Member<ReadableByteStreamController> controller_;
+  NotShared<DOMArrayBufferView> view_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/streams/readable_stream_controller.h b/third_party/blink/renderer/core/streams/readable_stream_controller.h
index 080c33a..8ea66c0 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_controller.h
+++ b/third_party/blink/renderer/core/streams/readable_stream_controller.h
@@ -15,6 +15,9 @@
 
 class ReadableStreamController : public ScriptWrappable {
  public:
+  virtual bool IsDefaultController() const = 0;
+  virtual bool IsByteStreamController() const = 0;
+
   // https://streams.spec.whatwg.org/#abstract-opdef-readablestreamcontroller-cancelsteps
   virtual v8::Local<v8::Promise> CancelSteps(ScriptState*,
                                              v8::Local<v8::Value> reason) = 0;
diff --git a/third_party/blink/renderer/core/streams/readable_stream_default_controller.h b/third_party/blink/renderer/core/streams/readable_stream_default_controller.h
index b96ce094..ca53eca0 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_default_controller.h
+++ b/third_party/blink/renderer/core/streams/readable_stream_default_controller.h
@@ -7,6 +7,7 @@
 
 #include "base/optional.h"
 #include "third_party/blink/renderer/core/streams/readable_stream_controller.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
 #include "v8/include/v8.h"
 
 namespace blink {
@@ -70,6 +71,9 @@
   static const char* EnqueueExceptionMessage(
       const ReadableStreamDefaultController*);
 
+  bool IsDefaultController() const override { return true; }
+  bool IsByteStreamController() const override { return false; }
+
   void Trace(Visitor*) const override;
 
   // https://streams.spec.whatwg.org/#rs-default-controller-private-cancel
@@ -125,6 +129,13 @@
   Member<StrategySizeAlgorithm> strategy_size_algorithm_;
 };
 
+template <>
+struct DowncastTraits<ReadableStreamDefaultController> {
+  static bool AllowFrom(const ReadableStreamController& controller) {
+    return controller.IsDefaultController();
+  }
+};
+
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_READABLE_STREAM_DEFAULT_CONTROLLER_H_
diff --git a/third_party/blink/renderer/core/streams/readable_stream_default_reader.h b/third_party/blink/renderer/core/streams/readable_stream_default_reader.h
index ea1f52e..5ab9f59 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_default_reader.h
+++ b/third_party/blink/renderer/core/streams/readable_stream_default_reader.h
@@ -8,8 +8,10 @@
 #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
+#include "third_party/blink/renderer/core/streams/readable_byte_stream_controller.h"
 #include "third_party/blink/renderer/core/streams/readable_stream_generic_reader.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
 
 namespace blink {
 
@@ -36,6 +38,9 @@
                               ExceptionState&);
   ~ReadableStreamDefaultReader() override;
 
+  bool IsDefaultReader() const override { return true; }
+  bool IsBYOBReader() const override { return false; }
+
   // https://streams.spec.whatwg.org/#default-reader-read
   ScriptPromise read(ScriptState*, ExceptionState&);
 
@@ -60,6 +65,7 @@
   bool HasPendingActivity() const final;
 
  private:
+  friend class ReadableByteStreamController;
   friend class ReadableStreamDefaultController;
   friend class ReadableStream;
 
@@ -67,6 +73,13 @@
   bool for_author_code_ = true;
 };
 
+template <>
+struct DowncastTraits<ReadableStreamDefaultReader> {
+  static bool AllowFrom(const ReadableStreamGenericReader& reader) {
+    return reader.IsDefaultReader();
+  }
+};
+
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_READABLE_STREAM_DEFAULT_READER_H_
diff --git a/third_party/blink/renderer/core/streams/readable_stream_generic_reader.h b/third_party/blink/renderer/core/streams/readable_stream_generic_reader.h
index 7e23844..1fe26a2b 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_generic_reader.h
+++ b/third_party/blink/renderer/core/streams/readable_stream_generic_reader.h
@@ -31,6 +31,9 @@
   ReadableStreamGenericReader();
   ~ReadableStreamGenericReader() override;
 
+  virtual bool IsDefaultReader() const = 0;
+  virtual bool IsBYOBReader() const = 0;
+
   // https://streams.spec.whatwg.org/#generic-reader-closed
   ScriptPromise closed(ScriptState*) const;
 
diff --git a/third_party/blink/renderer/core/streams/readable_stream_test.cc b/third_party/blink/renderer/core/streams/readable_stream_test.cc
index 0954a00..b592509 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_test.cc
+++ b/third_party/blink/renderer/core/streams/readable_stream_test.cc
@@ -6,15 +6,18 @@
 
 #include "base/optional.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/bindings/core/v8/readable_stream_default_reader_or_readable_stream_byob_reader.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_function.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_extras_test_utils.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_iterator_result_value.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream.h"
 #include "third_party/blink/renderer/core/messaging/message_channel.h"
 #include "third_party/blink/renderer/core/streams/readable_stream_default_controller_with_script_scope.h"
 #include "third_party/blink/renderer/core/streams/readable_stream_default_reader.h"
+#include "third_party/blink/renderer/core/streams/readable_stream_get_reader_options.h"
 #include "third_party/blink/renderer/core/streams/readable_stream_transferring_optimizer.h"
 #include "third_party/blink/renderer/core/streams/test_underlying_source.h"
 #include "third_party/blink/renderer/core/streams/underlying_source_base.h"
@@ -220,6 +223,42 @@
   EXPECT_TRUE(stream->IsDisturbed());
 }
 
+// Testing getReader with mode BYOB.
+TEST_F(ReadableStreamTest, GetBYOBReader) {
+  V8TestingScope scope;
+  ScriptState* script_state = scope.GetScriptState();
+  v8::Isolate* isolate = scope.GetIsolate();
+
+  ScriptValue byte_stream =
+      EvalWithPrintingError(&scope, "new ReadableStream({type: 'bytes'})");
+  ReadableStream* stream{
+      V8ReadableStream::ToImplWithTypeCheck(isolate, byte_stream.V8Value())};
+  ASSERT_TRUE(stream);
+
+  EXPECT_FALSE(stream->locked());
+  EXPECT_FALSE(stream->IsLocked());
+  EXPECT_FALSE(stream->IsDisturbed());
+
+  auto* options = ReadableStreamGetReaderOptions::Create();
+  options->setMode("byob");
+
+  ReadableStreamDefaultReaderOrReadableStreamBYOBReader return_value;
+  stream->getReader(script_state, options, return_value, ASSERT_NO_EXCEPTION);
+  ReadableStreamBYOBReader* reader =
+      return_value.GetAsReadableStreamBYOBReader();
+  ASSERT_TRUE(reader);
+
+  EXPECT_TRUE(stream->locked());
+  EXPECT_TRUE(stream->IsLocked());
+  EXPECT_FALSE(stream->IsDisturbed());
+
+  NotShared<DOMArrayBufferView> view =
+      NotShared<DOMUint8Array>(DOMUint8Array::Create(1));
+  reader->read(script_state, view, ASSERT_NO_EXCEPTION);
+
+  EXPECT_TRUE(stream->IsDisturbed());
+}
+
 TEST_F(ReadableStreamTest, Cancel) {
   V8TestingScope scope;
   ScriptState* script_state = scope.GetScriptState();
diff --git a/third_party/blink/renderer/core/streams/transferable_streams.cc b/third_party/blink/renderer/core/streams/transferable_streams.cc
index 5c364db..eb47b5b 100644
--- a/third_party/blink/renderer/core/streams/transferable_streams.cc
+++ b/third_party/blink/renderer/core/streams/transferable_streams.cc
@@ -946,7 +946,10 @@
     return nullptr;
   }
 
-  controller_ = stream->GetController();
+  // The stream is created right above, and the type of the source is not given,
+  // hence it is guaranteed that the controller is a
+  // ReadableStreamDefaultController.
+  controller_ = To<ReadableStreamDefaultController>(stream->GetController());
   return stream;
 }
 
diff --git a/third_party/blink/renderer/core/streams/transform_stream.cc b/third_party/blink/renderer/core/streams/transform_stream.cc
index 7b7706db..bd1659b 100644
--- a/third_party/blink/renderer/core/streams/transform_stream.cc
+++ b/third_party/blink/renderer/core/streams/transform_stream.cc
@@ -262,6 +262,13 @@
                                  WritableStream* writable)
     : readable_(readable), writable_(writable) {}
 
+ReadableStreamDefaultController* TransformStream::GetReadableController() {
+  // The type of source is not given when constructing the readable stream in
+  // TranformStream, so it is guaranteed that the controller is a
+  // ReadableStreamDefaultController.
+  return To<ReadableStreamDefaultController>(readable_->GetController());
+}
+
 void TransformStream::Trace(Visitor* visitor) const {
   visitor->Trace(backpressure_change_promise_);
   visitor->Trace(readable_);
@@ -437,7 +444,6 @@
     DCHECK_EQ(argc, 0);
     // https://streams.spec.whatwg.org/#transform-stream-default-sink-close-algorithm
     // 1. Let readable be stream.[[readable]].
-    ReadableStream* readable = stream_->readable_;
 
     // 2. Let controller be stream.[[transformStreamController]].
     TransformStreamDefaultController* controller =
@@ -453,24 +459,24 @@
 
     class ResolveFunction final : public PromiseHandlerWithValue {
      public:
-      ResolveFunction(ScriptState* script_state, ReadableStream* readable)
-          : PromiseHandlerWithValue(script_state), readable_(readable) {}
+      ResolveFunction(ScriptState* script_state, TransformStream* stream)
+          : PromiseHandlerWithValue(script_state), stream_(stream) {}
 
       v8::Local<v8::Value> CallWithLocal(v8::Local<v8::Value>) override {
         // 5. Return the result of transforming flushPromise with:
         //    a. A fulfillment handler that performs the following steps:
         //       i. If readable.[[state]] is "errored", throw
         //          readable.[[storedError]].
-        if (ReadableStream::IsErrored(readable_)) {
+        if (ReadableStream::IsErrored(stream_->readable_)) {
           // Returning a rejection is equivalent to throwing here.
-          return PromiseReject(
-              GetScriptState(),
-              readable_->GetStoredError(GetScriptState()->GetIsolate()));
+          return PromiseReject(GetScriptState(),
+                               stream_->readable_->GetStoredError(
+                                   GetScriptState()->GetIsolate()));
         }
 
         //      ii. Let readableController be
         //          readable.[[readableStreamController]].
-        auto* readable_controller = readable_->GetController();
+        auto* readable_controller = stream_->GetReadableController();
 
         //     iii. If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(
         //          readableController) is true, perform !
@@ -485,12 +491,12 @@
       }
 
       void Trace(Visitor* visitor) const override {
-        visitor->Trace(readable_);
+        visitor->Trace(stream_);
         PromiseHandlerWithValue::Trace(visitor);
       }
 
      private:
-      Member<ReadableStream> readable_;
+      Member<TransformStream> stream_;
     };
 
     class RejectFunction final : public PromiseHandlerWithValue {
@@ -522,7 +528,7 @@
     // 5. Return the result of transforming flushPromise ...
     return StreamThenPromise(
         script_state->GetContext(), flush_promise,
-        MakeGarbageCollected<ResolveFunction>(script_state, readable),
+        MakeGarbageCollected<ResolveFunction>(script_state, stream_),
         MakeGarbageCollected<RejectFunction>(script_state, stream_));
   }
 
@@ -828,9 +834,8 @@
   // https://streams.spec.whatwg.org/#transform-stream-error
   // 1. Perform ! ReadableStreamDefaultControllerError(stream.[[readable]].
   //    [[readableStreamController]], e).
-  ReadableStream* readable = stream->readable_;
   ReadableStreamDefaultController::Error(script_state,
-                                         readable->GetController(), e);
+                                         stream->GetReadableController(), e);
 
   // 2. Perform ! TransformStreamErrorWritableAndUnblockWrite(stream, e).
   ErrorWritableAndUnblockWrite(script_state, stream, e);
diff --git a/third_party/blink/renderer/core/streams/transform_stream.h b/third_party/blink/renderer/core/streams/transform_stream.h
index 1db4d3c65..56f14c3 100644
--- a/third_party/blink/renderer/core/streams/transform_stream.h
+++ b/third_party/blink/renderer/core/streams/transform_stream.h
@@ -15,6 +15,7 @@
 
 class ExceptionState;
 class ReadableStream;
+class ReadableStreamDefaultController;
 class ScriptState;
 class StrategySizeAlgorithm;
 class StreamAlgorithm;
@@ -124,6 +125,8 @@
                               TransformStream*,
                               bool backpressure);
 
+  ReadableStreamDefaultController* GetReadableController();
+
   // The [[backpressure]] internal slot from the standard is here called
   // |had_backpressure_| to conform to Blink style. The initial value is
   // *undefined* in the standard, but it is set to *true* by
diff --git a/third_party/blink/renderer/core/streams/transform_stream_default_controller.cc b/third_party/blink/renderer/core/streams/transform_stream_default_controller.cc
index fc1749b..a85ce1d 100644
--- a/third_party/blink/renderer/core/streams/transform_stream_default_controller.cc
+++ b/third_party/blink/renderer/core/streams/transform_stream_default_controller.cc
@@ -18,19 +18,29 @@
 #include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/heap/visitor.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
 
 namespace blink {
 
 TransformStreamDefaultController::TransformStreamDefaultController() = default;
 TransformStreamDefaultController::~TransformStreamDefaultController() = default;
 
+ReadableStreamDefaultController*
+TransformStreamDefaultController::GetDefaultController(
+    TransformStream* stream) {
+  // The TransformStreamDefaultController will always use a
+  // ReadableStreamDefaultController. Hence, it is safe to down-cast here.
+  return To<ReadableStreamDefaultController>(
+      stream->readable_->GetController());
+}
+
 base::Optional<double> TransformStreamDefaultController::desiredSize() const {
   // https://streams.spec.whatwg.org/#ts-default-controller-desired-size
   // 2. Let readableController be
   //    this.[[controlledTransformStream]].[[readable]].
   //    [[readableStreamController]].
   const auto* readable_controller =
-      controlled_transform_stream_->readable_->GetController();
+      GetDefaultController(controlled_transform_stream_);
 
   // 3. Return !
   //    ReadableStreamDefaultControllerGetDesiredSize(readableController).
@@ -249,7 +259,7 @@
 
   // 2. Let readableController be
   //    stream.[[readable]].[[readableStreamController]].
-  auto* readable_controller = stream->readable_->GetController();
+  auto* readable_controller = GetDefaultController(stream);
 
   // 3. If !
   //    ReadableStreamDefaultControllerCanCloseOrEnqueue(readableController) is
@@ -360,7 +370,7 @@
   // 2. Let readableController be
   //    stream.[[readable]].[[readableStreamController]].
   ReadableStreamDefaultController* readable_controller =
-      stream->readable_->GetController();
+      GetDefaultController(stream);
 
   // 3. If !
   //    ReadableStreamDefaultControllerCanCloseOrEnqueue(readableController) is
diff --git a/third_party/blink/renderer/core/streams/transform_stream_default_controller.h b/third_party/blink/renderer/core/streams/transform_stream_default_controller.h
index f4d188b1..70130dc 100644
--- a/third_party/blink/renderer/core/streams/transform_stream_default_controller.h
+++ b/third_party/blink/renderer/core/streams/transform_stream_default_controller.h
@@ -13,6 +13,7 @@
 namespace blink {
 
 class ExceptionState;
+class ReadableStreamDefaultController;
 class ScriptState;
 class StreamAlgorithm;
 class TransformStream;
@@ -82,6 +83,9 @@
   // https://streams.spec.whatwg.org/#transform-stream-default-controller-terminate
   static void Terminate(ScriptState*, TransformStreamDefaultController*);
 
+  static ReadableStreamDefaultController* GetDefaultController(
+      TransformStream*);
+
   Member<TransformStream> controlled_transform_stream_;
   Member<StreamAlgorithm> flush_algorithm_;
   Member<StreamAlgorithm> transform_algorithm_;
diff --git a/third_party/blink/renderer/core/streams/underlying_source.idl b/third_party/blink/renderer/core/streams/underlying_source.idl
new file mode 100644
index 0000000..dfc0184
--- /dev/null
+++ b/third_party/blink/renderer/core/streams/underlying_source.idl
@@ -0,0 +1,13 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://streams.spec.whatwg.org/#dictdef-underlyingsource
+
+dictionary UnderlyingSource {
+  UnderlyingSourceStartCallback start;
+  UnderlyingSourcePullCallback pull;
+  UnderlyingSourceCancelCallback cancel;
+  ReadableStreamType type;
+  [EnforceRange] unsigned long long autoAllocateChunkSize;
+};
diff --git a/third_party/blink/renderer/core/streams/underlying_source_cancel_callback.idl b/third_party/blink/renderer/core/streams/underlying_source_cancel_callback.idl
new file mode 100644
index 0000000..1b671b8
--- /dev/null
+++ b/third_party/blink/renderer/core/streams/underlying_source_cancel_callback.idl
@@ -0,0 +1,7 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://streams.spec.whatwg.org/#callbackdef-underlyingsourcecancelcallback
+
+callback UnderlyingSourceCancelCallback = Promise<void> (optional any reason);
diff --git a/third_party/blink/renderer/core/streams/underlying_source_pull_callback.idl b/third_party/blink/renderer/core/streams/underlying_source_pull_callback.idl
new file mode 100644
index 0000000..9f69e86c
--- /dev/null
+++ b/third_party/blink/renderer/core/streams/underlying_source_pull_callback.idl
@@ -0,0 +1,7 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://streams.spec.whatwg.org/#callbackdef-underlyingsourcepullcallback
+
+callback UnderlyingSourcePullCallback = Promise<void> (ReadableStreamController controller);
diff --git a/third_party/blink/renderer/core/streams/underlying_source_start_callback.idl b/third_party/blink/renderer/core/streams/underlying_source_start_callback.idl
new file mode 100644
index 0000000..e20a211d
--- /dev/null
+++ b/third_party/blink/renderer/core/streams/underlying_source_start_callback.idl
@@ -0,0 +1,7 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://streams.spec.whatwg.org/#callbackdef-underlyingsourcestartcallback
+
+callback UnderlyingSourceStartCallback = any (ReadableStreamController controller);
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h
index f8e55971..b157694 100644
--- a/third_party/blink/renderer/core/style/computed_style.h
+++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -2653,6 +2653,8 @@
     return LogicalSize(LayoutUnit(ratio.Width()), LayoutUnit(ratio.Height()));
   }
 
+  bool IsContainerForContainerQueries() const { return ContainsLayout(); }
+
  private:
   EClear Clear() const { return ClearInternal(); }
   EFloat Floating() const { return FloatingInternal(); }
diff --git a/third_party/blink/renderer/core/style/computed_style_extra_fields.json5 b/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
index d728135..3d7a04a 100644
--- a/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
+++ b/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
@@ -1037,5 +1037,12 @@
       field_group: "*",
       default_value: "false",
     },
+    {
+      name: "DependsOnContainerQueries",
+      field_template: "primitive",
+      type_name: "bool",
+      field_group: "*",
+      default_value: "false",
+    },
   ],
 }
diff --git a/third_party/blink/renderer/modules/compression/deflate_transformer.cc b/third_party/blink/renderer/modules/compression/deflate_transformer.cc
index 07d96724..91a3b416 100644
--- a/third_party/blink/renderer/modules/compression/deflate_transformer.cc
+++ b/third_party/blink/renderer/modules/compression/deflate_transformer.cc
@@ -111,6 +111,10 @@
   // Zlib treats this pointer as const, so this cast is safe.
   stream_.next_in = const_cast<uint8_t*>(start);
 
+  // enqueue() may execute JavaScript which may invalidate the input buffer. So
+  // accumulate all the output before calling enqueue().
+  HeapVector<Member<DOMUint8Array>, 1u> buffers;
+
   do {
     stream_.avail_out = out_buffer_.size();
     stream_.next_out = out_buffer_.data();
@@ -120,16 +124,21 @@
 
     wtf_size_t bytes = out_buffer_.size() - stream_.avail_out;
     if (bytes) {
-      controller->enqueue(
-          script_state_,
-          ScriptValue::From(script_state_,
-                            DOMUint8Array::Create(out_buffer_.data(), bytes)),
-          exception_state);
-      if (exception_state.HadException()) {
-        return;
-      }
+      buffers.push_back(DOMUint8Array::Create(out_buffer_.data(), bytes));
     }
   } while (stream_.avail_out == 0);
+
+  DCHECK_EQ(stream_.avail_in, 0u);
+
+  // JavaScript may be executed inside this loop, however it is safe because
+  // |buffers| is a local variable that JavaScript cannot modify.
+  for (DOMUint8Array* buffer : buffers) {
+    controller->enqueue(script_state_, ScriptValue::From(script_state_, buffer),
+                        exception_state);
+    if (exception_state.HadException()) {
+      return;
+    }
+  }
 }
 
 void DeflateTransformer::Trace(Visitor* visitor) const {
diff --git a/third_party/blink/renderer/modules/compression/inflate_transformer.cc b/third_party/blink/renderer/modules/compression/inflate_transformer.cc
index 11ee058..fddb53b1 100644
--- a/third_party/blink/renderer/modules/compression/inflate_transformer.cc
+++ b/third_party/blink/renderer/modules/compression/inflate_transformer.cc
@@ -20,6 +20,7 @@
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/to_v8.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
 #include "v8/include/v8.h"
 
 namespace blink {
@@ -93,11 +94,15 @@
     TransformStreamDefaultController* controller,
     ExceptionState& exception_state) {
   DCHECK(!was_flush_called_);
+  was_flush_called_ = true;
   Inflate(nullptr, 0u, IsFinished(true), controller, exception_state);
   inflateEnd(&stream_);
-  was_flush_called_ = true;
   out_buffer_.clear();
 
+  if (exception_state.HadException()) {
+    return ScriptPromise();
+  }
+
   if (!reached_end_) {
     exception_state.ThrowTypeError("Compressed input was truncated.");
   }
@@ -121,12 +126,22 @@
   // Zlib treats this pointer as const, so this cast is safe.
   stream_.next_in = const_cast<uint8_t*>(start);
 
+  // enqueue() may execute JavaScript which may invalidate the input buffer. So
+  // accumulate all the output before calling enqueue().
+  HeapVector<Member<DOMUint8Array>, 1u> buffers;
+
   do {
     stream_.avail_out = out_buffer_.size();
     stream_.next_out = out_buffer_.data();
     const int err = inflate(&stream_, finished ? Z_FINISH : Z_NO_FLUSH);
     if (err != Z_OK && err != Z_STREAM_END && err != Z_BUF_ERROR) {
       DCHECK_NE(err, Z_STREAM_ERROR);
+
+      EnqueueBuffers(controller, std::move(buffers), exception_state);
+      if (exception_state.HadException()) {
+        return;
+      }
+
       if (err == Z_DATA_ERROR) {
         exception_state.ThrowTypeError(
             String("The compressed data was not valid: ") + stream_.msg + ".");
@@ -138,25 +153,44 @@
 
     wtf_size_t bytes = out_buffer_.size() - stream_.avail_out;
     if (bytes) {
-      controller->enqueue(
-          script_state_,
-          ScriptValue::From(script_state_,
-                            DOMUint8Array::Create(out_buffer_.data(), bytes)),
-          exception_state);
-      if (exception_state.HadException()) {
-        return;
-      }
+      buffers.push_back(DOMUint8Array::Create(out_buffer_.data(), bytes));
     }
 
     if (err == Z_STREAM_END) {
       reached_end_ = true;
-      if (stream_.next_in < start + length) {
+      const bool junk_found = stream_.avail_in > 0;
+
+      EnqueueBuffers(controller, std::move(buffers), exception_state);
+      if (exception_state.HadException()) {
+        return;
+      }
+
+      if (junk_found) {
         exception_state.ThrowTypeError(
             "Junk found after end of compressed data.");
       }
       return;
     }
   } while (stream_.avail_out == 0);
+
+  DCHECK_EQ(stream_.avail_in, 0u);
+
+  EnqueueBuffers(controller, std::move(buffers), exception_state);
+}
+
+void InflateTransformer::EnqueueBuffers(
+    TransformStreamDefaultController* controller,
+    HeapVector<Member<DOMUint8Array>, 1u> buffers,
+    ExceptionState& exception_state) {
+  // JavaScript may be executed inside this loop, however it is safe because
+  // |buffers| is a local variable that JavaScript cannot modify.
+  for (DOMUint8Array* buffer : buffers) {
+    controller->enqueue(script_state_, ScriptValue::From(script_state_, buffer),
+                        exception_state);
+    if (exception_state.HadException()) {
+      return;
+    }
+  }
 }
 
 void InflateTransformer::Trace(Visitor* visitor) const {
diff --git a/third_party/blink/renderer/modules/compression/inflate_transformer.h b/third_party/blink/renderer/modules/compression/inflate_transformer.h
index 390fce1..ac01659f 100644
--- a/third_party/blink/renderer/modules/compression/inflate_transformer.h
+++ b/third_party/blink/renderer/modules/compression/inflate_transformer.h
@@ -41,6 +41,10 @@
                TransformStreamDefaultController*,
                ExceptionState&);
 
+  void EnqueueBuffers(TransformStreamDefaultController*,
+                      HeapVector<Member<DOMUint8Array>, 1u> buffers,
+                      ExceptionState&);
+
   Member<ScriptState> script_state_;
 
   z_stream stream_;
diff --git a/third_party/blink/renderer/modules/file_system_access/global_native_file_system.cc b/third_party/blink/renderer/modules/file_system_access/global_native_file_system.cc
index 0622d1d5..10f759d 100644
--- a/third_party/blink/renderer/modules/file_system_access/global_native_file_system.cc
+++ b/third_party/blink/renderer/modules/file_system_access/global_native_file_system.cc
@@ -29,6 +29,7 @@
 #include "third_party/blink/renderer/platform/network/http_parsers.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
+#include "third_party/blink/renderer/platform/wtf/text/ascii_ctype.h"
 
 namespace blink {
 
@@ -38,14 +39,42 @@
   return chr == ' ' || chr == '\n' || chr == '\t' || chr == '\r';
 }
 
-bool AddExtension(const String& extension,
-                  Vector<String>& extensions,
-                  ExceptionState& exception_state) {
+bool IsValidSuffixCodePoint(UChar chr) {
+  return IsASCIIAlphanumeric(chr) || chr == '+' || chr == '.';
+}
+
+bool VerifyIsValidExtension(const String& extension,
+                            ExceptionState& exception_state) {
   if (!extension.StartsWith(".")) {
     exception_state.ThrowTypeError("Extension '" + extension +
                                    "' must start with '.'.");
     return false;
   }
+  if (!extension.IsAllSpecialCharacters<IsValidSuffixCodePoint>()) {
+    exception_state.ThrowTypeError("Extension '" + extension +
+                                   "' contains invalid characters.");
+    return false;
+  }
+  if (extension.EndsWith(".")) {
+    exception_state.ThrowTypeError("Extension '" + extension +
+                                   "' must not end with '.'.");
+    return false;
+  }
+  if (extension.length() > 16) {
+    exception_state.ThrowTypeError("Extension '" + extension +
+                                   "' cannot be longer than 16 characters.");
+    return false;
+  }
+
+  return true;
+}
+
+bool AddExtension(const String& extension,
+                  Vector<String>& extensions,
+                  ExceptionState& exception_state) {
+  if (!VerifyIsValidExtension(extension, exception_state))
+    return false;
+
   extensions.push_back(extension.Substring(1));
   return true;
 }
diff --git a/third_party/blink/renderer/modules/sanitizer_api/sanitizer_config.proto b/third_party/blink/renderer/modules/sanitizer_api/sanitizer_config.proto
index 2cb47ce..6089a320 100644
--- a/third_party/blink/renderer/modules/sanitizer_api/sanitizer_config.proto
+++ b/third_party/blink/renderer/modules/sanitizer_api/sanitizer_config.proto
@@ -5,13 +5,13 @@
 syntax = "proto2";
 
 message SanitizerConfigProto {
+  required string html_string = 1;
+
   message Elements { repeated string element = 1; }
-  repeated string allow_elements = 1;
-  repeated string block_elements = 2;
-  repeated string drop_elements = 3;
+  repeated string allow_elements = 2;
+  repeated string block_elements = 3;
+  repeated string drop_elements = 4;
 
-  map<string, Elements> allow_attributes = 4;
-  map<string, Elements> drop_attributes = 5;
-
-  required string html_string = 6;
+  map<string, Elements> allow_attributes = 5;
+  map<string, Elements> drop_attributes = 6;
 }
diff --git a/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.mm b/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.mm
index b9bd84e..930aba4 100644
--- a/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.mm
+++ b/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.mm
@@ -171,10 +171,8 @@
   DCHECK_NE(desired_family_string, FontCache::LegacySystemFontFamily());
 
   if (desired_family_string == font_family_names::kSystemUi) {
-    NSFont* font = nil;
-    if (@available(macOS 10.11, *)) {
-      font = [NSFont systemFontOfSize:size weight:toFontWeight(desired_weight)];
-    }
+    NSFont* font = [NSFont systemFontOfSize:size
+                                     weight:toFontWeight(desired_weight)];
     if (desired_traits & IMPORTANT_FONT_TRAITS)
       font = [[NSFontManager sharedFontManager] convertFont:font
                                                 toHaveTrait:desired_traits];
diff --git a/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac_test.mm b/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac_test.mm
index 0636b18..c3c3e678 100644
--- a/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac_test.mm
+++ b/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac_test.mm
@@ -6,7 +6,6 @@
 
 #include <AppKit/AppKit.h>
 
-#include "base/mac/mac_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/platform/font_family_names.h"
 
@@ -19,21 +18,6 @@
   EXPECT_TRUE([font.description containsString:substring]);
 }
 
-TEST(FontMatcherMacTest, YosemiteFontWeights) {
-  if (!base::mac::IsOS10_10())
-    return;
-
-  TestSystemFontContainsString(FontSelectionValue(100), @"-UltraLight");
-  TestSystemFontContainsString(FontSelectionValue(200), @"-Thin");
-  TestSystemFontContainsString(FontSelectionValue(300), @"-Light");
-  TestSystemFontContainsString(FontSelectionValue(400), @"-Regular");
-  TestSystemFontContainsString(FontSelectionValue(500), @"-Medium");
-  TestSystemFontContainsString(FontSelectionValue(600), @"-Bold");
-  TestSystemFontContainsString(FontSelectionValue(700), @"-Bold");
-  TestSystemFontContainsString(FontSelectionValue(800), @"-Heavy");
-  TestSystemFontContainsString(FontSelectionValue(900), @"-Heavy");
-}
-
 TEST(FontMatcherMacTest, NoUniqueFontMatchOnUnavailableFont) {
   NSFont* font = MatchUniqueFont(
       "ThisFontNameDoesNotExist07F444B9-4DDF-4A41-8F30-C80D4ED4CCA2", 12);
diff --git a/third_party/blink/renderer/platform/heap/BUILD.gn b/third_party/blink/renderer/platform/heap/BUILD.gn
index 503522b0..6079edf 100644
--- a/third_party/blink/renderer/platform/heap/BUILD.gn
+++ b/third_party/blink/renderer/platform/heap/BUILD.gn
@@ -55,6 +55,7 @@
   sources = [
     "blink_gc_memory_dump_provider.h",
     "collection_support/heap_hash_table_backing.h",
+    "collection_support/heap_linked_hash_set.h",
     "collection_support/heap_linked_stack.h",
     "collection_support/heap_vector_backing.h",
     "disallow_new_wrapper.h",
diff --git a/third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h b/third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h
index 27460c3..d1bb9401 100644
--- a/third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h
+++ b/third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h
@@ -15,16 +15,15 @@
 
 template <typename Table>
 class HeapHashTableBacking final
-    : public WTF::ConditionalDestructor<
+    : public GarbageCollected<HeapHashTableBacking<Table>>,
+      public WTF::ConditionalDestructor<
           HeapHashTableBacking<Table>,
           std::is_trivially_destructible<typename Table::ValueType>::value> {
-  DISALLOW_NEW();
-  IS_GARBAGE_COLLECTED_TYPE();
-
  public:
   template <typename Backing>
-  static void* AllocateObject(size_t size);
+  static void* AllocateObject(size_t);
 
+  // Conditionally invoked via destructor.
   void Finalize();
 };
 
@@ -47,10 +46,9 @@
   ThreadState* state =
       ThreadStateFor<ThreadingTrait<Backing>::kAffinity>::GetState();
   DCHECK(state->IsAllocationAllowed());
-  const char* type_name = WTF_HEAP_PROFILER_TYPE_NAME(Backing);
   return state->Heap().AllocateOnArenaIndex(
       state, size, BlinkGC::kHashTableArenaIndex, GCInfoTrait<Backing>::Index(),
-      type_name);
+      WTF_HEAP_PROFILER_TYPE_NAME(Backing));
 }
 
 template <typename Table>
diff --git a/third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h b/third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h
new file mode 100644
index 0000000..7e9b074
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h
@@ -0,0 +1,41 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_LINKED_HASH_SET_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_LINKED_HASH_SET_H_
+
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/wtf/linked_hash_set.h"
+#include "third_party/blink/renderer/platform/wtf/type_traits.h"
+
+namespace blink {
+
+template <typename ValueArg, typename TraitsArg = HashTraits<ValueArg>>
+class HeapLinkedHashSet final
+    : public GarbageCollected<HeapLinkedHashSet<ValueArg, TraitsArg>>,
+      public LinkedHashSet<ValueArg, TraitsArg, HeapAllocator> {
+  static void CheckType() {
+    static_assert(WTF::IsMemberOrWeakMemberType<ValueArg>::value,
+                  "HeapLinkedHashSet supports only Member and WeakMember.");
+    // If not trivially destructible, we have to add a destructor which will
+    // hinder performance.
+    static_assert(std::is_trivially_destructible<HeapLinkedHashSet>::value,
+                  "HeapLinkedHashSet must be trivially destructible.");
+    static_assert(WTF::IsTraceable<ValueArg>::value,
+                  "For sets without traceable elements, use LinkedHashSet<> "
+                  "instead of HeapLinkedHashSet<>.");
+  }
+
+ public:
+  HeapLinkedHashSet() = default;
+
+  void Trace(Visitor* v) const {
+    CheckType();
+    LinkedHashSet<ValueArg, TraitsArg, HeapAllocator>::Trace(v);
+  }
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_LINKED_HASH_SET_H_
diff --git a/third_party/blink/renderer/platform/heap/collection_support/heap_linked_stack.h b/third_party/blink/renderer/platform/heap/collection_support/heap_linked_stack.h
index 407d705..051dc07 100644
--- a/third_party/blink/renderer/platform/heap/collection_support/heap_linked_stack.h
+++ b/third_party/blink/renderer/platform/heap/collection_support/heap_linked_stack.h
@@ -47,12 +47,7 @@
 template <typename T>
 class HeapLinkedStack final : public GarbageCollected<HeapLinkedStack<T>> {
  public:
-  static void CheckType() {
-    static_assert(internal::IsMember<T>,
-                  "HeapLinkedStack supports only Member.");
-  }
-
-  HeapLinkedStack() { CheckType(); }
+  HeapLinkedStack() = default;
 
   inline size_t size() const;
   inline bool IsEmpty() const;
@@ -61,7 +56,10 @@
   inline const T& Peek() const;
   inline void Pop();
 
-  void Trace(Visitor* visitor) const { visitor->Trace(head_); }
+  void Trace(Visitor* visitor) const {
+    CheckType();
+    visitor->Trace(head_);
+  }
 
  private:
   class Node final : public GarbageCollected<Node> {
@@ -77,6 +75,11 @@
     Member<Node> next_;
   };
 
+  static void CheckType() {
+    static_assert(internal::IsMember<T>,
+                  "HeapLinkedStack supports only Member.");
+  }
+
   Member<Node> head_;
   size_t size_ = 0;
 };
diff --git a/third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h b/third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h
index 12b72b7..b75d0fc 100644
--- a/third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h
+++ b/third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h
@@ -20,27 +20,28 @@
 
 template <typename T, typename Traits = WTF::VectorTraits<T>>
 class HeapVectorBacking final
-    : public WTF::ConditionalDestructor<HeapVectorBacking<T, Traits>,
+    : public GarbageCollected<HeapVectorBacking<T, Traits>>,
+      public WTF::ConditionalDestructor<HeapVectorBacking<T, Traits>,
                                         !Traits::kNeedsDestruction> {
-  DISALLOW_NEW();
-  IS_GARBAGE_COLLECTED_TYPE();
-
  public:
   template <typename Backing>
-  static void* AllocateObject(size_t size) {
-    ThreadState* state =
-        ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState();
-    DCHECK(state->IsAllocationAllowed());
-    const char* type_name = WTF_HEAP_PROFILER_TYPE_NAME(Backing);
-    return state->Heap().AllocateOnArenaIndex(
-        state, size, BlinkGC::kVectorArenaIndex, GCInfoTrait<Backing>::Index(),
-        type_name);
-  }
+  static void* AllocateObject(size_t);
 
   // Conditionally invoked via destructor.
   void Finalize();
 };
 
+// static
+template <typename T, typename Traits>
+template <typename Backing>
+void* HeapVectorBacking<T, Traits>::AllocateObject(size_t size) {
+  ThreadState* state = ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState();
+  DCHECK(state->IsAllocationAllowed());
+  return state->Heap().AllocateOnArenaIndex(
+      state, size, BlinkGC::kVectorArenaIndex, GCInfoTrait<Backing>::Index(),
+      WTF_HEAP_PROFILER_TYPE_NAME(Backing));
+}
+
 template <typename T, typename Traits>
 void HeapVectorBacking<T, Traits>::Finalize() {
   static_assert(Traits::kNeedsDestruction,
diff --git a/third_party/blink/renderer/platform/heap/impl/heap.h b/third_party/blink/renderer/platform/heap/impl/heap.h
index f1740aaa..8da725d 100644
--- a/third_party/blink/renderer/platform/heap/impl/heap.h
+++ b/third_party/blink/renderer/platform/heap/impl/heap.h
@@ -538,8 +538,6 @@
   using GCInfoFoldedType = typename GCInfoFolded<Derived>::Type;
 
   GarbageCollected() = default;
-
-  DISALLOW_COPY_AND_ASSIGN(GarbageCollected);
 };
 
 // Used for passing custom sizes to MakeGarbageCollected.
diff --git a/third_party/blink/renderer/platform/heap/impl/heap_allocator.h b/third_party/blink/renderer/platform/heap/impl/heap_allocator.h
index 36013d9..6e72c47 100644
--- a/third_party/blink/renderer/platform/heap/impl/heap_allocator.h
+++ b/third_party/blink/renderer/platform/heap/impl/heap_allocator.h
@@ -9,6 +9,7 @@
 
 #include "build/build_config.h"
 #include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/heap/heap_buildflags.h"
@@ -42,22 +43,6 @@
 
 }  // namespace internal
 
-#define DISALLOW_IN_CONTAINER()              \
- public:                                     \
-  using IsDisallowedInContainerMarker = int; \
-                                             \
- private:                                    \
-  friend class ::WTF::internal::__thisIsHereToForceASemicolonAfterThisMacro
-
-// IsAllowedInContainer returns true if some type T supports being nested
-// arbitrarily in other containers. This is relevant for collections where some
-// collections assume that they are placed on a non-moving arena.
-template <typename T, typename = int>
-struct IsAllowedInContainer : std::true_type {};
-template <typename T>
-struct IsAllowedInContainer<T, typename T::IsDisallowedInContainerMarker>
-    : std::false_type {};
-
 // This is a static-only class used as a trait on collections to make them heap
 // allocated.  However see also HeapListHashSetAllocator.
 class PLATFORM_EXPORT HeapAllocator {
@@ -216,12 +201,6 @@
     static_assert(std::is_trivially_destructible<HeapHashMap>::value,
                   "HeapHashMap must be trivially destructible.");
     static_assert(
-        IsAllowedInContainer<KeyArg>::value,
-        "Not allowed to directly nest type. Use Member<> indirection instead.");
-    static_assert(
-        IsAllowedInContainer<MappedArg>::value,
-        "Not allowed to directly nest type. Use Member<> indirection instead.");
-    static_assert(
         WTF::IsTraceable<KeyArg>::value || WTF::IsTraceable<MappedArg>::value,
         "For hash maps without traceable elements, use HashMap<> "
         "instead of HeapHashMap<>.");
@@ -266,9 +245,6 @@
                   "HeapHashSet supports only Member and WeakMember.");
     static_assert(std::is_trivially_destructible<HeapHashSet>::value,
                   "HeapHashSet must be trivially destructible.");
-    static_assert(
-        IsAllowedInContainer<ValueArg>::value,
-        "Not allowed to directly nest type. Use Member<> indirection instead.");
     static_assert(WTF::IsTraceable<ValueArg>::value,
                   "For hash sets without traceable elements, use HashSet<> "
                   "instead of HeapHashSet<>.");
@@ -288,36 +264,6 @@
 struct GCInfoTrait<HeapHashSet<T, U, V>>
     : public GCInfoTrait<HashSet<T, U, V, HeapAllocator>> {};
 
-template <typename ValueArg, typename TraitsArg = HashTraits<ValueArg>>
-class HeapLinkedHashSet
-    : public LinkedHashSet<ValueArg, TraitsArg, HeapAllocator> {
-  IS_GARBAGE_COLLECTED_CONTAINER_TYPE();
-  DISALLOW_NEW();
-
-  static void CheckType() {
-    static_assert(WTF::IsMemberOrWeakMemberType<ValueArg>::value,
-                  "HeapLinkedHashSet supports only Member and WeakMember.");
-    // If not trivially destructible, we have to add a destructor which will
-    // hinder performance.
-    static_assert(std::is_trivially_destructible<HeapLinkedHashSet>::value,
-                  "HeapLinkedHashSet must be trivially destructible.");
-    static_assert(
-        IsAllowedInContainer<ValueArg>::value,
-        "Not allowed to directly nest type. Use Member<> indirection instead.");
-    static_assert(WTF::IsTraceable<ValueArg>::value,
-                  "For sets without traceable elements, use LinkedHashSet<> "
-                  "instead of HeapLinkedHashSet<>.");
-  }
-
- public:
-  template <typename>
-  static void* AllocateObject(size_t size) {
-    return ThreadHeap::Allocate<HeapLinkedHashSet<ValueArg, TraitsArg>>(size);
-  }
-
-  HeapLinkedHashSet() { CheckType(); }
-};
-
 }  // namespace blink
 
 namespace WTF {
@@ -389,10 +335,6 @@
   };
 };
 
-template <typename T, typename U>
-struct GCInfoTrait<HeapLinkedHashSet<T, U>>
-    : public GCInfoTrait<LinkedHashSet<T, U, HeapAllocator>> {};
-
 template <typename ValueArg,
           wtf_size_t inlineCapacity = 0,  // The inlineCapacity is just a dummy
                                           // to match ListHashSet (off-heap).
@@ -409,9 +351,6 @@
                   "HeapListHashSet supports only Member and WeakMember.");
     static_assert(std::is_trivially_destructible<HeapListHashSet>::value,
                   "HeapListHashSet must be trivially destructible.");
-    static_assert(
-        IsAllowedInContainer<ValueArg>::value,
-        "Not allowed to directly nest type. Use Member<> indirection instead.");
     static_assert(WTF::IsTraceable<ValueArg>::value,
                   "For sets without traceable elements, use ListHashSet<> "
                   "instead of HeapListHashSet<>.");
@@ -445,9 +384,6 @@
                   "HeapHashCountedSet supports only Member and WeakMember.");
     static_assert(std::is_trivially_destructible<HeapHashCountedSet>::value,
                   "HeapHashCountedSet must be trivially destructible.");
-    static_assert(
-        IsAllowedInContainer<Value>::value,
-        "Not allowed to directly nest type. Use Member<> indirection instead.");
     static_assert(WTF::IsTraceable<Value>::value,
                   "For counted sets without traceable elements, use "
                   "HashCountedSet<> instead of HeapHashCountedSet<>.");
@@ -476,9 +412,6 @@
     static_assert(
         std::is_trivially_destructible<HeapVector>::value || inlineCapacity,
         "HeapVector must be trivially destructible.");
-    static_assert(
-        IsAllowedInContainer<T>::value,
-        "Not allowed to directly nest type. Use Member<> indirection instead.");
     static_assert(WTF::IsTraceable<T>::value,
                   "For vectors without traceable elements, use Vector<> "
                   "instead of HeapVector<>.");
@@ -527,12 +460,12 @@
     return *this;
   }
 
-  HeapVector(HeapVector&& other)
+  HeapVector(HeapVector&& other) noexcept
       : Vector<T, inlineCapacity, HeapAllocator>(std::move(other)) {
     CheckType();
   }
 
-  HeapVector& operator=(HeapVector&& other) {
+  HeapVector& operator=(HeapVector&& other) noexcept {
     Vector<T, inlineCapacity, HeapAllocator>::operator=(std::move(other));
     return *this;
   }
@@ -556,9 +489,6 @@
     static_assert(internal::IsMember<T>, "HeapDeque supports only Member.");
     static_assert(std::is_trivially_destructible<HeapDeque>::value,
                   "HeapDeque must be trivially destructible.");
-    static_assert(
-        IsAllowedInContainer<T>::value,
-        "Not allowed to directly nest type. Use Member<> indirection instead.");
     static_assert(WTF::IsTraceable<T>::value,
                   "For vectors without traceable elements, use Deque<> instead "
                   "of HeapDeque<>");
diff --git a/third_party/blink/renderer/platform/heap/test/concurrent_marking_test.cc b/third_party/blink/renderer/platform/heap/test/concurrent_marking_test.cc
index 4f92244..aec8e7f 100644
--- a/third_party/blink/renderer/platform/heap/test/concurrent_marking_test.cc
+++ b/third_party/blink/renderer/platform/heap/test/concurrent_marking_test.cc
@@ -36,6 +36,14 @@
 // Tests that expose data races when modifying collections =====================
 // =============================================================================
 
+template <typename T>
+struct MethodAdapterBase {
+  static void Swap(T& a, T& b) { a.swap(b); }
+};
+
+template <typename T>
+struct MethodAdapter : public MethodAdapterBase<T> {};
+
 template <typename C>
 void AddToCollection() {
   constexpr int kIterations = 10;
@@ -135,7 +143,7 @@
       new_collection->insert(MakeGarbageCollected<IntegerObject>(j));
     }
     driver.SingleConcurrentStep();
-    collection->swap(*new_collection);
+    MethodAdapter<C>::Swap(*collection, *new_collection);
   }
   driver.FinishSteps();
   driver.FinishGC();
@@ -192,34 +200,31 @@
   SwapCollections<HeapHashSet<Member<IntegerObject>>>();
 }
 
-// HeapLinkedHashSet
 template <typename T>
-class HeapLinkedHashSetAdapter : public HeapLinkedHashSet<T> {
- public:
-  ALWAYS_INLINE void swap(HeapLinkedHashSetAdapter<T>& other) {
-    HeapLinkedHashSet<T>::Swap(other);
+struct MethodAdapter<HeapLinkedHashSet<T>>
+    : public MethodAdapterBase<HeapLinkedHashSet<T>> {
+  static void Swap(HeapLinkedHashSet<T>& a, HeapLinkedHashSet<T>& b) {
+    a.Swap(b);
   }
 };
 
 TEST_F(ConcurrentMarkingTest, AddToLinkedHashSet) {
-  AddToCollection<HeapLinkedHashSetAdapter<Member<IntegerObject>>>();
+  AddToCollection<HeapLinkedHashSet<Member<IntegerObject>>>();
 }
 TEST_F(ConcurrentMarkingTest, RemoveFromBeginningOfLinkedHashSet) {
-  RemoveFromBeginningOfCollection<
-      HeapLinkedHashSetAdapter<Member<IntegerObject>>>();
+  RemoveFromBeginningOfCollection<HeapLinkedHashSet<Member<IntegerObject>>>();
 }
 TEST_F(ConcurrentMarkingTest, RemoveFromMiddleOfLinkedHashSet) {
-  RemoveFromMiddleOfCollection<
-      HeapLinkedHashSetAdapter<Member<IntegerObject>>>();
+  RemoveFromMiddleOfCollection<HeapLinkedHashSet<Member<IntegerObject>>>();
 }
 TEST_F(ConcurrentMarkingTest, RemoveFromEndOfLinkedHashSet) {
-  RemoveFromEndOfCollection<HeapLinkedHashSetAdapter<Member<IntegerObject>>>();
+  RemoveFromEndOfCollection<HeapLinkedHashSet<Member<IntegerObject>>>();
 }
 TEST_F(ConcurrentMarkingTest, ClearLinkedHashSet) {
-  ClearCollection<HeapLinkedHashSetAdapter<Member<IntegerObject>>>();
+  ClearCollection<HeapLinkedHashSet<Member<IntegerObject>>>();
 }
 TEST_F(ConcurrentMarkingTest, SwapLinkedHashSet) {
-  SwapCollections<HeapLinkedHashSetAdapter<Member<IntegerObject>>>();
+  SwapCollections<HeapLinkedHashSet<Member<IntegerObject>>>();
 }
 
 // HeapListHashSet
diff --git a/third_party/blink/renderer/platform/network/http_parsers.cc b/third_party/blink/renderer/platform/network/http_parsers.cc
index 443f141f..ffde8bea 100644
--- a/third_party/blink/renderer/platform/network/http_parsers.cc
+++ b/third_party/blink/renderer/platform/network/http_parsers.cc
@@ -144,6 +144,7 @@
 blink::ContentSecurityPolicyPtr ConvertToBlink(
     ContentSecurityPolicyPtr policy_in) {
   return blink::ContentSecurityPolicy::New(
+      ConvertToBlink(std::move(policy_in->self_origin)),
       ConvertToBlink(std::move(policy_in->raw_directives)),
       ConvertToBlink(std::move(policy_in->directives)),
       policy_in->upgrade_insecure_requests, policy_in->treat_as_public_address,
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 33d1f48..95208ec 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -600,6 +600,10 @@
       depends_on: ["PictureInPictureAPI"],
     },
     {
+      name: "CSSPseudoDir",
+      status: "experimental",
+    },
+    {
       name: "CSSPseudoIs",
       status: "stable",
     },
@@ -1648,6 +1652,7 @@
     },
     {
       name: "ReadableByteStream",
+      status: "experimental",
     },
     {
       name: "RemotePlayback",
diff --git a/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.cc b/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.cc
index 97cb4c2..e795d786 100644
--- a/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.cc
+++ b/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.cc
@@ -200,19 +200,7 @@
     scoped_refptr<media::VideoFrame> source_frame,
     scoped_refptr<blink::WebRtcVideoFrameAdapter::BufferPoolOwner>
         scaled_frame_pool) {
-  gfx::GpuMemoryBuffer* gmb = source_frame->GetGpuMemoryBuffer();
-  if (!gmb || !gmb->Map()) {
-    return nullptr;
-  }
-  // Crop to the visible rectangle specified in |source_frame|.
-  const uint8_t* src_y = (reinterpret_cast<const uint8_t*>(gmb->memory(0)) +
-                          source_frame->visible_rect().x() +
-                          (source_frame->visible_rect().y() * gmb->stride(0)));
-  const uint8_t* src_uv =
-      (reinterpret_cast<const uint8_t*>(gmb->memory(1)) +
-       ((source_frame->visible_rect().x() / 2) * 2) +
-       ((source_frame->visible_rect().y() / 2) * gmb->stride(1)));
-
+  auto mapped_frame = media::ConvertToMemoryMappedFrame(source_frame);
   // Convert to I420 and scale to the natural size specified in
   // |source_frame|.
   auto dst_frame = scaled_frame_pool->CreateFrame(
@@ -220,25 +208,26 @@
       gfx::Rect(source_frame->natural_size()), source_frame->natural_size(),
       source_frame->timestamp());
   if (!dst_frame) {
-    gmb->Unmap();
     LOG(ERROR) << "Failed to create I420 frame from pool.";
     return nullptr;
   }
   dst_frame->metadata()->MergeMetadataFrom(source_frame->metadata());
   const auto& i420_planes = dst_frame->layout().planes();
   webrtc::NV12ToI420Scaler scaler;
-  scaler.NV12ToI420Scale(src_y, gmb->stride(0), src_uv, gmb->stride(1),
-                         source_frame->visible_rect().width(),
-                         source_frame->visible_rect().height(),
-                         dst_frame->data(media::VideoFrame::kYPlane),
-                         i420_planes[media::VideoFrame::kYPlane].stride,
-                         dst_frame->data(media::VideoFrame::kUPlane),
-                         i420_planes[media::VideoFrame::kUPlane].stride,
-                         dst_frame->data(media::VideoFrame::kVPlane),
-                         i420_planes[media::VideoFrame::kVPlane].stride,
-                         dst_frame->coded_size().width(),
-                         dst_frame->coded_size().height());
-  gmb->Unmap();
+  scaler.NV12ToI420Scale(
+      mapped_frame->visible_data(media::VideoFrame::kYPlane),
+      mapped_frame->stride(media::VideoFrame::kYPlane),
+      mapped_frame->visible_data(media::VideoFrame::kUVPlane),
+      mapped_frame->stride(media::VideoFrame::kUVPlane),
+      source_frame->visible_rect().width(),
+      source_frame->visible_rect().height(),
+      dst_frame->data(media::VideoFrame::kYPlane),
+      i420_planes[media::VideoFrame::kYPlane].stride,
+      dst_frame->data(media::VideoFrame::kUPlane),
+      i420_planes[media::VideoFrame::kUPlane].stride,
+      dst_frame->data(media::VideoFrame::kVPlane),
+      i420_planes[media::VideoFrame::kVPlane].stride,
+      dst_frame->coded_size().width(), dst_frame->coded_size().height());
   return dst_frame;
 }
 
@@ -246,26 +235,17 @@
     scoped_refptr<media::VideoFrame> source_frame,
     scoped_refptr<blink::WebRtcVideoFrameAdapter::BufferPoolOwner>
         scaled_frame_pool) {
-  gfx::GpuMemoryBuffer* gmb = source_frame->GetGpuMemoryBuffer();
-  if (!gmb || !gmb->Map()) {
-    return nullptr;
-  }
-  // Crop to the visible rectangle specified in |source_frame|.
-  const uint8_t* src_y = (reinterpret_cast<const uint8_t*>(gmb->memory(0)) +
-                          source_frame->visible_rect().x() +
-                          (source_frame->visible_rect().y() * gmb->stride(0)));
-  const uint8_t* src_uv =
-      (reinterpret_cast<const uint8_t*>(gmb->memory(1)) +
-       ((source_frame->visible_rect().x() / 2) * 2) +
-       ((source_frame->visible_rect().y() / 2) * gmb->stride(1)));
-
+  auto mapped_frame = media::ConvertToMemoryMappedFrame(source_frame);
   auto dst_frame = scaled_frame_pool->CreateFrame(
       media::PIXEL_FORMAT_NV12, source_frame->natural_size(),
       gfx::Rect(source_frame->natural_size()), source_frame->natural_size(),
       source_frame->timestamp());
   dst_frame->metadata()->MergeMetadataFrom(source_frame->metadata());
   const auto& nv12_planes = dst_frame->layout().planes();
-  libyuv::NV12Scale(src_y, gmb->stride(0), src_uv, gmb->stride(1),
+  libyuv::NV12Scale(mapped_frame->visible_data(media::VideoFrame::kYPlane),
+                    mapped_frame->stride(media::VideoFrame::kYPlane),
+                    mapped_frame->visible_data(media::VideoFrame::kUVPlane),
+                    mapped_frame->stride(media::VideoFrame::kUVPlane),
                     source_frame->visible_rect().width(),
                     source_frame->visible_rect().height(),
                     dst_frame->data(media::VideoFrame::kYPlane),
@@ -274,7 +254,6 @@
                     nv12_planes[media::VideoFrame::kUVPlane].stride,
                     dst_frame->coded_size().width(),
                     dst_frame->coded_size().height(), libyuv::kFilterBox);
-  gmb->Unmap();
   return dst_frame;
 }
 
diff --git a/third_party/blink/tools/blinkpy/common/memoized.py b/third_party/blink/tools/blinkpy/common/memoized.py
index 409b3a4..cd2dbaf 100644
--- a/third_party/blink/tools/blinkpy/common/memoized.py
+++ b/third_party/blink/tools/blinkpy/common/memoized.py
@@ -52,5 +52,13 @@
     # Use python "descriptor" protocol __get__ to appear
     # invisible during property access.
     def __get__(self, instance, owner):
-        # Return a function partial with object already bound as self.
-        return functools.partial(self.__call__, instance)
+        # Imagine we have a class, Foo, that has a @memoized method, bar(). So
+        # that foo.bar() works we need to bind the underlying instance via
+        # functools.partial, but we also want cache_clear() to work so we
+        # monkey-patch it on top.
+        wrapper = functools.partial(self.__call__, instance)
+        wrapper.cache_clear = self.cache_clear
+        return wrapper
+
+    def cache_clear(self):
+        self._results_cache = {}
diff --git a/third_party/blink/tools/blinkpy/common/memoized_unittest.py b/third_party/blink/tools/blinkpy/common/memoized_unittest.py
index 58273fd0..0f50270 100644
--- a/third_party/blink/tools/blinkpy/common/memoized_unittest.py
+++ b/third_party/blink/tools/blinkpy/common/memoized_unittest.py
@@ -40,6 +40,11 @@
         self.call_count += 1
         return argument + 1
 
+    @memoized
+    def memoized_subtract_one(self, argument):
+        self.call_count += 1
+        return argument - 1
+
 
 class MemoizedTest(unittest.TestCase):
     def test_multiple_identical_calls(self):
@@ -64,6 +69,22 @@
         self.assertEqual(add_one(4), 5)
         self.assertEqual(test.call_count, 1)
 
+    def test_cache_clear(self):
+        test = _TestObject()
+        self.assertEqual(test.memoized_add_one(1), 2)
+        self.assertEqual(test.memoized_subtract_one(2), 1)
+        self.assertEqual(test.call_count, 2)
+
+        # Now clear the cache of memoized_add_one. This should only clear the
+        # cache for that function.
+        test.memoized_add_one.cache_clear()
+
+        self.assertEqual(test.memoized_subtract_one(2), 1)
+        self.assertEqual(test.call_count, 2)
+
+        self.assertEqual(test.memoized_add_one(1), 2)
+        self.assertEqual(test.call_count, 3)
+
     def test_non_hashable_args(self):
         test = _TestObject()
         try:
diff --git a/third_party/blink/tools/blinkpy/w3c/test_importer.py b/third_party/blink/tools/blinkpy/w3c/test_importer.py
index 25bf0dfb..047fb81a 100644
--- a/third_party/blink/tools/blinkpy/w3c/test_importer.py
+++ b/third_party/blink/tools/blinkpy/w3c/test_importer.py
@@ -48,7 +48,6 @@
     def __init__(self, host, wpt_github=None, wpt_manifests=None):
         self.host = host
         self.wpt_github = wpt_github
-        self.port = host.port_factory.get()
 
         self.executive = host.executive
         self.fs = host.filesystem
@@ -157,8 +156,9 @@
         # TODO(robertma): Implement `add --all` in Git (it is different from `commit --all`).
         self.chromium_git.run(['add', '--all', self.dest_path])
 
-        # Remove expectations for tests that were deleted and rename tests
-        # in expectations for renamed tests.
+        # Remove expectations for tests that were deleted and rename tests in
+        # expectations for renamed tests. This requires the old WPT manifest, so
+        # must happen before we regenerate it.
         self._expectations_updater.cleanup_test_expectations_files()
 
         self._generate_manifest()
@@ -166,7 +166,6 @@
         # TODO(crbug.com/800570 robertma): Re-enable it once we fix the bug.
         # self._delete_orphaned_baselines()
 
-
         if not self.chromium_git.has_working_directory_changes():
             _log.info('Done: no changes to import.')
             return 0
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py
index 81d13cfa5..b1f3344 100644
--- a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py
+++ b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py
@@ -155,6 +155,13 @@
             mapping tests that couldn't be rebaselined to lists of expectation
             lines written to TestExpectations.
         """
+        # The wpt_manifest function in Port is cached by default, but may be out
+        # of date if this code is called during test import. An out of date
+        # manifest will cause us to mistreat newly added tests, as they will not
+        # exist in the cached manifest. To avoid this, we invalidate the cache
+        # here. See https://crbug.com/1154650 .
+        self.port.wpt_manifest.cache_clear()
+
         issue_number = self.get_issue_number()
         if issue_number == 'None':
             raise ScriptError('No issue on current branch.')
@@ -170,7 +177,9 @@
             if (job_status.result == 'SUCCESS' and
                     not self.options.include_unexpected_pass):
                 continue
+            # Temporary logging for https://crbug.com/1154650
             result_dicts = self.get_failing_results_dicts(build)
+            _log.info('Merging failing results dicts for %s', build)
             for result_dict in result_dicts:
                 test_expectations = self.merge_dicts(
                     test_expectations, result_dict)
@@ -363,9 +372,14 @@
                 elif target[key] == source[key]:
                     pass
                 else:
+                    # Temporary logging for https://crbug.com/1154650.
+                    _log.info(
+                        'Error: mismatching key values in merge_dicts.\n'
+                        'target[key]: %s\nsource[key]: %s', target[key],
+                        source[key])
                     raise ValueError(
-                        'The key: %s already exist in the target dictionary.' %
-                        '.'.join(path))
+                        'The key: %s already exists in the target dictionary.'
+                        % '.'.join(path))
             else:
                 target[key] = source[key]
         return target
diff --git a/third_party/blink/web_tests/LeakExpectations b/third_party/blink/web_tests/LeakExpectations
index 651812226..28cd6c2 100644
--- a/third_party/blink/web_tests/LeakExpectations
+++ b/third_party/blink/web_tests/LeakExpectations
@@ -37,6 +37,9 @@
 crbug.com/1098106 virtual/off-main-thread-css-paint/http/tests/csspaint/invalidation-background-image.html [ Crash ]
 crbug.com/1098106 virtual/off-main-thread-css-paint/http/tests/csspaint/invalidation-content-image.html [ Crash ]
 
+# Random timeout
+crbug.com/1151861 [ Linux ] external/wpt/workers/semantics/multiple-workers/003.html [ Timeout Crash ]
+
 # -----------------------------------------------------------------
 # Flakily leaks
 # -----------------------------------------------------------------
diff --git a/third_party/blink/web_tests/SmokeTests b/third_party/blink/web_tests/SmokeTests
index c14f6f1..b485096 100644
--- a/third_party/blink/web_tests/SmokeTests
+++ b/third_party/blink/web_tests/SmokeTests
@@ -798,7 +798,6 @@
 http/tests/security/local-JavaScript-from-remote.html
 http/tests/security/no-javascript-refresh.php
 http/tests/shapes/crash-image-changed-during-layout.html
-http/tests/streams/chromium/get-reader-byob.html
 http/tests/uri/escaped-entity.html
 http/tests/uri/resolve-encoding-relative.html
 http/tests/uri/utf8-path.html
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index b3b35de..705d9eb 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2692,7 +2692,6 @@
 crbug.com/626703 [ Mac ] external/wpt/css/css-fonts/standard-font-family.html [ Failure ]
 crbug.com/626703 [ Mac10.13 ] external/wpt/screen-capture/getdisplaymedia.https.html [ Failure Timeout ]
 crbug.com/626703 [ Mac10.14 ] external/wpt/screen-capture/getdisplaymedia.https.html [ Failure Timeout ]
-crbug.com/626703 external/wpt/streams/readable-byte-streams/construct-byob-request.any.sharedworker.html [ Timeout ]
 crbug.com/626703 [ Mac ] external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-iframe-messagechannel.https.html [ Timeout ]
 crbug.com/626703 [ Win ] external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-iframe-messagechannel.https.html [ Timeout ]
 crbug.com/1144104 [ Linux ] external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/no-coop-coep.https.any.html [ Failure ]
@@ -2722,7 +2721,6 @@
 crbug.com/626703 [ Win10 ] external/wpt/payment-request/payment-request-hasenrolledinstrument-method.tentative.https.html [ Failure Timeout ]
 crbug.com/626703 [ Win ] external/wpt/web-animations/timing-model/animation-effects/phases-and-states.html [ Crash ]
 crbug.com/626703 external/wpt/webvtt/rendering/cues-with-video/processing-model/snap-to-line.html [ Failure ]
-crbug.com/626703 external/wpt/shadow-dom/directionality-002.tentative.html [ Failure ]
 crbug.com/626703 [ Mac10.13 ] external/wpt/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/mediastreamaudiosourcenode-routing.html [ Timeout ]
 crbug.com/626703 [ Mac10.14 ] external/wpt/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/mediastreamaudiosourcenode-routing.html [ Timeout ]
 crbug.com/626703 [ Win7 ] external/wpt/IndexedDB/structured-clone.any.html [ Timeout ]
@@ -2995,8 +2993,6 @@
 crbug.com/626703 external/wpt/web-animations/timing-model/timelines/update-and-send-events.html [ Failure ]
 crbug.com/626703 external/wpt/svg/painting/reftests/paint-context-001.svg [ Failure ]
 crbug.com/626703 external/wpt/svg/painting/reftests/paint-context-002.svg [ Failure ]
-crbug.com/626703 external/wpt/css/css-scoping/shadow-directionality-002.tentative.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-scoping/shadow-directionality-001.tentative.html [ Failure ]
 crbug.com/626703 external/wpt/screen-orientation/orientation-reading.html [ Timeout ]
 crbug.com/626703 external/wpt/html/browsers/browsing-the-web/unloading-documents/prompt-and-unload-script-closeable.html [ Failure ]
 crbug.com/626703 external/wpt/html/infrastructure/urls/resolving-urls/query-encoding/navigation.sub.html?encoding=x-cp1251 [ Timeout ]
@@ -4087,17 +4083,6 @@
 # [css-animations]
 crbug.com/993365 external/wpt/css/css-transitions/Element-getAnimations.tentative.html [ Failure Pass ]
 
-# [selectors-4]
-crbug.com/576815 external/wpt/css/selectors/selectors-dir-selector-ltr-001.html [ Failure ]
-crbug.com/576815 external/wpt/css/selectors/selectors-dir-selector-rtl-001.html [ Failure ]
-crbug.com/576815 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/selectors4/dir-style-01a.html [ Failure ]
-crbug.com/576815 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/selectors4/dir-style-01b.html [ Failure ]
-crbug.com/576815 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/selectors4/dir-style-02a.html [ Failure ]
-crbug.com/576815 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/selectors4/dir-style-02b.html [ Failure ]
-crbug.com/576815 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/selectors4/dir-style-03a.html [ Failure ]
-crbug.com/576815 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/selectors4/dir-style-03b.html [ Failure ]
-crbug.com/576815 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/selectors4/dir-style-04.html [ Failure ]
-
 crbug.com/664450 http/tests/devtools/console/console-on-animation-worklet.js [ Skip ]
 
 crbug.com/826419 external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-remove-track-inband.html [ Skip ]
@@ -5932,7 +5917,6 @@
 crbug.com/1150475 fast/dom/open-and-close-by-DOM.html [ Pass Failure ]
 
 #Sheriff 2020-11-23
-crbug.com/1151861 external/wpt/workers/semantics/multiple-workers/003.html [ Timeout Crash ]
 crbug.com/1152088 [ Mac10.13 Debug ] fast/dom/cssTarget-crash.html [ Pass Timeout ]
 crbug.com/1149734 http/tests/devtools/sources/source-frame-toolbar-items.js [ Pass Failure ]
 crbug.com/1149734 http/tests/devtools/sources/debugger-frameworks/frameworks-sourcemap.js [ Pass Failure ]
diff --git a/third_party/blink/web_tests/external/wpt/compression/compression-with-detach.tentative.any.js b/third_party/blink/web_tests/external/wpt/compression/compression-with-detach.tentative.any.js
new file mode 100644
index 0000000..786bba2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/compression/compression-with-detach.tentative.any.js
@@ -0,0 +1,55 @@
+// META: global=window,worker
+// META: script=resources/concatenate-stream.js
+
+'use strict';
+
+const kInputLength = 500000;
+
+function createLargeRandomInput() {
+  const buffer = new ArrayBuffer(kInputLength);
+  // The getRandomValues API will only let us get 65536 bytes at a time, so call
+  // it multiple times.
+  const kChunkSize = 65536;
+  for (let offset = 0; offset < kInputLength; offset += kChunkSize) {
+    const length =
+        offset + kChunkSize > kInputLength ? kInputLength - offset : kChunkSize;
+    const view = new Uint8Array(buffer, offset, length);
+    crypto.getRandomValues(view);
+  }
+  return new Uint8Array(buffer);
+}
+
+function decompress(view) {
+  const ds = new DecompressionStream('deflate');
+  const writer = ds.writable.getWriter();
+  writer.write(view);
+  writer.close();
+  return concatenateStream(ds.readable);
+}
+
+promise_test(async () => {
+  const input = createLargeRandomInput();
+  const inputCopy = input.slice(0, input.byteLength);
+  const cs = new CompressionStream('deflate');
+  const writer = cs.writable.getWriter();
+  writer.write(input);
+  writer.close();
+  // Object.prototype.then will be looked up synchronously when the promise
+  // returned by read() is resolved.
+  Object.defineProperty(Object.prototype, 'then', {
+    get() {
+      // Cause input to become detached and unreferenced.
+      try {
+        postMessage(undefined, 'nowhere', [input.buffer]);
+      } catch (e) {
+        // It's already detached.
+      }
+    }
+  });
+  const output = await concatenateStream(cs.readable);
+  // Perform the comparison as strings since this is reasonably fast even when
+  // JITted JavaScript is running under an emulator.
+  assert_equals(
+      inputCopy.toString(), (await decompress(output)).toString(),
+      'decompressing the output should return the input');
+}, 'data should be correctly compressed even if input is detached partway');
diff --git a/third_party/blink/web_tests/external/wpt/compression/decompression-with-detach.tentative.any.js b/third_party/blink/web_tests/external/wpt/compression/decompression-with-detach.tentative.any.js
new file mode 100644
index 0000000..a2f8bda0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/compression/decompression-with-detach.tentative.any.js
@@ -0,0 +1,41 @@
+// META: global=window,worker
+// META: script=resources/concatenate-stream.js
+
+'use strict';
+
+const kInputLength = 1000000;
+
+async function createLargeCompressedInput() {
+  const cs = new CompressionStream('deflate');
+  // The input has to be large enough that it won't fit in a single chunk when
+  // decompressed.
+  const writer = cs.writable.getWriter();
+  writer.write(new Uint8Array(kInputLength));
+  writer.close();
+  return concatenateStream(cs.readable);
+}
+
+promise_test(async () => {
+  const input = await createLargeCompressedInput();
+  const ds = new DecompressionStream('deflate');
+  const writer = ds.writable.getWriter();
+  writer.write(input);
+  writer.close();
+  // Object.prototype.then will be looked up synchronously when the promise
+  // returned by read() is resolved.
+  Object.defineProperty(Object.prototype, 'then', {
+    get() {
+      // Cause input to become detached and unreferenced.
+      try {
+        postMessage(undefined, 'nowhere', [input.buffer]);
+      } catch (e) {
+        // It's already detached.
+      }
+    }
+  });
+  const output = await concatenateStream(ds.readable);
+  // If output successfully decompressed and gave the right length, we can be
+  // reasonably confident that no data corruption happened.
+  assert_equals(
+      output.byteLength, kInputLength, 'output should be the right length');
+}, 'data should be correctly decompressed even if input is detached partway');
diff --git a/third_party/blink/web_tests/external/wpt/compression/resources/concatenate-stream.js b/third_party/blink/web_tests/external/wpt/compression/resources/concatenate-stream.js
new file mode 100644
index 0000000..a35bb14
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/compression/resources/concatenate-stream.js
@@ -0,0 +1,25 @@
+'use strict';
+
+// Read all the chunks from a stream that returns BufferSource objects and
+// concatenate them into a single Uint8Array.
+async function concatenateStream(readableStream) {
+  const reader = readableStream.getReader();
+  let totalSize = 0;
+  const buffers = [];
+  while (true) {
+    const { value, done } = await reader.read();
+    if (done) {
+      break;
+    }
+    buffers.push(value);
+    totalSize += value.byteLength;
+  }
+  reader.releaseLock();
+  const concatenated = new Uint8Array(totalSize);
+  let offset = 0;
+  for (const buffer of buffers) {
+    concatenated.set(buffer, offset);
+    offset += buffer.byteLength;
+  }
+  return concatenated;
+}
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/frame-src/frame-src-sandboxed-allowed-expected.txt b/third_party/blink/web_tests/external/wpt/content-security-policy/frame-src/frame-src-sandboxed-allowed-expected.txt
deleted file mode 100644
index 1102ea6..0000000
--- a/third_party/blink/web_tests/external/wpt/content-security-policy/frame-src/frame-src-sandboxed-allowed-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL SubframeLoaded assert_unreached: unexpected securitypolicyviolation Reached unreachable code
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-anchoring/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-scroll-anchoring/DIR_METADATA
new file mode 100644
index 0000000..85377a7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-anchoring/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Layout"
+}
+team_email: "layout-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-anchoring/OWNERS b/third_party/blink/web_tests/external/wpt/css/css-scroll-anchoring/OWNERS
index 6db7af8..c6ee3b6 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-scroll-anchoring/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-anchoring/OWNERS
@@ -1,4 +1 @@
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>Layout
-# WPT-NOTIFY: true
 skobes@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-shapes/DIR_METADATA
new file mode 100644
index 0000000..815ca00
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Layout>Shape"
+}
+team_email: "layout-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/OWNERS b/third_party/blink/web_tests/external/wpt/css/css-shapes/OWNERS
index 45d17fb8..e8b3fc1 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-shapes/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/OWNERS
@@ -1,4 +1 @@
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>Layout>Shape
-# WPT-NOTIFY: true
 bjonesbe@adobe.com
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-sizing/DIR_METADATA
new file mode 100644
index 0000000..85377a7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Layout"
+}
+team_email: "layout-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/OWNERS b/third_party/blink/web_tests/external/wpt/css/css-sizing/OWNERS
index 95f61b7..51c6a57d 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-sizing/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/OWNERS
@@ -1,4 +1 @@
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>Layout
-# WPT-NOTIFY: true
 cbiesinger@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/css/css-syntax/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-syntax/DIR_METADATA
new file mode 100644
index 0000000..a1cb39c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-syntax/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>CSS"
+}
+team_email: "layout-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/css/css-syntax/OWNERS b/third_party/blink/web_tests/external/wpt/css/css-syntax/OWNERS
deleted file mode 100644
index e282c4f..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-syntax/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>CSS
diff --git a/third_party/blink/web_tests/external/wpt/css/css-tables/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-tables/DIR_METADATA
new file mode 100644
index 0000000..bd468f81a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-tables/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Layout>Table"
+}
+team_email: "layout-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/css/css-tables/OWNERS b/third_party/blink/web_tests/external/wpt/css/css-tables/OWNERS
index 1cc9d5b..aef437e 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-tables/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/css/css-tables/OWNERS
@@ -1,4 +1 @@
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>Layout>Table
-# WPT-NOTIFY: true
 dgrogan@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-text-decor/DIR_METADATA
new file mode 100644
index 0000000..85377a7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Layout"
+}
+team_email: "layout-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/OWNERS b/third_party/blink/web_tests/external/wpt/css/css-text-decor/OWNERS
index 801a0f4..f196c82 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text-decor/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/OWNERS
@@ -1,4 +1 @@
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>Layout
-# WPT-NOTIFY: true
 drott@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-text/DIR_METADATA
new file mode 100644
index 0000000..85377a7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Layout"
+}
+team_email: "layout-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/OWNERS b/third_party/blink/web_tests/external/wpt/css/css-text/OWNERS
deleted file mode 100644
index 9b2e5be..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-text/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>Layout
-# WPT-NOTIFY: true
diff --git a/third_party/blink/web_tests/external/wpt/css/css-timing/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-timing/DIR_METADATA
new file mode 100644
index 0000000..a1cb39c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-timing/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>CSS"
+}
+team_email: "layout-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/css/css-timing/OWNERS b/third_party/blink/web_tests/external/wpt/css/css-timing/OWNERS
deleted file mode 100644
index e282c4f..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-timing/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>CSS
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-transforms/DIR_METADATA
new file mode 100644
index 0000000..46ba8320
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Transforms"
+}
+team_email: "paint-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/OWNERS b/third_party/blink/web_tests/external/wpt/css/css-transforms/OWNERS
deleted file mode 100644
index e090a5a..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-transforms/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# TEAM: paint-dev@chromium.org
-# COMPONENT: Blink>Transforms
-# WPT-NOTIFY: true
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-typed-om/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-typed-om/DIR_METADATA
new file mode 100644
index 0000000..a1cb39c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-typed-om/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>CSS"
+}
+team_email: "layout-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/css/css-typed-om/OWNERS b/third_party/blink/web_tests/external/wpt/css/css-typed-om/OWNERS
deleted file mode 100644
index e282c4f..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-typed-om/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>CSS
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-ui/DIR_METADATA
new file mode 100644
index 0000000..85377a7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Layout"
+}
+team_email: "layout-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/OWNERS b/third_party/blink/web_tests/external/wpt/css/css-ui/OWNERS
index 5f43f91..5e03d9bc 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-ui/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/OWNERS
@@ -1,4 +1 @@
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>Layout
-# WPT-NOTIFY: true
 rego@igalia.com
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-values/DIR_METADATA
new file mode 100644
index 0000000..a1cb39c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-values/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>CSS"
+}
+team_email: "layout-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/OWNERS b/third_party/blink/web_tests/external/wpt/css/css-values/OWNERS
deleted file mode 100644
index e282c4f..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-values/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>CSS
diff --git a/third_party/blink/web_tests/external/wpt/css/css-variables/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-variables/DIR_METADATA
new file mode 100644
index 0000000..a1cb39c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-variables/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>CSS"
+}
+team_email: "layout-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/css/css-variables/OWNERS b/third_party/blink/web_tests/external/wpt/css/css-variables/OWNERS
deleted file mode 100644
index e282c4f..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-variables/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>CSS
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/DIR_METADATA
new file mode 100644
index 0000000..fecdb38
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Layout>WritingMode"
+}
+team_email: "layout-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/OWNERS b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/OWNERS
index d7655b1..53463b3 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/OWNERS
@@ -1,4 +1 @@
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>Layout>WritingMode
-# WPT-NOTIFY: true
 kojii@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom-view/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/cssom-view/DIR_METADATA
new file mode 100644
index 0000000..a1cb39c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/cssom-view/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>CSS"
+}
+team_email: "layout-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom-view/OWNERS b/third_party/blink/web_tests/external/wpt/css/cssom-view/OWNERS
deleted file mode 100644
index e282c4f..0000000
--- a/third_party/blink/web_tests/external/wpt/css/cssom-view/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>CSS
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/cssom/DIR_METADATA
new file mode 100644
index 0000000..a1cb39c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/cssom/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>CSS"
+}
+team_email: "layout-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/OWNERS b/third_party/blink/web_tests/external/wpt/css/cssom/OWNERS
deleted file mode 100644
index e282c4f..0000000
--- a/third_party/blink/web_tests/external/wpt/css/cssom/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>CSS
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/filter-effects/DIR_METADATA
new file mode 100644
index 0000000..765407c4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Paint"
+}
+team_email: "paint-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/OWNERS b/third_party/blink/web_tests/external/wpt/css/filter-effects/OWNERS
deleted file mode 100644
index 5f3e240..0000000
--- a/third_party/blink/web_tests/external/wpt/css/filter-effects/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# TEAM: paint-dev@chromium.org
-# COMPONENT: Blink>Paint
-# WPT-NOTIFY: true
diff --git a/third_party/blink/web_tests/external/wpt/css/geometry/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/geometry/DIR_METADATA
new file mode 100644
index 0000000..f7d3bf5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/geometry/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Geometry"
+}
+team_email: "paint-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/css/geometry/OWNERS b/third_party/blink/web_tests/external/wpt/css/geometry/OWNERS
index b788e32..806af33 100644
--- a/third_party/blink/web_tests/external/wpt/css/geometry/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/css/geometry/OWNERS
@@ -1,6 +1,3 @@
-# TEAM: paint-dev@chromium.org
-# COMPONENT: Blink>Geometry
-# WPT-NOTIFY: true
 xlai@chromium.org
 jinho.bang@samsung.com
 hs1217.lee@samsung.com
diff --git a/third_party/blink/web_tests/external/wpt/css/mediaqueries/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/mediaqueries/DIR_METADATA
new file mode 100644
index 0000000..a1cb39c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/mediaqueries/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>CSS"
+}
+team_email: "layout-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/css/mediaqueries/OWNERS b/third_party/blink/web_tests/external/wpt/css/mediaqueries/OWNERS
deleted file mode 100644
index e282c4f..0000000
--- a/third_party/blink/web_tests/external/wpt/css/mediaqueries/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>CSS
diff --git a/third_party/blink/web_tests/external/wpt/css/motion/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/motion/DIR_METADATA
new file mode 100644
index 0000000..a1cb39c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/motion/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>CSS"
+}
+team_email: "layout-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/css/motion/OWNERS b/third_party/blink/web_tests/external/wpt/css/motion/OWNERS
index d10225e..812e93d 100644
--- a/third_party/blink/web_tests/external/wpt/css/motion/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/css/motion/OWNERS
@@ -1,3 +1 @@
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>CSS
 ericwilligers@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/selectors/DIR_METADATA
new file mode 100644
index 0000000..a1cb39c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/selectors/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>CSS"
+}
+team_email: "layout-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/OWNERS b/third_party/blink/web_tests/external/wpt/css/selectors/OWNERS
index 9b25911..5e03d9bc 100644
--- a/third_party/blink/web_tests/external/wpt/css/selectors/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/css/selectors/OWNERS
@@ -1,3 +1 @@
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>CSS
 rego@igalia.com
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-auto.html b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-auto.html
new file mode 100644
index 0000000..d53e989
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-auto.html
@@ -0,0 +1,93 @@
+<!doctype html>
+<html>
+<head>
+  <link rel="help" href="http://www.w3.org/TR/selectors4/#dir-pseudo">
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <style>
+    #div4_1 {
+      direction: rtl;
+    }
+  </style>
+</head>
+
+<!-- &#1514; is the Hebrew letter tav, i.e. RTL -->
+<body>
+  <div id=testDivs>
+    <div id=div1 dir=auto>
+      <div id=div1_1>a</div>
+    </div>
+    <div id=div2 dir=auto>
+      <div id=div2_1>&#1514;</div>
+    </div>
+    <div id=div3 dir=auto>
+      <div id=div3_1 dir=rtl>&#1514;</div>
+      <div id=div3_2>a</div>
+    </div>
+    <div id=div4 dir=auto>
+      <div id=div4_1>
+        <div id=div4_1_1>a</div>
+      </div>
+    </div>
+  </div>
+</body>
+
+<script>
+function test_directionality(message, element, expected) {
+  test(() => {
+    var isLTR = document.querySelector("#" + element.id + ":dir(ltr)") == element;
+    var isRTL = document.querySelector("#" + element.id + ":dir(rtl)") == element;
+    if (expected == "ltr") {
+      assert_true(isLTR);
+      assert_false(isRTL);
+    } else {
+      assert_false(isLTR);
+      assert_true(isRTL);
+    }
+  }, message + " directionality of element " + element.id + " is " + expected);
+}
+
+test_directionality("Initial ", div1, "ltr");
+test_directionality("Initial ", div1_1, "ltr");
+test_directionality("Initial ", div2, "rtl");
+test_directionality("Initial ", div2_1, "rtl");
+test_directionality("Initial ", div3, "ltr");
+test_directionality("Initial ", div3_1, "rtl");
+test_directionality("Initial ", div3_2, "ltr");
+test_directionality("Initial ", div4, "ltr");
+test_directionality("Initial ", div4_1, "ltr");
+test_directionality("Initial ", div4_1_1, "ltr");
+
+div1_1.innerText = "\u05EA";
+div1_1.offsetTop;
+test_directionality("Updated ", div1, "rtl");
+test_directionality("Updated ", div1_1, "rtl");
+
+div1_1.dir = "ltr";
+div1_1.offsetTop;
+test_directionality("Updated ", div1, "ltr");
+test_directionality("Updated ", div1_1, "ltr");
+
+div1_1.innerText = "a";
+div1_1.offsetTop;
+test_directionality("Reupdated ", div1, "ltr");
+test_directionality("Reupdated ", div1_1, "ltr");
+
+div2_1.remove();
+div2.offsetTop;
+test_directionality("Updated ", div2, "ltr");
+
+div3_1.dir = "";
+div3_1.offsetTop;
+test_directionality("Updated ", div3, "rtl");
+div3.appendChild(div3_1);
+div3.offsetTop;
+test_directionality("Updated ", div3, "ltr");
+
+div4_1_1.innerText = "\u05EA";
+div4_1_1.offsetTop;
+test_directionality("Updated ", div4, "rtl");
+test_directionality("Updated ", div4_1, "rtl");
+test_directionality("Updated ", div4_1_1, "rtl");
+</script>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-change-001-ref.html b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-change-001-ref.html
new file mode 100644
index 0000000..8c79c83
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-change-001-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <style type="text/css">
+        span { background-color: lime }
+    </style>
+</head>
+<body>
+    <div>
+        <div>
+          <div></div>
+          <span>The background color should be lime</span>
+        </div>
+    </div>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-change-001.html b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-change-001.html
new file mode 100644
index 0000000..f9523896
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-change-001.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>CSS Selectors Level 4 Test: Check for correctly updating :dir matching on dir attribute change from default(ltr) to rtl</title>
+    <link rel="author" title="Miyoung Shin" href="mailto:myid.shin@igalia.com">
+    <link rel="help" href="http://www.w3.org/TR/selectors4/#dir-pseudo">
+    <link rel="match" href="selectors-dir-selector-change-001-ref.html">
+    <style type="text/css">
+        #x:dir(rtl) + span { background-color: lime }
+        #outer { direction:ltr }
+    </style>
+</head>
+<body>
+    <div id="outer" style="-webkit-locale: 'en'">
+        <div>
+            <div id="x"></div>
+            <span>The background color should be lime</span>
+        </div>
+    </div>
+    <script>
+        outer.offsetTop;
+        outer.setAttribute("dir", "rtl");
+    </script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-change-002.html b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-change-002.html
new file mode 100644
index 0000000..bc032b5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-change-002.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>CSS Selectors Level 4 Test: Check for correctly updating :dir matching on dir attribute change from default(ltr) to rtl</title>
+    <link rel="author" title="Miyoung Shin" href="mailto:myid.shin@igalia.com">
+    <link rel="help" href="http://www.w3.org/TR/selectors4/#dir-pseudo">
+    <link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+    <style type="text/css">
+       div {
+           width: 100px;
+           height: 100px;
+           background-color: red;
+       }
+
+       div:dir(rtl) {
+           background-color: green;
+       }
+    </style>
+</head>
+<body>
+    <p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+    <div id="inner"></div>
+    <script>
+        inner.offsetTop;
+        inner.setAttribute("dir", "rtl");
+    </script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-change-003-ref.html b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-change-003-ref.html
new file mode 100644
index 0000000..8c79c83
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-change-003-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <style type="text/css">
+        span { background-color: lime }
+    </style>
+</head>
+<body>
+    <div>
+        <div>
+          <div></div>
+          <span>The background color should be lime</span>
+        </div>
+    </div>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-change-003.html b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-change-003.html
new file mode 100644
index 0000000..f400015
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-change-003.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>CSS Selectors Level 4 Test: Check for correctly updating :dir matching on dir attribute change from rtl to auto</title>
+    <link rel="author" title="Miyoung Shin" href="mailto:myid.shin@igalia.com">
+    <link rel="help" href="http://www.w3.org/TR/selectors4/#dir-pseudo">
+    <link rel="match" href="selectors-dir-selector-change-003-ref.html">
+    <style type="text/css">
+        #x:dir(ltr) + span { background-color: lime }
+    </style>
+</head>
+<body>
+    <div id="outer" dir="rtl">
+        <div>
+            <div id="x"></div>
+            <span>The background color should be lime</span>
+        </div>
+    </div>
+    <script>
+        outer.offsetTop;
+        outer.setAttribute("dir", "auto");
+    </script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-change-004-ref.html b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-change-004-ref.html
new file mode 100644
index 0000000..9a130cb
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-change-004-ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+    <style type="text/css">
+        span { background-color: lime }
+    </style>
+</head>
+<body>
+    <div>
+        <div dir="rtl">
+          <div></div>
+          <span>מקור השם עברית</span>
+        </div>
+    </div>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-change-004.html b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-change-004.html
new file mode 100644
index 0000000..4c76b29
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-change-004.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>CSS Selectors Level 4 Test: Check for correctly updating :dir matching on directionality change from ltr to rtl</title>
+    <link rel="author" title="Miyoung Shin" href="mailto:myid.shin@igalia.com">
+    <link rel="help" href="http://www.w3.org/TR/selectors4/#dir-pseudo">
+    <link rel="match" href="selectors-dir-selector-change-004-ref.html">
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+    <style type="text/css">
+        #x:dir(rtl) + span { background-color: lime }
+    </style>
+</head>
+<body>
+    <div dir="auto">
+        <div>
+            <div id="x"></div>
+            <span id="inner">The background color should be lime</span>
+        </div>
+    </div>
+    <script>
+        inner.offsetTop;
+        inner.innerHTML = "מקור השם עברית";
+    </script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-ltr-002.html b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-ltr-002.html
new file mode 100644
index 0000000..bbb3f26
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-ltr-002.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>CSS Selectors Level 4 Test: exception handling for an invalid identifier of dir()</title>
+    <link rel="author" title="Miyoung Shin" href="mailto:myid.shin@igalia.com">
+    <link rel="help" href="http://www.w3.org/TR/selectors4/#dir-pseudo">
+    <link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+    <meta name="flags" content="">
+    <meta name="assert" content="The invalid identifier of :dir(ltrr) pseudo-class doesn't match an element that has a directionality of (ltr). Even if the div element has dir=ltr, the selector should not match.">
+    <style type="text/css">
+       div {
+           width: 100px;
+           height: 100px;
+           background-color: green;
+       }
+
+       div:dir(ltrr) {
+           background-color: red;
+       }
+    </style>
+</head>
+<body>
+    <p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+    <div dir="ltr"></div>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-ltr-003.html b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-ltr-003.html
new file mode 100644
index 0000000..821a336
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-ltr-003.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>CSS Selectors Level 4 Test: exception handling for multiple identifiers of dir() </title>
+    <link rel="author" title="Miyoung Shin" href="mailto:myid.shin@igalia.com">
+    <link rel="help" href="http://www.w3.org/TR/selectors4/#dir-pseudo">
+    <link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+    <meta name="flags" content="">
+    <meta name="assert" content="The multiple identifiers of :dir(ltr, rtl) pseudo-class don't match an element that has a directionality of (ltr). Even if the div element has dir=ltr, the selector should not match.">
+    <style type="text/css">
+       div {
+           width: 100px;
+           height: 100px;
+           background-color: green;
+       }
+
+       div:dir(ltr, rtl) {
+           background-color: red;
+       }
+    </style>
+</head>
+<body>
+    <p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+    <div dir="ltr"></div>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-querySelector.html b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-querySelector.html
new file mode 100644
index 0000000..a05e3fe
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-querySelector.html
@@ -0,0 +1,71 @@
+<!doctype html>
+<html>
+<head>
+  <link rel="help" href="http://www.w3.org/TR/selectors4/#dir-pseudo">
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+</head>
+
+<body>
+  <div id=outer>
+    <div id=div1></div>
+    <div id=div2 dir=ltr>
+      <div id=div2_1></div>
+      <div id=div2_2 dir=ltr></div>
+      <div id=div2_3 dir=rtl></div>
+    </div>
+    <div id=div3 dir=rtl>
+      <div id=div3_1>
+        <div id=div3_1_1></div>
+      </div>
+      <div id=div3_2 dir=ltr></div>
+      <div id=div3_3 dir=rtl></div>
+    </div>
+    <div id=div4 dir=lol></div>
+    <div id=div5 dir=auto></div>
+  </div>
+</body>
+
+<script>
+test(() => {
+  assert_equals(document.querySelector(":dir(lol)"), null);
+  assert_equals(document.querySelector(":dir(lol )"), null);
+  assert_equals(document.querySelector(":dir( auto)"), null);
+  assert_equals(document.querySelector(":dir(\nauto\t)"), null);
+}, ":dir() allows any ident value but strings other than ltr/rtl don't match");
+
+test(() => {
+  assert_throws_dom("SYNTAX_ERR", () => { document.querySelector(":dir()"); });
+  assert_throws_dom("SYNTAX_ERR", () => { document.querySelector(":dir(ltr, rtl)"); });
+  assert_throws_dom("SYNTAX_ERR", () => { document.querySelector(":dir('ltr')"); });
+}, ":dir() requires exactly an ident argument");
+
+test(() => {
+  assert_equals(document.querySelector(":dir(rtl)"), div2_3);
+  assert_equals(document.querySelector("*:dir(rtl)"), div2_3);
+  assert_equals(document.querySelector("div:dir(ltr)"), outer);
+  assert_equals(document.querySelector("div:dir(ltr):dir(ltr)"), outer);
+  assert_equals(document.querySelector(":dir(rtl)#div3_3"), div3_3);
+  assert_equals(document.querySelector(":nth-child(2):dir(rtl)"), null);
+  assert_equals(document.querySelector(":nth-child(3):dir(rtl)"), div2_3);
+  assert_equals(document.querySelector(":nth-child(4):dir(ltr)"), div4);
+  assert_equals(document.querySelector(":nth-last-child(3):dir(rtl)"), div3);
+}, ":dir() works in compound selectors");
+
+test(() => {
+  assert_equals(document.querySelector("#div2 :dir(ltr)"), div2_1);
+  assert_equals(document.querySelector(":dir(rtl) div"), div3_1);
+  assert_equals(document.querySelector("div + :dir(ltr)"), div2);
+  assert_equals(document.querySelector(":dir(ltr) + :dir(rtl)"), div2_3);
+  assert_equals(document.querySelector(":dir(rtl) :dir(rtl)"), div3_1);
+  assert_equals(document.querySelector(":dir(rtl) + :dir(ltr)"), div3_2);
+  assert_equals(document.querySelector(":dir(rtl) ~ :dir(rtl)"), div3_3);
+  assert_equals(document.querySelector(":dir(rtl) :dir(ltr)"), div3_2);
+  assert_equals(document.querySelector("* :dir(rtl) *"), div3_1);
+  assert_equals(document.querySelector("div :dir(rtl) div"), div3_1);
+  assert_equals(document.querySelector(":dir(ltr) :dir(rtl) + :dir(ltr)"), div3_2);
+  assert_equals(document.querySelector(":dir(ltr) + :dir(rtl) + * + *"), div5);
+  assert_equals(document.querySelector(":dir(rtl) > * > :dir(rtl)"), div3_1_1);
+}, ":dir() works in complex selectors");
+</script>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-white-space-001-ref.html b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-white-space-001-ref.html
new file mode 100644
index 0000000..955a2dd
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-white-space-001-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <style type="text/css">
+       div {
+           width: 100px;
+           height: 100px;
+           background-color: green;
+       }
+    </style>
+</head>
+<body>
+    <p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+    <div></div>
+    <div></div>
+    <div></div>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-white-space-001.html b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-white-space-001.html
new file mode 100644
index 0000000..d3128a0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-dir-selector-white-space-001.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>CSS Selectors Level 4 Test: Verify for an identifier with leading and tailing whitespace of dir() </title>
+    <link rel="author" title="Miyoung Shin" href="mailto:myid.shin@igalia.com">
+    <link rel="help" href="http://www.w3.org/TR/selectors4/#dir-pseudo">
+    <link rel="match" href="selectors-dir-selector-white-space-001-ref.html">
+    <meta name="assert" content="The :dir(ltr) pseudo-class matches an element that has a directionality of (ltr). Since the div element has dir=ltr, the selector matches.">
+    <style type="text/css">
+       div {
+           width: 100px;
+           height: 100px;
+           background-color: red;
+       }
+
+       #a:dir( ltr) { background-color: green; }
+       #b:dir(ltr ) { background-color: green; }
+       #c:dir( ltr ) { background-color: green; }
+    </style>
+</head>
+<body>
+    <p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+    <div id="a" dir="ltr"></div>
+    <div id="b" dir="ltr"></div>
+    <div id="c" dir="ltr"></div>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/DIR_METADATA
new file mode 100644
index 0000000..85377a7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Layout"
+}
+team_email: "layout-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/OWNERS b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/OWNERS
index 5f43f91..5e03d9bc 100644
--- a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/OWNERS
@@ -1,4 +1 @@
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>Layout
-# WPT-NOTIFY: true
 rego@igalia.com
diff --git a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/DIR_METADATA
new file mode 100644
index 0000000..38ef497
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Layout>Flexbox"
+}
+team_email: "layout-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/OWNERS b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/OWNERS
index 3aa8367..51c6a57d 100644
--- a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/OWNERS
@@ -1,4 +1 @@
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>Layout>Flexbox
-# WPT-NOTIFY: true
 cbiesinger@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/DIR_METADATA
new file mode 100644
index 0000000..815ca00
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Layout>Shape"
+}
+team_email: "layout-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/OWNERS b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/OWNERS
deleted file mode 100644
index 5704d224..0000000
--- a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>Layout>Shape
-# WPT-NOTIFY: true
diff --git a/third_party/blink/web_tests/external/wpt/custom-elements/DIR_METADATA b/third_party/blink/web_tests/external/wpt/custom-elements/DIR_METADATA
new file mode 100644
index 0000000..1c2a667
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/custom-elements/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>HTML>CustomElements"
+}
+team_email: "dom-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/custom-elements/OWNERS b/third_party/blink/web_tests/external/wpt/custom-elements/OWNERS
deleted file mode 100644
index e1d5315..0000000
--- a/third_party/blink/web_tests/external/wpt/custom-elements/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# TEAM: dom-dev@chromium.org
-# COMPONENT: Blink>HTML>CustomElements
diff --git a/third_party/blink/web_tests/external/wpt/html-media-capture/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html-media-capture/DIR_METADATA
new file mode 100644
index 0000000..f76b084a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html-media-capture/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>ImageCapture"
+}
+team_email: "webrtc-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/html-media-capture/OWNERS b/third_party/blink/web_tests/external/wpt/html-media-capture/OWNERS
index bae3815..3c4f9b8 100644
--- a/third_party/blink/web_tests/external/wpt/html-media-capture/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/html-media-capture/OWNERS
@@ -1,4 +1,2 @@
-# TEAM: webrtc-dev@chromium.org
-# COMPONENT: Blink>ImageCapture
 
 rijubrata.bhaumik@intel.com
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/DIR_METADATA
new file mode 100644
index 0000000..85377a7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Layout"
+}
+team_email: "layout-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/OWNERS b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/OWNERS
deleted file mode 100644
index 9b2e5be..0000000
--- a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>Layout
-# WPT-NOTIFY: true
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-frameset-and-frame-elements/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-frameset-and-frame-elements/DIR_METADATA
new file mode 100644
index 0000000..85377a7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-frameset-and-frame-elements/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Layout"
+}
+team_email: "layout-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-frameset-and-frame-elements/OWNERS b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-frameset-and-frame-elements/OWNERS
deleted file mode 100644
index 9b2e5be..0000000
--- a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-frameset-and-frame-elements/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>Layout
-# WPT-NOTIFY: true
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-hr-element-0/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-hr-element-0/DIR_METADATA
new file mode 100644
index 0000000..85377a7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-hr-element-0/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Layout"
+}
+team_email: "layout-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-hr-element-0/OWNERS b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-hr-element-0/OWNERS
deleted file mode 100644
index 9b2e5be..0000000
--- a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-hr-element-0/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>Layout
-# WPT-NOTIFY: true
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/attributes-for-embedded-content-and-images/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/attributes-for-embedded-content-and-images/DIR_METADATA
new file mode 100644
index 0000000..85377a7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/attributes-for-embedded-content-and-images/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Layout"
+}
+team_email: "layout-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/attributes-for-embedded-content-and-images/OWNERS b/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/attributes-for-embedded-content-and-images/OWNERS
deleted file mode 100644
index 9b2e5be..0000000
--- a/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/attributes-for-embedded-content-and-images/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>Layout
-# WPT-NOTIFY: true
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/embedded-content-rendering-rules/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/embedded-content-rendering-rules/DIR_METADATA
new file mode 100644
index 0000000..85377a7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/embedded-content-rendering-rules/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Layout"
+}
+team_email: "layout-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/embedded-content-rendering-rules/OWNERS b/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/embedded-content-rendering-rules/OWNERS
deleted file mode 100644
index 9b2e5be..0000000
--- a/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/embedded-content-rendering-rules/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>Layout
-# WPT-NOTIFY: true
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/images/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/images/DIR_METADATA
new file mode 100644
index 0000000..85377a7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/images/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Layout"
+}
+team_email: "layout-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/images/OWNERS b/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/images/OWNERS
deleted file mode 100644
index 9b2e5be..0000000
--- a/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/images/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>Layout
-# WPT-NOTIFY: true
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/semantics/DIR_METADATA
new file mode 100644
index 0000000..1510459
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/DIR_METADATA
@@ -0,0 +1 @@
+team_email: "dom-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/OWNERS b/third_party/blink/web_tests/external/wpt/html/semantics/OWNERS
deleted file mode 100644
index 422c227..0000000
--- a/third_party/blink/web_tests/external/wpt/html/semantics/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-# TEAM: dom-dev@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/selectors/pseudo-classes/dir-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/selectors/pseudo-classes/dir-expected.txt
index 8d4f297..dc96464 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/selectors/pseudo-classes/dir-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/selectors/pseudo-classes/dir-expected.txt
@@ -1,6 +1,32 @@
 This is a testharness.js-based test.
-FAIL ':dir(rtl)' matches all elements whose directionality is 'rtl'. Failed to execute 'querySelectorAll' on 'Document': ':dir(rtl)' is not a valid selector.
-FAIL ':dir(ltr)' matches all elements whose directionality is 'ltr'. Failed to execute 'querySelectorAll' on 'Document': ':dir(ltr)' is not a valid selector.
-FAIL ':dir(ltr)' doesn't match elements not in the document. Failed to execute 'querySelectorAll' on 'Document': ':dir(ltr)' is not a valid selector.
+FAIL ':dir(rtl)' matches all elements whose directionality is 'rtl'. assert_array_equals: lengths differ, expected array [Element node <bdo dir="rtl" id="bdo1">WERBEH</bdo>, Element node <bdi dir="rtl" id="bdi2">WERBEH</bdi>, Element node <bdi id="bdi4">إيان</bdi>, Element node <span dir="rtl" id="span2">WERBEH</span>, Element node <span dir="rtl" id="span5">WERBEH</span>, Element node <span dir="rtl" id="span7">
+     <input type="tel" id="in..., Element node <input type="tel" id="input-tel3" dir="rtl"></input>, Element node <bdo dir="auto" id="bdo4">إيان</bdo>] length 8, got [Element node <bdo dir="rtl" id="bdo1">WERBEH</bdo>, Element node <bdi dir="rtl" id="bdi2">WERBEH</bdi>, Element node <bdi id="bdi4">إيان</bdi>, Element node <span dir="rtl" id="span2">WERBEH</span>, Element node <span dir="rtl" id="span5">WERBEH</span>, Element node <span dir="rtl" id="span7">
+     <input type="tel" id="in..., Element node <input type="tel" id="input-tel1"></input>, Element node <input type="tel" id="input-tel2" dir="invalid"></input>, Element node <input type="tel" id="input-tel3" dir="rtl"></input>, Element node <bdo dir="auto" id="bdo4">إيان</bdo>] length 10
+FAIL ':dir(ltr)' matches all elements whose directionality is 'ltr'. assert_array_equals: lengths differ, expected array […, Element node <link rel="author" title="Denis Ah-Kang" href="mailto:den..., Element node <link rel="help" href="https://html.spec.whatwg.org/multi..., Element node <script src="/resources/testharness.js" id="script1"></sc..., Element node <script src="/resources/testharnessreport.js" id="script2..., Element node <script src="utils.js" id="script3"></script>, Element node <style id="style">
+      #span1 {direction: rtl;}
+      #..., Element node <body id="body">
+    <div id="log"></div>
+    <bdo dir="r..., Element node <div id="log"></div>, Element node <bdo dir="ltr" id="bdo2">HEBREW</bdo>, Element node <bdi id="bdi1">HEBREW</bdi>, Element node <bdi dir="ltr" id="bdi3">HEBREW</bdi>, Element node <span id="span1">WERBEH</span>, Element node <span dir="ltr" id="span3">HEBREW</span>, Element node <span id="span4">WERBEH</span>, Element node <span dir="ltr" id="span6">HEBREW</span>, Element node <input type="tel" id="input-tel1"></input>, Element node <input type="tel" id="input-tel2" dir="invalid"></input>, Element node <bdo dir="auto" id="bdo3">HEBREW</bdo>, Element node <bdo dir="ltr" id="bdo5">עברית</bdo>, Element node <script id="script4">
+      const rtlElements = [
+       ...] length 24, got […, Element node <meta charset="utf-8" id="meta"></meta>, Element node <title id="title">Selector: pseudo-classes (:dir(ltr), :d..., Element node <link rel="author" title="Denis Ah-Kang" href="mailto:den..., Element node <link rel="help" href="https://html.spec.whatwg.org/multi..., Element node <script src="/resources/testharness.js" id="script1"></sc..., Element node <script src="/resources/testharnessreport.js" id="script2..., Element node <script src="utils.js" id="script3"></script>, Element node <style id="style">
+      #span1 {direction: rtl;}
+      #..., Element node <body id="body">
+    <div id="log"></div>
+    <bdo dir="r..., Element node <div id="log"></div>, Element node <bdo dir="ltr" id="bdo2">HEBREW</bdo>, Element node <bdi id="bdi1">HEBREW</bdi>, Element node <bdi dir="ltr" id="bdi3">HEBREW</bdi>, Element node <span id="span1">WERBEH</span>, Element node <span dir="ltr" id="span3">HEBREW</span>, Element node <span id="span4">WERBEH</span>, Element node <span dir="ltr" id="span6">HEBREW</span>, Element node <bdo dir="auto" id="bdo3">HEBREW</bdo>, Element node <bdo dir="ltr" id="bdo5">עברית</bdo>, Element node <script id="script4">
+      const rtlElements = [
+       ...] length 22
+FAIL ':dir(ltr)' doesn't match elements not in the document. assert_array_equals: lengths differ, expected array […, Element node <link rel="author" title="Denis Ah-Kang" href="mailto:den..., Element node <link rel="help" href="https://html.spec.whatwg.org/multi..., Element node <script src="/resources/testharness.js" id="script1"></sc..., Element node <script src="/resources/testharnessreport.js" id="script2..., Element node <script src="utils.js" id="script3"></script>, Element node <style id="style">
+      #span1 {direction: rtl;}
+      #..., Element node <body id="body">
+    <div id="log"></div>
+    <bdo dir="r..., Element node <div id="log"></div>, Element node <bdo dir="ltr" id="bdo2">HEBREW</bdo>, Element node <bdi id="bdi1">HEBREW</bdi>, Element node <bdi dir="ltr" id="bdi3">HEBREW</bdi>, Element node <span id="span1">WERBEH</span>, Element node <span dir="ltr" id="span3">HEBREW</span>, Element node <span id="span4">WERBEH</span>, Element node <span dir="ltr" id="span6">HEBREW</span>, Element node <input type="tel" id="input-tel1"></input>, Element node <input type="tel" id="input-tel2" dir="invalid"></input>, Element node <bdo dir="auto" id="bdo3">HEBREW</bdo>, Element node <bdo dir="ltr" id="bdo5">עברית</bdo>, Element node <script id="script4">
+      const rtlElements = [
+       ...] length 24, got […, Element node <meta charset="utf-8" id="meta"></meta>, Element node <title id="title">Selector: pseudo-classes (:dir(ltr), :d..., Element node <link rel="author" title="Denis Ah-Kang" href="mailto:den..., Element node <link rel="help" href="https://html.spec.whatwg.org/multi..., Element node <script src="/resources/testharness.js" id="script1"></sc..., Element node <script src="/resources/testharnessreport.js" id="script2..., Element node <script src="utils.js" id="script3"></script>, Element node <style id="style">
+      #span1 {direction: rtl;}
+      #..., Element node <body id="body">
+    <div id="log"></div>
+    <bdo dir="r..., Element node <div id="log"></div>, Element node <bdo dir="ltr" id="bdo2">HEBREW</bdo>, Element node <bdi id="bdi1">HEBREW</bdi>, Element node <bdi dir="ltr" id="bdi3">HEBREW</bdi>, Element node <span id="span1">WERBEH</span>, Element node <span dir="ltr" id="span3">HEBREW</span>, Element node <span id="span4">WERBEH</span>, Element node <span dir="ltr" id="span6">HEBREW</span>, Element node <bdo dir="auto" id="bdo3">HEBREW</bdo>, Element node <bdo dir="ltr" id="bdo5">עברית</bdo>, Element node <script id="script4">
+      const rtlElements = [
+       ...] length 22
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/selectors/pseudo-classes/dir-html-input-dynamic-text-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/selectors/pseudo-classes/dir-html-input-dynamic-text-expected.txt
deleted file mode 100644
index d26b681..0000000
--- a/third_party/blink/web_tests/external/wpt/html/semantics/selectors/pseudo-classes/dir-html-input-dynamic-text-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL :dir on <input> isn't altered by text children Failed to execute 'matches' on 'Element': ':dir(ltr)' is not a valid selector.
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/selectors/pseudo-classes/dir01-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/selectors/pseudo-classes/dir01-expected.txt
deleted file mode 100644
index dc08da0..0000000
--- a/third_party/blink/web_tests/external/wpt/html/semantics/selectors/pseudo-classes/dir01-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL direction doesn't affect :dir() Failed to execute 'querySelectorAll' on 'Document': ':dir(ltr)' is not a valid selector.
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/html/syntax/parsing/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/syntax/parsing/DIR_METADATA
new file mode 100644
index 0000000..1510459
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/syntax/parsing/DIR_METADATA
@@ -0,0 +1 @@
+team_email: "dom-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/html/syntax/parsing/OWNERS b/third_party/blink/web_tests/external/wpt/html/syntax/parsing/OWNERS
deleted file mode 100644
index 422c227..0000000
--- a/third_party/blink/web_tests/external/wpt/html/syntax/parsing/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-# TEAM: dom-dev@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/html/syntax/serializing-html-fragments/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/syntax/serializing-html-fragments/DIR_METADATA
new file mode 100644
index 0000000..1510459
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/syntax/serializing-html-fragments/DIR_METADATA
@@ -0,0 +1 @@
+team_email: "dom-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/html/syntax/serializing-html-fragments/OWNERS b/third_party/blink/web_tests/external/wpt/html/syntax/serializing-html-fragments/OWNERS
deleted file mode 100644
index 422c227..0000000
--- a/third_party/blink/web_tests/external/wpt/html/syntax/serializing-html-fragments/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-# TEAM: dom-dev@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/html/syntax/serializing-xml-fragments/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/syntax/serializing-xml-fragments/DIR_METADATA
new file mode 100644
index 0000000..1510459
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/syntax/serializing-xml-fragments/DIR_METADATA
@@ -0,0 +1 @@
+team_email: "dom-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/html/syntax/serializing-xml-fragments/OWNERS b/third_party/blink/web_tests/external/wpt/html/syntax/serializing-xml-fragments/OWNERS
deleted file mode 100644
index 422c227..0000000
--- a/third_party/blink/web_tests/external/wpt/html/syntax/serializing-xml-fragments/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-# TEAM: dom-dev@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/html/user-activation/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/user-activation/DIR_METADATA
new file mode 100644
index 0000000..4a2c8aa
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/user-activation/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Input"
+}
+team_email: "input-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/html/user-activation/OWNERS b/third_party/blink/web_tests/external/wpt/html/user-activation/OWNERS
index f17b123..35449ec5 100644
--- a/third_party/blink/web_tests/external/wpt/html/user-activation/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/html/user-activation/OWNERS
@@ -1,4 +1 @@
-# TEAM: input-dev@chromium.org
-# COMPONENT: Blink>Input
-# WPT-NOTIFY: true
 mustaq@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/closing-the-input-stream/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/closing-the-input-stream/DIR_METADATA
new file mode 100644
index 0000000..1510459
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/closing-the-input-stream/DIR_METADATA
@@ -0,0 +1 @@
+team_email: "dom-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/closing-the-input-stream/OWNERS b/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/closing-the-input-stream/OWNERS
deleted file mode 100644
index 422c227..0000000
--- a/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/closing-the-input-stream/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-# TEAM: dom-dev@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/document-write/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/document-write/DIR_METADATA
new file mode 100644
index 0000000..1510459
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/document-write/DIR_METADATA
@@ -0,0 +1 @@
+team_email: "dom-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/document-write/OWNERS b/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/document-write/OWNERS
deleted file mode 100644
index 422c227..0000000
--- a/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/document-write/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-# TEAM: dom-dev@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/document-writeln/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/document-writeln/DIR_METADATA
new file mode 100644
index 0000000..1510459
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/document-writeln/DIR_METADATA
@@ -0,0 +1 @@
+team_email: "dom-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/document-writeln/OWNERS b/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/document-writeln/OWNERS
deleted file mode 100644
index 422c227..0000000
--- a/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/document-writeln/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-# TEAM: dom-dev@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/DIR_METADATA
new file mode 100644
index 0000000..1510459
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/DIR_METADATA
@@ -0,0 +1 @@
+team_email: "dom-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/OWNERS b/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/OWNERS
deleted file mode 100644
index 422c227..0000000
--- a/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-# TEAM: dom-dev@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/event-loops/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/event-loops/DIR_METADATA
new file mode 100644
index 0000000..1510459
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/event-loops/DIR_METADATA
@@ -0,0 +1 @@
+team_email: "dom-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/event-loops/OWNERS b/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/event-loops/OWNERS
deleted file mode 100644
index 422c227..0000000
--- a/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/event-loops/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-# TEAM: dom-dev@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/events/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/events/DIR_METADATA
new file mode 100644
index 0000000..1510459
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/events/DIR_METADATA
@@ -0,0 +1 @@
+team_email: "dom-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/events/OWNERS b/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/events/OWNERS
deleted file mode 100644
index 422c227..0000000
--- a/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/events/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-# TEAM: dom-dev@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/processing-model-2/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/processing-model-2/DIR_METADATA
new file mode 100644
index 0000000..1510459
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/processing-model-2/DIR_METADATA
@@ -0,0 +1 @@
+team_email: "dom-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/processing-model-2/OWNERS b/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/processing-model-2/OWNERS
deleted file mode 100644
index 422c227..0000000
--- a/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/processing-model-2/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-# TEAM: dom-dev@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/imagebitmap-renderingcontext/DIR_METADATA b/third_party/blink/web_tests/external/wpt/imagebitmap-renderingcontext/DIR_METADATA
new file mode 100644
index 0000000..866f703
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/imagebitmap-renderingcontext/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Canvas"
+}
+team_email: "paint-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/imagebitmap-renderingcontext/OWNERS b/third_party/blink/web_tests/external/wpt/imagebitmap-renderingcontext/OWNERS
deleted file mode 100644
index 3b83b67..0000000
--- a/third_party/blink/web_tests/external/wpt/imagebitmap-renderingcontext/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# TEAM: paint-dev@chromium.org
-# COMPONENT: Blink>Canvas
-# WPT-NOTIFY: true
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/images/DIR_METADATA b/third_party/blink/web_tests/external/wpt/images/DIR_METADATA
new file mode 100644
index 0000000..13df631
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/images/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Image"
+}
+team_email: "paint-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/images/OWNERS b/third_party/blink/web_tests/external/wpt/images/OWNERS
deleted file mode 100644
index 6640d0e..0000000
--- a/third_party/blink/web_tests/external/wpt/images/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# TEAM: paint-dev@chromium.org
-# COMPONENT: Blink>Image
-# WPT-NOTIFY: true
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/DIR_METADATA b/third_party/blink/web_tests/external/wpt/infrastructure/DIR_METADATA
index 8e9f60a..da335b9 100644
--- a/third_party/blink/web_tests/external/wpt/infrastructure/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/infrastructure/DIR_METADATA
@@ -1,9 +1,7 @@
 monorail {
-  project: "chromium"
   component: "Blink>Infra>Ecosystem"
 }
 team_email: "ecosystem-infra@chromium.org"
-os: LINUX
 wpt {
   notify: YES
 }
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/OWNERS b/third_party/blink/web_tests/external/wpt/infrastructure/OWNERS
index 49891ac8..0df202b 100644
--- a/third_party/blink/web_tests/external/wpt/infrastructure/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/infrastructure/OWNERS
@@ -1,6 +1,3 @@
-# TEAM: ecosystem-infra@chromium.org
-# COMPONENT: Blink>Infra>Ecosystem
-# WPT-NOTIFY: true
 foolip@chromium.org
 robertma@chromium.org
 smcgruer@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/actions/DIR_METADATA b/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/actions/DIR_METADATA
new file mode 100644
index 0000000..4a2c8aa
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/actions/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Input"
+}
+team_email: "input-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/actions/OWNERS b/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/actions/OWNERS
index 6aa7ab7..dee5bb0f 100644
--- a/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/actions/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/actions/OWNERS
@@ -1,4 +1 @@
-# TEAM: input-dev@chromium.org
-# COMPONENT: Blink>Input
-# WPT-NOTIFY: true
 lanwei@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/input-events/DIR_METADATA b/third_party/blink/web_tests/external/wpt/input-events/DIR_METADATA
new file mode 100644
index 0000000..4a2c8aa
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/input-events/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Input"
+}
+team_email: "input-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/input-events/OWNERS b/third_party/blink/web_tests/external/wpt/input-events/OWNERS
index 3b44901..004dcc9 100644
--- a/third_party/blink/web_tests/external/wpt/input-events/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/input-events/OWNERS
@@ -1,5 +1,2 @@
-# TEAM: input-dev@chromium.org
-# COMPONENT: Blink>Input
-# WPT-NOTIFY: true
 nzolghadr@chromium.org
 yosin@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/intersection-observer/DIR_METADATA b/third_party/blink/web_tests/external/wpt/intersection-observer/DIR_METADATA
new file mode 100644
index 0000000..85377a7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/intersection-observer/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Layout"
+}
+team_email: "layout-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/intersection-observer/OWNERS b/third_party/blink/web_tests/external/wpt/intersection-observer/OWNERS
index 1d4fb997..ac2b5a2 100644
--- a/third_party/blink/web_tests/external/wpt/intersection-observer/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/intersection-observer/OWNERS
@@ -1,5 +1,2 @@
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>Layout
-# WPT-NOTIFY: true
 eae@chromium.org
 szager@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/native-file-system/showPicker-errors.https.window.js b/third_party/blink/web_tests/external/wpt/native-file-system/showPicker-errors.https.window.js
index e8f0d3f..d1dabf3 100644
--- a/third_party/blink/web_tests/external/wpt/native-file-system/showPicker-errors.https.window.js
+++ b/third_party/blink/web_tests/external/wpt/native-file-system/showPicker-errors.https.window.js
@@ -80,9 +80,39 @@
       showPickerMethod +
           ': MIME type can\'t have invalid characters in subtype.');
 
-  promise_test(async t => {
-    await promise_rejects_js(t, TypeError, self[showPickerMethod]({
-                               types: [{accept: {'text/plain': ['.txt', 'txt']}}]
-                             }));
-  }, showPickerMethod + ': extension has to start with ".".');
+  const invalid_extensions = {
+    '.extensiontoolong': 'extension length more than 16.',
+    '.txt.': 'extenstion ends with "."',
+    'txt': 'extenstion does not start with "."',
+    '.$txt' : 'illegal character "$"',
+    '.t<xt': 'illegal character "<"',
+    '.t/xt': 'illegal character "\"',
+    '.\txt': 'illegal character "/"',
+    '.txt\\': 'illegal characters "\\"',
+    '.txt?': 'illegal character "?"',
+    '.txt*': 'illegal character "*"',
+    '.{txt': 'illegal character "{"',
+    '.}txt': 'illegal character "}"',
+    ' .txt': 'illegal whitespace at front of extension',
+    '. txt': 'illegal whitespace in extension',
+    '.txt ': 'illegal whitespace at end of extension',
+    '.\u202etxt\u202e' : 'illegal RTL character',
+    '.t\u00E6xt': 'non-ASCII character "æ"',
+    '.קום': 'non-ASCII character "קום"',
+    '.txt🙂': 'non-ASCII character "🙂"',
+    '.{txt}': 'illegal characters "{" and "}"',
+  }
+
+  for (const [extension, description] of Object.entries(invalid_extensions)) {
+    define_file_picker_extension_error_test(showPickerMethod, extension, description)
+  }
 }
+
+function define_file_picker_extension_error_test(showPickerMethod, extension, description) {
+  promise_test(async t => {
+    await promise_rejects_js(
+      t, TypeError,
+      self[showPickerMethod](
+        { types: [{ accept: { 'text/plain': ['.txt', extension] } }] }));
+  }, showPickerMethod + ': invalid extension "' + extension + '". ' + description + ".");
+}
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/selection/DIR_METADATA b/third_party/blink/web_tests/external/wpt/selection/DIR_METADATA
new file mode 100644
index 0000000..484b90d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/selection/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>Editing>Selection"
+}
+team_email: "layout-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/selection/OWNERS b/third_party/blink/web_tests/external/wpt/selection/OWNERS
deleted file mode 100644
index 259ded51..0000000
--- a/third_party/blink/web_tests/external/wpt/selection/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# TEAM: layout-dev@chromium.org
-# COMPONENT: Blink>Editing>Selection
diff --git a/third_party/blink/web_tests/external/wpt/server-timing/DIR_METADATA b/third_party/blink/web_tests/external/wpt/server-timing/DIR_METADATA
new file mode 100644
index 0000000..34d52c7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/server-timing/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>PerformanceAPIs>ServerTiming"
+}
+team_email: "loading-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/server-timing/OWNERS b/third_party/blink/web_tests/external/wpt/server-timing/OWNERS
index 46e79e05..2746bb9 100644
--- a/third_party/blink/web_tests/external/wpt/server-timing/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/server-timing/OWNERS
@@ -1,4 +1,2 @@
-# TEAM: loading-dev@chromium.org
-# COMPONENT: Blink>PerformanceAPIs>ServerTiming
 cvazac@akamai.com
 igrigorik@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/DIR_METADATA b/third_party/blink/web_tests/external/wpt/service-workers/DIR_METADATA
new file mode 100644
index 0000000..23931a5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/service-workers/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>ServiceWorker"
+}
+team_email: "worker-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/OWNERS b/third_party/blink/web_tests/external/wpt/service-workers/OWNERS
index c7c9d2c..245436a 100644
--- a/third_party/blink/web_tests/external/wpt/service-workers/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/service-workers/OWNERS
@@ -1,4 +1 @@
-# TEAM: worker-dev@chromium.org
-# COMPONENT: Blink>ServiceWorker
-# WPT-NOTIFY: true
 file://content/browser/service_worker/OWNERS
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/DIR_METADATA b/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/DIR_METADATA
new file mode 100644
index 0000000..f48eedf
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Storage>CacheStorage"
+}
+team_email: "storage-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/OWNERS b/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/OWNERS
index afb2620..82c8165 100644
--- a/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/OWNERS
@@ -1,4 +1 @@
-# TEAM: storage-dev@chromium.org
-# COMPONENT: Blink>Storage>CacheStorage
-# WPT-NOTIFY: true
 jsbell@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/shadow-dom/DIR_METADATA b/third_party/blink/web_tests/external/wpt/shadow-dom/DIR_METADATA
new file mode 100644
index 0000000..407e33f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/shadow-dom/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>DOM>ShadowDOM"
+}
+team_email: "dom-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/shadow-dom/OWNERS b/third_party/blink/web_tests/external/wpt/shadow-dom/OWNERS
deleted file mode 100644
index 5fc1b89..0000000
--- a/third_party/blink/web_tests/external/wpt/shadow-dom/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# TEAM: dom-dev@chromium.org
-# COMPONENT: Blink>DOM>ShadowDOM
diff --git a/third_party/blink/web_tests/external/wpt/storage/DIR_METADATA b/third_party/blink/web_tests/external/wpt/storage/DIR_METADATA
new file mode 100644
index 0000000..56c0693
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/storage/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Storage>Quota"
+}
+team_email: "storage-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/storage/OWNERS b/third_party/blink/web_tests/external/wpt/storage/OWNERS
index ce2ae1f..82c8165 100644
--- a/third_party/blink/web_tests/external/wpt/storage/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/storage/OWNERS
@@ -1,4 +1 @@
-# TEAM: storage-dev@chromium.org
-# COMPONENT: Blink>Storage>Quota
-# WPT-NOTIFY: true
 jsbell@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/streams/DIR_METADATA b/third_party/blink/web_tests/external/wpt/streams/DIR_METADATA
new file mode 100644
index 0000000..04b78c0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/streams/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Network>StreamsAPI"
+}
+team_email: "blink-network-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/streams/OWNERS b/third_party/blink/web_tests/external/wpt/streams/OWNERS
index 041c2b6..0431035 100644
--- a/third_party/blink/web_tests/external/wpt/streams/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/streams/OWNERS
@@ -1,5 +1,2 @@
-# TEAM: blink-network-dev@chromium.org
-# COMPONENT: Blink>Network>StreamsAPI
-# WPT-NOTIFY: true
 domenic@chromium.org
 ricea@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/streams/idlharness.any-expected.txt b/third_party/blink/web_tests/external/wpt/streams/idlharness.any-expected.txt
index bf60a89..ac189daf 100644
--- a/third_party/blink/web_tests/external/wpt/streams/idlharness.any-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/streams/idlharness.any-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 224 tests; 139 PASS, 85 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 224 tests; 193 PASS, 31 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS idl_test setup
 PASS idl_test validation
 PASS ReadableStreamDefaultReader includes ReadableStreamGenericReader: member names are unique
@@ -46,24 +46,24 @@
 PASS ReadableStreamDefaultReader interface: (new ReadableStream()).getReader() must inherit property "closed" with the proper type
 PASS ReadableStreamDefaultReader interface: (new ReadableStream()).getReader() must inherit property "cancel(optional any)" with the proper type
 PASS ReadableStreamDefaultReader interface: calling cancel(optional any) on (new ReadableStream()).getReader() with too few arguments must throw TypeError
-FAIL ReadableStreamBYOBReader interface: existence and properties of interface object assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface object length assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface object name assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface: existence and properties of interface prototype object assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface: operation read(ArrayBufferView) assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface: operation releaseLock() assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface: attribute closed assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface: operation cancel(optional any) assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader must be primary interface of (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
-FAIL Stringification of (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
-FAIL ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "read(ArrayBufferView)" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
-FAIL ReadableStreamBYOBReader interface: calling read(ArrayBufferView) on (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) with too few arguments must throw TypeError assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
-FAIL ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "releaseLock()" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
-FAIL ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "closed" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
-FAIL ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "cancel(optional any)" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
-FAIL ReadableStreamBYOBReader interface: calling cancel(optional any) on (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) with too few arguments must throw TypeError assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
+PASS ReadableStreamBYOBReader interface: existence and properties of interface object
+PASS ReadableStreamBYOBReader interface object length
+PASS ReadableStreamBYOBReader interface object name
+PASS ReadableStreamBYOBReader interface: existence and properties of interface prototype object
+PASS ReadableStreamBYOBReader interface: existence and properties of interface prototype object's "constructor" property
+PASS ReadableStreamBYOBReader interface: existence and properties of interface prototype object's @@unscopables property
+PASS ReadableStreamBYOBReader interface: operation read(ArrayBufferView)
+PASS ReadableStreamBYOBReader interface: operation releaseLock()
+PASS ReadableStreamBYOBReader interface: attribute closed
+PASS ReadableStreamBYOBReader interface: operation cancel(optional any)
+PASS ReadableStreamBYOBReader must be primary interface of (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' })
+PASS Stringification of (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' })
+PASS ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "read(ArrayBufferView)" with the proper type
+PASS ReadableStreamBYOBReader interface: calling read(ArrayBufferView) on (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) with too few arguments must throw TypeError
+PASS ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "releaseLock()" with the proper type
+PASS ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "closed" with the proper type
+PASS ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "cancel(optional any)" with the proper type
+PASS ReadableStreamBYOBReader interface: calling cancel(optional any) on (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) with too few arguments must throw TypeError
 FAIL ReadableStreamDefaultController interface: existence and properties of interface object assert_own_property: self does not have own property "ReadableStreamDefaultController" expected property "ReadableStreamDefaultController" missing
 FAIL ReadableStreamDefaultController interface object length assert_own_property: self does not have own property "ReadableStreamDefaultController" expected property "ReadableStreamDefaultController" missing
 FAIL ReadableStreamDefaultController interface object name assert_own_property: self does not have own property "ReadableStreamDefaultController" expected property "ReadableStreamDefaultController" missing
@@ -82,42 +82,42 @@
 PASS ReadableStreamDefaultController interface: calling enqueue(optional any) on self.readableStreamDefaultController with too few arguments must throw TypeError
 PASS ReadableStreamDefaultController interface: self.readableStreamDefaultController must inherit property "error(optional any)" with the proper type
 PASS ReadableStreamDefaultController interface: calling error(optional any) on self.readableStreamDefaultController with too few arguments must throw TypeError
-FAIL ReadableByteStreamController interface: existence and properties of interface object assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface object length assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface object name assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: existence and properties of interface prototype object assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: attribute byobRequest assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: attribute desiredSize assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: operation close() assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: operation enqueue(ArrayBufferView) assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: operation error(optional any) assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController must be primary interface of self.readableByteStreamController assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL Stringification of self.readableByteStreamController assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableByteStreamController interface: self.readableByteStreamController must inherit property "byobRequest" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableByteStreamController interface: self.readableByteStreamController must inherit property "desiredSize" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableByteStreamController interface: self.readableByteStreamController must inherit property "close()" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableByteStreamController interface: self.readableByteStreamController must inherit property "enqueue(ArrayBufferView)" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableByteStreamController interface: calling enqueue(ArrayBufferView) on self.readableByteStreamController with too few arguments must throw TypeError assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableByteStreamController interface: self.readableByteStreamController must inherit property "error(optional any)" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableByteStreamController interface: calling error(optional any) on self.readableByteStreamController with too few arguments must throw TypeError assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableStreamBYOBRequest interface: existence and properties of interface object assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface object length assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface object name assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface: existence and properties of interface prototype object assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface: attribute view assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface: operation respond(unsigned long long) assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface: operation respondWithNewView(ArrayBufferView) assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest must be primary interface of self.readableStreamByobRequest assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL Stringification of self.readableStreamByobRequest assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableStreamBYOBRequest interface: self.readableStreamByobRequest must inherit property "view" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableStreamBYOBRequest interface: self.readableStreamByobRequest must inherit property "respond(unsigned long long)" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableStreamBYOBRequest interface: calling respond(unsigned long long) on self.readableStreamByobRequest with too few arguments must throw TypeError assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableStreamBYOBRequest interface: self.readableStreamByobRequest must inherit property "respondWithNewView(ArrayBufferView)" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableStreamBYOBRequest interface: calling respondWithNewView(ArrayBufferView) on self.readableStreamByobRequest with too few arguments must throw TypeError assert_equals: wrong typeof object expected "object" but got "undefined"
+PASS ReadableByteStreamController interface: existence and properties of interface object
+PASS ReadableByteStreamController interface object length
+PASS ReadableByteStreamController interface object name
+PASS ReadableByteStreamController interface: existence and properties of interface prototype object
+PASS ReadableByteStreamController interface: existence and properties of interface prototype object's "constructor" property
+PASS ReadableByteStreamController interface: existence and properties of interface prototype object's @@unscopables property
+PASS ReadableByteStreamController interface: attribute byobRequest
+PASS ReadableByteStreamController interface: attribute desiredSize
+PASS ReadableByteStreamController interface: operation close()
+PASS ReadableByteStreamController interface: operation enqueue(ArrayBufferView)
+PASS ReadableByteStreamController interface: operation error(optional any)
+PASS ReadableByteStreamController must be primary interface of self.readableByteStreamController
+PASS Stringification of self.readableByteStreamController
+PASS ReadableByteStreamController interface: self.readableByteStreamController must inherit property "byobRequest" with the proper type
+PASS ReadableByteStreamController interface: self.readableByteStreamController must inherit property "desiredSize" with the proper type
+PASS ReadableByteStreamController interface: self.readableByteStreamController must inherit property "close()" with the proper type
+PASS ReadableByteStreamController interface: self.readableByteStreamController must inherit property "enqueue(ArrayBufferView)" with the proper type
+PASS ReadableByteStreamController interface: calling enqueue(ArrayBufferView) on self.readableByteStreamController with too few arguments must throw TypeError
+PASS ReadableByteStreamController interface: self.readableByteStreamController must inherit property "error(optional any)" with the proper type
+PASS ReadableByteStreamController interface: calling error(optional any) on self.readableByteStreamController with too few arguments must throw TypeError
+PASS ReadableStreamBYOBRequest interface: existence and properties of interface object
+PASS ReadableStreamBYOBRequest interface object length
+PASS ReadableStreamBYOBRequest interface object name
+PASS ReadableStreamBYOBRequest interface: existence and properties of interface prototype object
+PASS ReadableStreamBYOBRequest interface: existence and properties of interface prototype object's "constructor" property
+PASS ReadableStreamBYOBRequest interface: existence and properties of interface prototype object's @@unscopables property
+PASS ReadableStreamBYOBRequest interface: attribute view
+PASS ReadableStreamBYOBRequest interface: operation respond(unsigned long long)
+PASS ReadableStreamBYOBRequest interface: operation respondWithNewView(ArrayBufferView)
+PASS ReadableStreamBYOBRequest must be primary interface of self.readableStreamByobRequest
+PASS Stringification of self.readableStreamByobRequest
+PASS ReadableStreamBYOBRequest interface: self.readableStreamByobRequest must inherit property "view" with the proper type
+PASS ReadableStreamBYOBRequest interface: self.readableStreamByobRequest must inherit property "respond(unsigned long long)" with the proper type
+PASS ReadableStreamBYOBRequest interface: calling respond(unsigned long long) on self.readableStreamByobRequest with too few arguments must throw TypeError
+PASS ReadableStreamBYOBRequest interface: self.readableStreamByobRequest must inherit property "respondWithNewView(ArrayBufferView)" with the proper type
+PASS ReadableStreamBYOBRequest interface: calling respondWithNewView(ArrayBufferView) on self.readableStreamByobRequest with too few arguments must throw TypeError
 PASS WritableStream interface: existence and properties of interface object
 PASS WritableStream interface object length
 PASS WritableStream interface object name
diff --git a/third_party/blink/web_tests/external/wpt/streams/idlharness.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/streams/idlharness.any.serviceworker-expected.txt
index bf60a89..ac189daf 100644
--- a/third_party/blink/web_tests/external/wpt/streams/idlharness.any.serviceworker-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/streams/idlharness.any.serviceworker-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 224 tests; 139 PASS, 85 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 224 tests; 193 PASS, 31 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS idl_test setup
 PASS idl_test validation
 PASS ReadableStreamDefaultReader includes ReadableStreamGenericReader: member names are unique
@@ -46,24 +46,24 @@
 PASS ReadableStreamDefaultReader interface: (new ReadableStream()).getReader() must inherit property "closed" with the proper type
 PASS ReadableStreamDefaultReader interface: (new ReadableStream()).getReader() must inherit property "cancel(optional any)" with the proper type
 PASS ReadableStreamDefaultReader interface: calling cancel(optional any) on (new ReadableStream()).getReader() with too few arguments must throw TypeError
-FAIL ReadableStreamBYOBReader interface: existence and properties of interface object assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface object length assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface object name assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface: existence and properties of interface prototype object assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface: operation read(ArrayBufferView) assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface: operation releaseLock() assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface: attribute closed assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface: operation cancel(optional any) assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader must be primary interface of (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
-FAIL Stringification of (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
-FAIL ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "read(ArrayBufferView)" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
-FAIL ReadableStreamBYOBReader interface: calling read(ArrayBufferView) on (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) with too few arguments must throw TypeError assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
-FAIL ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "releaseLock()" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
-FAIL ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "closed" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
-FAIL ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "cancel(optional any)" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
-FAIL ReadableStreamBYOBReader interface: calling cancel(optional any) on (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) with too few arguments must throw TypeError assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
+PASS ReadableStreamBYOBReader interface: existence and properties of interface object
+PASS ReadableStreamBYOBReader interface object length
+PASS ReadableStreamBYOBReader interface object name
+PASS ReadableStreamBYOBReader interface: existence and properties of interface prototype object
+PASS ReadableStreamBYOBReader interface: existence and properties of interface prototype object's "constructor" property
+PASS ReadableStreamBYOBReader interface: existence and properties of interface prototype object's @@unscopables property
+PASS ReadableStreamBYOBReader interface: operation read(ArrayBufferView)
+PASS ReadableStreamBYOBReader interface: operation releaseLock()
+PASS ReadableStreamBYOBReader interface: attribute closed
+PASS ReadableStreamBYOBReader interface: operation cancel(optional any)
+PASS ReadableStreamBYOBReader must be primary interface of (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' })
+PASS Stringification of (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' })
+PASS ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "read(ArrayBufferView)" with the proper type
+PASS ReadableStreamBYOBReader interface: calling read(ArrayBufferView) on (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) with too few arguments must throw TypeError
+PASS ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "releaseLock()" with the proper type
+PASS ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "closed" with the proper type
+PASS ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "cancel(optional any)" with the proper type
+PASS ReadableStreamBYOBReader interface: calling cancel(optional any) on (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) with too few arguments must throw TypeError
 FAIL ReadableStreamDefaultController interface: existence and properties of interface object assert_own_property: self does not have own property "ReadableStreamDefaultController" expected property "ReadableStreamDefaultController" missing
 FAIL ReadableStreamDefaultController interface object length assert_own_property: self does not have own property "ReadableStreamDefaultController" expected property "ReadableStreamDefaultController" missing
 FAIL ReadableStreamDefaultController interface object name assert_own_property: self does not have own property "ReadableStreamDefaultController" expected property "ReadableStreamDefaultController" missing
@@ -82,42 +82,42 @@
 PASS ReadableStreamDefaultController interface: calling enqueue(optional any) on self.readableStreamDefaultController with too few arguments must throw TypeError
 PASS ReadableStreamDefaultController interface: self.readableStreamDefaultController must inherit property "error(optional any)" with the proper type
 PASS ReadableStreamDefaultController interface: calling error(optional any) on self.readableStreamDefaultController with too few arguments must throw TypeError
-FAIL ReadableByteStreamController interface: existence and properties of interface object assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface object length assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface object name assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: existence and properties of interface prototype object assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: attribute byobRequest assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: attribute desiredSize assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: operation close() assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: operation enqueue(ArrayBufferView) assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: operation error(optional any) assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController must be primary interface of self.readableByteStreamController assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL Stringification of self.readableByteStreamController assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableByteStreamController interface: self.readableByteStreamController must inherit property "byobRequest" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableByteStreamController interface: self.readableByteStreamController must inherit property "desiredSize" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableByteStreamController interface: self.readableByteStreamController must inherit property "close()" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableByteStreamController interface: self.readableByteStreamController must inherit property "enqueue(ArrayBufferView)" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableByteStreamController interface: calling enqueue(ArrayBufferView) on self.readableByteStreamController with too few arguments must throw TypeError assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableByteStreamController interface: self.readableByteStreamController must inherit property "error(optional any)" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableByteStreamController interface: calling error(optional any) on self.readableByteStreamController with too few arguments must throw TypeError assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableStreamBYOBRequest interface: existence and properties of interface object assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface object length assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface object name assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface: existence and properties of interface prototype object assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface: attribute view assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface: operation respond(unsigned long long) assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface: operation respondWithNewView(ArrayBufferView) assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest must be primary interface of self.readableStreamByobRequest assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL Stringification of self.readableStreamByobRequest assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableStreamBYOBRequest interface: self.readableStreamByobRequest must inherit property "view" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableStreamBYOBRequest interface: self.readableStreamByobRequest must inherit property "respond(unsigned long long)" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableStreamBYOBRequest interface: calling respond(unsigned long long) on self.readableStreamByobRequest with too few arguments must throw TypeError assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableStreamBYOBRequest interface: self.readableStreamByobRequest must inherit property "respondWithNewView(ArrayBufferView)" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableStreamBYOBRequest interface: calling respondWithNewView(ArrayBufferView) on self.readableStreamByobRequest with too few arguments must throw TypeError assert_equals: wrong typeof object expected "object" but got "undefined"
+PASS ReadableByteStreamController interface: existence and properties of interface object
+PASS ReadableByteStreamController interface object length
+PASS ReadableByteStreamController interface object name
+PASS ReadableByteStreamController interface: existence and properties of interface prototype object
+PASS ReadableByteStreamController interface: existence and properties of interface prototype object's "constructor" property
+PASS ReadableByteStreamController interface: existence and properties of interface prototype object's @@unscopables property
+PASS ReadableByteStreamController interface: attribute byobRequest
+PASS ReadableByteStreamController interface: attribute desiredSize
+PASS ReadableByteStreamController interface: operation close()
+PASS ReadableByteStreamController interface: operation enqueue(ArrayBufferView)
+PASS ReadableByteStreamController interface: operation error(optional any)
+PASS ReadableByteStreamController must be primary interface of self.readableByteStreamController
+PASS Stringification of self.readableByteStreamController
+PASS ReadableByteStreamController interface: self.readableByteStreamController must inherit property "byobRequest" with the proper type
+PASS ReadableByteStreamController interface: self.readableByteStreamController must inherit property "desiredSize" with the proper type
+PASS ReadableByteStreamController interface: self.readableByteStreamController must inherit property "close()" with the proper type
+PASS ReadableByteStreamController interface: self.readableByteStreamController must inherit property "enqueue(ArrayBufferView)" with the proper type
+PASS ReadableByteStreamController interface: calling enqueue(ArrayBufferView) on self.readableByteStreamController with too few arguments must throw TypeError
+PASS ReadableByteStreamController interface: self.readableByteStreamController must inherit property "error(optional any)" with the proper type
+PASS ReadableByteStreamController interface: calling error(optional any) on self.readableByteStreamController with too few arguments must throw TypeError
+PASS ReadableStreamBYOBRequest interface: existence and properties of interface object
+PASS ReadableStreamBYOBRequest interface object length
+PASS ReadableStreamBYOBRequest interface object name
+PASS ReadableStreamBYOBRequest interface: existence and properties of interface prototype object
+PASS ReadableStreamBYOBRequest interface: existence and properties of interface prototype object's "constructor" property
+PASS ReadableStreamBYOBRequest interface: existence and properties of interface prototype object's @@unscopables property
+PASS ReadableStreamBYOBRequest interface: attribute view
+PASS ReadableStreamBYOBRequest interface: operation respond(unsigned long long)
+PASS ReadableStreamBYOBRequest interface: operation respondWithNewView(ArrayBufferView)
+PASS ReadableStreamBYOBRequest must be primary interface of self.readableStreamByobRequest
+PASS Stringification of self.readableStreamByobRequest
+PASS ReadableStreamBYOBRequest interface: self.readableStreamByobRequest must inherit property "view" with the proper type
+PASS ReadableStreamBYOBRequest interface: self.readableStreamByobRequest must inherit property "respond(unsigned long long)" with the proper type
+PASS ReadableStreamBYOBRequest interface: calling respond(unsigned long long) on self.readableStreamByobRequest with too few arguments must throw TypeError
+PASS ReadableStreamBYOBRequest interface: self.readableStreamByobRequest must inherit property "respondWithNewView(ArrayBufferView)" with the proper type
+PASS ReadableStreamBYOBRequest interface: calling respondWithNewView(ArrayBufferView) on self.readableStreamByobRequest with too few arguments must throw TypeError
 PASS WritableStream interface: existence and properties of interface object
 PASS WritableStream interface object length
 PASS WritableStream interface object name
diff --git a/third_party/blink/web_tests/external/wpt/streams/idlharness.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/streams/idlharness.any.sharedworker-expected.txt
index bf60a89..ac189daf 100644
--- a/third_party/blink/web_tests/external/wpt/streams/idlharness.any.sharedworker-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/streams/idlharness.any.sharedworker-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 224 tests; 139 PASS, 85 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 224 tests; 193 PASS, 31 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS idl_test setup
 PASS idl_test validation
 PASS ReadableStreamDefaultReader includes ReadableStreamGenericReader: member names are unique
@@ -46,24 +46,24 @@
 PASS ReadableStreamDefaultReader interface: (new ReadableStream()).getReader() must inherit property "closed" with the proper type
 PASS ReadableStreamDefaultReader interface: (new ReadableStream()).getReader() must inherit property "cancel(optional any)" with the proper type
 PASS ReadableStreamDefaultReader interface: calling cancel(optional any) on (new ReadableStream()).getReader() with too few arguments must throw TypeError
-FAIL ReadableStreamBYOBReader interface: existence and properties of interface object assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface object length assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface object name assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface: existence and properties of interface prototype object assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface: operation read(ArrayBufferView) assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface: operation releaseLock() assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface: attribute closed assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface: operation cancel(optional any) assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader must be primary interface of (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
-FAIL Stringification of (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
-FAIL ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "read(ArrayBufferView)" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
-FAIL ReadableStreamBYOBReader interface: calling read(ArrayBufferView) on (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) with too few arguments must throw TypeError assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
-FAIL ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "releaseLock()" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
-FAIL ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "closed" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
-FAIL ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "cancel(optional any)" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
-FAIL ReadableStreamBYOBReader interface: calling cancel(optional any) on (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) with too few arguments must throw TypeError assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
+PASS ReadableStreamBYOBReader interface: existence and properties of interface object
+PASS ReadableStreamBYOBReader interface object length
+PASS ReadableStreamBYOBReader interface object name
+PASS ReadableStreamBYOBReader interface: existence and properties of interface prototype object
+PASS ReadableStreamBYOBReader interface: existence and properties of interface prototype object's "constructor" property
+PASS ReadableStreamBYOBReader interface: existence and properties of interface prototype object's @@unscopables property
+PASS ReadableStreamBYOBReader interface: operation read(ArrayBufferView)
+PASS ReadableStreamBYOBReader interface: operation releaseLock()
+PASS ReadableStreamBYOBReader interface: attribute closed
+PASS ReadableStreamBYOBReader interface: operation cancel(optional any)
+PASS ReadableStreamBYOBReader must be primary interface of (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' })
+PASS Stringification of (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' })
+PASS ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "read(ArrayBufferView)" with the proper type
+PASS ReadableStreamBYOBReader interface: calling read(ArrayBufferView) on (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) with too few arguments must throw TypeError
+PASS ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "releaseLock()" with the proper type
+PASS ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "closed" with the proper type
+PASS ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "cancel(optional any)" with the proper type
+PASS ReadableStreamBYOBReader interface: calling cancel(optional any) on (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) with too few arguments must throw TypeError
 FAIL ReadableStreamDefaultController interface: existence and properties of interface object assert_own_property: self does not have own property "ReadableStreamDefaultController" expected property "ReadableStreamDefaultController" missing
 FAIL ReadableStreamDefaultController interface object length assert_own_property: self does not have own property "ReadableStreamDefaultController" expected property "ReadableStreamDefaultController" missing
 FAIL ReadableStreamDefaultController interface object name assert_own_property: self does not have own property "ReadableStreamDefaultController" expected property "ReadableStreamDefaultController" missing
@@ -82,42 +82,42 @@
 PASS ReadableStreamDefaultController interface: calling enqueue(optional any) on self.readableStreamDefaultController with too few arguments must throw TypeError
 PASS ReadableStreamDefaultController interface: self.readableStreamDefaultController must inherit property "error(optional any)" with the proper type
 PASS ReadableStreamDefaultController interface: calling error(optional any) on self.readableStreamDefaultController with too few arguments must throw TypeError
-FAIL ReadableByteStreamController interface: existence and properties of interface object assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface object length assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface object name assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: existence and properties of interface prototype object assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: attribute byobRequest assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: attribute desiredSize assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: operation close() assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: operation enqueue(ArrayBufferView) assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: operation error(optional any) assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController must be primary interface of self.readableByteStreamController assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL Stringification of self.readableByteStreamController assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableByteStreamController interface: self.readableByteStreamController must inherit property "byobRequest" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableByteStreamController interface: self.readableByteStreamController must inherit property "desiredSize" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableByteStreamController interface: self.readableByteStreamController must inherit property "close()" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableByteStreamController interface: self.readableByteStreamController must inherit property "enqueue(ArrayBufferView)" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableByteStreamController interface: calling enqueue(ArrayBufferView) on self.readableByteStreamController with too few arguments must throw TypeError assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableByteStreamController interface: self.readableByteStreamController must inherit property "error(optional any)" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableByteStreamController interface: calling error(optional any) on self.readableByteStreamController with too few arguments must throw TypeError assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableStreamBYOBRequest interface: existence and properties of interface object assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface object length assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface object name assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface: existence and properties of interface prototype object assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface: attribute view assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface: operation respond(unsigned long long) assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface: operation respondWithNewView(ArrayBufferView) assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest must be primary interface of self.readableStreamByobRequest assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL Stringification of self.readableStreamByobRequest assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableStreamBYOBRequest interface: self.readableStreamByobRequest must inherit property "view" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableStreamBYOBRequest interface: self.readableStreamByobRequest must inherit property "respond(unsigned long long)" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableStreamBYOBRequest interface: calling respond(unsigned long long) on self.readableStreamByobRequest with too few arguments must throw TypeError assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableStreamBYOBRequest interface: self.readableStreamByobRequest must inherit property "respondWithNewView(ArrayBufferView)" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableStreamBYOBRequest interface: calling respondWithNewView(ArrayBufferView) on self.readableStreamByobRequest with too few arguments must throw TypeError assert_equals: wrong typeof object expected "object" but got "undefined"
+PASS ReadableByteStreamController interface: existence and properties of interface object
+PASS ReadableByteStreamController interface object length
+PASS ReadableByteStreamController interface object name
+PASS ReadableByteStreamController interface: existence and properties of interface prototype object
+PASS ReadableByteStreamController interface: existence and properties of interface prototype object's "constructor" property
+PASS ReadableByteStreamController interface: existence and properties of interface prototype object's @@unscopables property
+PASS ReadableByteStreamController interface: attribute byobRequest
+PASS ReadableByteStreamController interface: attribute desiredSize
+PASS ReadableByteStreamController interface: operation close()
+PASS ReadableByteStreamController interface: operation enqueue(ArrayBufferView)
+PASS ReadableByteStreamController interface: operation error(optional any)
+PASS ReadableByteStreamController must be primary interface of self.readableByteStreamController
+PASS Stringification of self.readableByteStreamController
+PASS ReadableByteStreamController interface: self.readableByteStreamController must inherit property "byobRequest" with the proper type
+PASS ReadableByteStreamController interface: self.readableByteStreamController must inherit property "desiredSize" with the proper type
+PASS ReadableByteStreamController interface: self.readableByteStreamController must inherit property "close()" with the proper type
+PASS ReadableByteStreamController interface: self.readableByteStreamController must inherit property "enqueue(ArrayBufferView)" with the proper type
+PASS ReadableByteStreamController interface: calling enqueue(ArrayBufferView) on self.readableByteStreamController with too few arguments must throw TypeError
+PASS ReadableByteStreamController interface: self.readableByteStreamController must inherit property "error(optional any)" with the proper type
+PASS ReadableByteStreamController interface: calling error(optional any) on self.readableByteStreamController with too few arguments must throw TypeError
+PASS ReadableStreamBYOBRequest interface: existence and properties of interface object
+PASS ReadableStreamBYOBRequest interface object length
+PASS ReadableStreamBYOBRequest interface object name
+PASS ReadableStreamBYOBRequest interface: existence and properties of interface prototype object
+PASS ReadableStreamBYOBRequest interface: existence and properties of interface prototype object's "constructor" property
+PASS ReadableStreamBYOBRequest interface: existence and properties of interface prototype object's @@unscopables property
+PASS ReadableStreamBYOBRequest interface: attribute view
+PASS ReadableStreamBYOBRequest interface: operation respond(unsigned long long)
+PASS ReadableStreamBYOBRequest interface: operation respondWithNewView(ArrayBufferView)
+PASS ReadableStreamBYOBRequest must be primary interface of self.readableStreamByobRequest
+PASS Stringification of self.readableStreamByobRequest
+PASS ReadableStreamBYOBRequest interface: self.readableStreamByobRequest must inherit property "view" with the proper type
+PASS ReadableStreamBYOBRequest interface: self.readableStreamByobRequest must inherit property "respond(unsigned long long)" with the proper type
+PASS ReadableStreamBYOBRequest interface: calling respond(unsigned long long) on self.readableStreamByobRequest with too few arguments must throw TypeError
+PASS ReadableStreamBYOBRequest interface: self.readableStreamByobRequest must inherit property "respondWithNewView(ArrayBufferView)" with the proper type
+PASS ReadableStreamBYOBRequest interface: calling respondWithNewView(ArrayBufferView) on self.readableStreamByobRequest with too few arguments must throw TypeError
 PASS WritableStream interface: existence and properties of interface object
 PASS WritableStream interface object length
 PASS WritableStream interface object name
diff --git a/third_party/blink/web_tests/external/wpt/streams/idlharness.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/streams/idlharness.any.worker-expected.txt
index bf60a89..ac189daf 100644
--- a/third_party/blink/web_tests/external/wpt/streams/idlharness.any.worker-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/streams/idlharness.any.worker-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 224 tests; 139 PASS, 85 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 224 tests; 193 PASS, 31 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS idl_test setup
 PASS idl_test validation
 PASS ReadableStreamDefaultReader includes ReadableStreamGenericReader: member names are unique
@@ -46,24 +46,24 @@
 PASS ReadableStreamDefaultReader interface: (new ReadableStream()).getReader() must inherit property "closed" with the proper type
 PASS ReadableStreamDefaultReader interface: (new ReadableStream()).getReader() must inherit property "cancel(optional any)" with the proper type
 PASS ReadableStreamDefaultReader interface: calling cancel(optional any) on (new ReadableStream()).getReader() with too few arguments must throw TypeError
-FAIL ReadableStreamBYOBReader interface: existence and properties of interface object assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface object length assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface object name assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface: existence and properties of interface prototype object assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface: operation read(ArrayBufferView) assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface: operation releaseLock() assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface: attribute closed assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader interface: operation cancel(optional any) assert_own_property: self does not have own property "ReadableStreamBYOBReader" expected property "ReadableStreamBYOBReader" missing
-FAIL ReadableStreamBYOBReader must be primary interface of (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
-FAIL Stringification of (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
-FAIL ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "read(ArrayBufferView)" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
-FAIL ReadableStreamBYOBReader interface: calling read(ArrayBufferView) on (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) with too few arguments must throw TypeError assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
-FAIL ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "releaseLock()" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
-FAIL ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "closed" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
-FAIL ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "cancel(optional any)" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
-FAIL ReadableStreamBYOBReader interface: calling cancel(optional any) on (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) with too few arguments must throw TypeError assert_equals: Unexpected exception when evaluating object expected null but got object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented"
+PASS ReadableStreamBYOBReader interface: existence and properties of interface object
+PASS ReadableStreamBYOBReader interface object length
+PASS ReadableStreamBYOBReader interface object name
+PASS ReadableStreamBYOBReader interface: existence and properties of interface prototype object
+PASS ReadableStreamBYOBReader interface: existence and properties of interface prototype object's "constructor" property
+PASS ReadableStreamBYOBReader interface: existence and properties of interface prototype object's @@unscopables property
+PASS ReadableStreamBYOBReader interface: operation read(ArrayBufferView)
+PASS ReadableStreamBYOBReader interface: operation releaseLock()
+PASS ReadableStreamBYOBReader interface: attribute closed
+PASS ReadableStreamBYOBReader interface: operation cancel(optional any)
+PASS ReadableStreamBYOBReader must be primary interface of (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' })
+PASS Stringification of (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' })
+PASS ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "read(ArrayBufferView)" with the proper type
+PASS ReadableStreamBYOBReader interface: calling read(ArrayBufferView) on (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) with too few arguments must throw TypeError
+PASS ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "releaseLock()" with the proper type
+PASS ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "closed" with the proper type
+PASS ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property "cancel(optional any)" with the proper type
+PASS ReadableStreamBYOBReader interface: calling cancel(optional any) on (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) with too few arguments must throw TypeError
 FAIL ReadableStreamDefaultController interface: existence and properties of interface object assert_own_property: self does not have own property "ReadableStreamDefaultController" expected property "ReadableStreamDefaultController" missing
 FAIL ReadableStreamDefaultController interface object length assert_own_property: self does not have own property "ReadableStreamDefaultController" expected property "ReadableStreamDefaultController" missing
 FAIL ReadableStreamDefaultController interface object name assert_own_property: self does not have own property "ReadableStreamDefaultController" expected property "ReadableStreamDefaultController" missing
@@ -82,42 +82,42 @@
 PASS ReadableStreamDefaultController interface: calling enqueue(optional any) on self.readableStreamDefaultController with too few arguments must throw TypeError
 PASS ReadableStreamDefaultController interface: self.readableStreamDefaultController must inherit property "error(optional any)" with the proper type
 PASS ReadableStreamDefaultController interface: calling error(optional any) on self.readableStreamDefaultController with too few arguments must throw TypeError
-FAIL ReadableByteStreamController interface: existence and properties of interface object assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface object length assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface object name assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: existence and properties of interface prototype object assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: attribute byobRequest assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: attribute desiredSize assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: operation close() assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: operation enqueue(ArrayBufferView) assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController interface: operation error(optional any) assert_own_property: self does not have own property "ReadableByteStreamController" expected property "ReadableByteStreamController" missing
-FAIL ReadableByteStreamController must be primary interface of self.readableByteStreamController assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL Stringification of self.readableByteStreamController assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableByteStreamController interface: self.readableByteStreamController must inherit property "byobRequest" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableByteStreamController interface: self.readableByteStreamController must inherit property "desiredSize" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableByteStreamController interface: self.readableByteStreamController must inherit property "close()" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableByteStreamController interface: self.readableByteStreamController must inherit property "enqueue(ArrayBufferView)" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableByteStreamController interface: calling enqueue(ArrayBufferView) on self.readableByteStreamController with too few arguments must throw TypeError assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableByteStreamController interface: self.readableByteStreamController must inherit property "error(optional any)" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableByteStreamController interface: calling error(optional any) on self.readableByteStreamController with too few arguments must throw TypeError assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableStreamBYOBRequest interface: existence and properties of interface object assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface object length assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface object name assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface: existence and properties of interface prototype object assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface: attribute view assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface: operation respond(unsigned long long) assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest interface: operation respondWithNewView(ArrayBufferView) assert_own_property: self does not have own property "ReadableStreamBYOBRequest" expected property "ReadableStreamBYOBRequest" missing
-FAIL ReadableStreamBYOBRequest must be primary interface of self.readableStreamByobRequest assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL Stringification of self.readableStreamByobRequest assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableStreamBYOBRequest interface: self.readableStreamByobRequest must inherit property "view" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableStreamBYOBRequest interface: self.readableStreamByobRequest must inherit property "respond(unsigned long long)" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableStreamBYOBRequest interface: calling respond(unsigned long long) on self.readableStreamByobRequest with too few arguments must throw TypeError assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableStreamBYOBRequest interface: self.readableStreamByobRequest must inherit property "respondWithNewView(ArrayBufferView)" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL ReadableStreamBYOBRequest interface: calling respondWithNewView(ArrayBufferView) on self.readableStreamByobRequest with too few arguments must throw TypeError assert_equals: wrong typeof object expected "object" but got "undefined"
+PASS ReadableByteStreamController interface: existence and properties of interface object
+PASS ReadableByteStreamController interface object length
+PASS ReadableByteStreamController interface object name
+PASS ReadableByteStreamController interface: existence and properties of interface prototype object
+PASS ReadableByteStreamController interface: existence and properties of interface prototype object's "constructor" property
+PASS ReadableByteStreamController interface: existence and properties of interface prototype object's @@unscopables property
+PASS ReadableByteStreamController interface: attribute byobRequest
+PASS ReadableByteStreamController interface: attribute desiredSize
+PASS ReadableByteStreamController interface: operation close()
+PASS ReadableByteStreamController interface: operation enqueue(ArrayBufferView)
+PASS ReadableByteStreamController interface: operation error(optional any)
+PASS ReadableByteStreamController must be primary interface of self.readableByteStreamController
+PASS Stringification of self.readableByteStreamController
+PASS ReadableByteStreamController interface: self.readableByteStreamController must inherit property "byobRequest" with the proper type
+PASS ReadableByteStreamController interface: self.readableByteStreamController must inherit property "desiredSize" with the proper type
+PASS ReadableByteStreamController interface: self.readableByteStreamController must inherit property "close()" with the proper type
+PASS ReadableByteStreamController interface: self.readableByteStreamController must inherit property "enqueue(ArrayBufferView)" with the proper type
+PASS ReadableByteStreamController interface: calling enqueue(ArrayBufferView) on self.readableByteStreamController with too few arguments must throw TypeError
+PASS ReadableByteStreamController interface: self.readableByteStreamController must inherit property "error(optional any)" with the proper type
+PASS ReadableByteStreamController interface: calling error(optional any) on self.readableByteStreamController with too few arguments must throw TypeError
+PASS ReadableStreamBYOBRequest interface: existence and properties of interface object
+PASS ReadableStreamBYOBRequest interface object length
+PASS ReadableStreamBYOBRequest interface object name
+PASS ReadableStreamBYOBRequest interface: existence and properties of interface prototype object
+PASS ReadableStreamBYOBRequest interface: existence and properties of interface prototype object's "constructor" property
+PASS ReadableStreamBYOBRequest interface: existence and properties of interface prototype object's @@unscopables property
+PASS ReadableStreamBYOBRequest interface: attribute view
+PASS ReadableStreamBYOBRequest interface: operation respond(unsigned long long)
+PASS ReadableStreamBYOBRequest interface: operation respondWithNewView(ArrayBufferView)
+PASS ReadableStreamBYOBRequest must be primary interface of self.readableStreamByobRequest
+PASS Stringification of self.readableStreamByobRequest
+PASS ReadableStreamBYOBRequest interface: self.readableStreamByobRequest must inherit property "view" with the proper type
+PASS ReadableStreamBYOBRequest interface: self.readableStreamByobRequest must inherit property "respond(unsigned long long)" with the proper type
+PASS ReadableStreamBYOBRequest interface: calling respond(unsigned long long) on self.readableStreamByobRequest with too few arguments must throw TypeError
+PASS ReadableStreamBYOBRequest interface: self.readableStreamByobRequest must inherit property "respondWithNewView(ArrayBufferView)" with the proper type
+PASS ReadableStreamBYOBRequest interface: calling respondWithNewView(ArrayBufferView) on self.readableStreamByobRequest with too few arguments must throw TypeError
 PASS WritableStream interface: existence and properties of interface object
 PASS WritableStream interface object length
 PASS WritableStream interface object name
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/bad-buffers-and-views.any-expected.txt b/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/bad-buffers-and-views.any-expected.txt
deleted file mode 100644
index 9a39ea47..0000000
--- a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/bad-buffers-and-views.any-expected.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-This is a testharness.js-based test.
-FAIL ReadableStream with byte source: read()ing from a closed stream still transfers the buffer Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read()ing from a stream with queued chunks still transfers the buffer Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueuing an already-detached buffer throws Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueuing a zero-length buffer throws Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueuing a zero-length view on a non-zero-length buffer throws Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: reading into an already-detached buffer rejects Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: reading into a zero-length buffer rejects Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: reading into a zero-length view on a non-zero-length buffer rejects Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respond() throws if the BYOB request's buffer has been detached (in the readable state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respond() throws if the BYOB request's buffer has been detached (in the closed state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view's buffer has been detached (in the readable state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view's buffer is zero-length (in the readable state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view is zero-length on a non-zero-length buffer (in the readable state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view's buffer has been detached (in the closed state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view's buffer is zero-length (in the closed state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view is zero-length on a non-zero-length buffer (in the closed state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/bad-buffers-and-views.any.js b/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/bad-buffers-and-views.any.js
index 0777208..d4ad483 100644
--- a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/bad-buffers-and-views.any.js
+++ b/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/bad-buffers-and-views.any.js
@@ -212,8 +212,7 @@
 
       c.close();
 
-      const zeroLengthView = new Uint8Array(view.buffer, 0, 0);
-      assert_throws_js(TypeError, () => c.byobRequest.respondWithNewView(zeroLengthView));
+      assert_throws_js(TypeError, () => c.byobRequest.respondWithNewView(view));
     }),
     type: 'bytes'
   });
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/bad-buffers-and-views.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/bad-buffers-and-views.any.serviceworker-expected.txt
deleted file mode 100644
index 9a39ea47..0000000
--- a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/bad-buffers-and-views.any.serviceworker-expected.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-This is a testharness.js-based test.
-FAIL ReadableStream with byte source: read()ing from a closed stream still transfers the buffer Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read()ing from a stream with queued chunks still transfers the buffer Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueuing an already-detached buffer throws Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueuing a zero-length buffer throws Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueuing a zero-length view on a non-zero-length buffer throws Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: reading into an already-detached buffer rejects Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: reading into a zero-length buffer rejects Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: reading into a zero-length view on a non-zero-length buffer rejects Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respond() throws if the BYOB request's buffer has been detached (in the readable state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respond() throws if the BYOB request's buffer has been detached (in the closed state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view's buffer has been detached (in the readable state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view's buffer is zero-length (in the readable state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view is zero-length on a non-zero-length buffer (in the readable state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view's buffer has been detached (in the closed state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view's buffer is zero-length (in the closed state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view is zero-length on a non-zero-length buffer (in the closed state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/bad-buffers-and-views.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/bad-buffers-and-views.any.sharedworker-expected.txt
deleted file mode 100644
index 9a39ea47..0000000
--- a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/bad-buffers-and-views.any.sharedworker-expected.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-This is a testharness.js-based test.
-FAIL ReadableStream with byte source: read()ing from a closed stream still transfers the buffer Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read()ing from a stream with queued chunks still transfers the buffer Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueuing an already-detached buffer throws Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueuing a zero-length buffer throws Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueuing a zero-length view on a non-zero-length buffer throws Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: reading into an already-detached buffer rejects Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: reading into a zero-length buffer rejects Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: reading into a zero-length view on a non-zero-length buffer rejects Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respond() throws if the BYOB request's buffer has been detached (in the readable state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respond() throws if the BYOB request's buffer has been detached (in the closed state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view's buffer has been detached (in the readable state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view's buffer is zero-length (in the readable state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view is zero-length on a non-zero-length buffer (in the readable state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view's buffer has been detached (in the closed state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view's buffer is zero-length (in the closed state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view is zero-length on a non-zero-length buffer (in the closed state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/bad-buffers-and-views.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/bad-buffers-and-views.any.worker-expected.txt
deleted file mode 100644
index 9a39ea47..0000000
--- a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/bad-buffers-and-views.any.worker-expected.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-This is a testharness.js-based test.
-FAIL ReadableStream with byte source: read()ing from a closed stream still transfers the buffer Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read()ing from a stream with queued chunks still transfers the buffer Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueuing an already-detached buffer throws Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueuing a zero-length buffer throws Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueuing a zero-length view on a non-zero-length buffer throws Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: reading into an already-detached buffer rejects Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: reading into a zero-length buffer rejects Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: reading into a zero-length view on a non-zero-length buffer rejects Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respond() throws if the BYOB request's buffer has been detached (in the readable state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respond() throws if the BYOB request's buffer has been detached (in the closed state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view's buffer has been detached (in the readable state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view's buffer is zero-length (in the readable state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view is zero-length on a non-zero-length buffer (in the readable state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view's buffer has been detached (in the closed state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view's buffer is zero-length (in the closed state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view is zero-length on a non-zero-length buffer (in the closed state) Failed to construct 'ReadableStream': bytes type is not yet implemented
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/construct-byob-request.any-expected.txt b/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/construct-byob-request.any-expected.txt
deleted file mode 100644
index 129e634..0000000
--- a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/construct-byob-request.any-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Uncaught ReferenceError: ReadableByteStreamController is not defined
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/construct-byob-request.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/construct-byob-request.any.serviceworker-expected.txt
deleted file mode 100644
index 8804b86f..0000000
--- a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/construct-byob-request.any.serviceworker-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Unhandled rejection: Failed to register a ServiceWorker for scope ('https://web-platform.test:8444/streams/readable-byte-streams/does/not/exist') with script ('https://web-platform.test:8444/streams/readable-byte-streams/construct-byob-request.any.worker.js'): ServiceWorker script evaluation failed
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/construct-byob-request.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/construct-byob-request.any.sharedworker-expected.txt
deleted file mode 100644
index 8ec519e..0000000
--- a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/construct-byob-request.any.sharedworker-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL construct-byob-request Uncaught RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/construct-byob-request.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/construct-byob-request.any.worker-expected.txt
deleted file mode 100644
index 129e634..0000000
--- a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/construct-byob-request.any.worker-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Uncaught ReferenceError: ReadableByteStreamController is not defined
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/general.any-expected.txt b/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/general.any-expected.txt
deleted file mode 100644
index 97c2cf1..0000000
--- a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/general.any-expected.txt
+++ /dev/null
@@ -1,83 +0,0 @@
-This is a testharness.js-based test.
-Found 76 tests; 2 PASS, 74 FAIL, 0 TIMEOUT, 0 NOTRUN.
-PASS getReader({mode: "byob"}) throws on non-bytes streams
-FAIL ReadableStream with byte source can be constructed with no errors Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL getReader({mode}) must perform ToString() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Construct and expect start and pull being called Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: No automatic pull call if start doesn't finish Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Construct with highWaterMark of 0 Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: desiredSize when closed Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: desiredSize when errored Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: getReader(), then releaseLock() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: getReader() with mode set to byob, then releaseLock() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Test that closing a stream does not release a reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Test that closing a stream does not release a BYOB reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Test that erroring a stream does not release a reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Test that erroring a stream does not release a BYOB reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: releaseLock() on ReadableStreamDefaultReader with pending read() must throw Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Automatic pull() after start() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Automatic pull() after start() and read() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: autoAllocateChunkSize Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Mix of auto allocate and BYOB Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Automatic pull() after start() and read(view) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), getReader(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Push source that doesn't understand pull signal Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: pull() function is not callable assert_throws_js: constructor should throw function "() => new ReadableStream({
-    pull: 'foo',
-    type: 'bytes'
-  })" threw object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented" ("RangeError") expected instance of function "function TypeError() { [native code] }" ("TypeError")
-FAIL ReadableStream with byte source: enqueue() with Uint16Array, getReader(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), read(view) partially, then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: getReader(), enqueue(), close(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), close(), getReader(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Respond to pull() by enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Respond to pull() by enqueue() asynchronously Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Respond to multiple pull() by separate enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view), then respond() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view), then respond() with a transferred ArrayBuffer Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view), then respond() with too big value Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respond(3) to read(view) with 2 element Uint16Array enqueues the 1 byte remainder Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), getReader(), then cancel() (mode = not BYOB) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), getReader(), then cancel() (mode = BYOB) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: getReader(), read(view), then cancel() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: cancel() with partially filled pending pull() request Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) where view.buffer is not fully covered by view Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Multiple enqueue(), getReader(), then read(view) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) with a bigger view Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) with smaller views Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue() 1 byte, getReader(), then read(view) with Uint16Array Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue() 3 byte, getReader(), then read(view) with 2-element Uint16Array Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view) with Uint16Array on close()-d stream with 1 byte enqueue()-d must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: A stream must be errored if close()-d before fulfilling read(view) with Uint16Array Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Throw if close()-ed more than once Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Throw on enqueue() after close() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view), then respond() and close() in pull() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view) with Uint32Array, then fill it by multiple respond() calls Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read() twice, then enqueue() twice Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Multiple read(view), close() and respond() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Multiple read(view), big enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Multiple read(view) and multiple enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view) with passing undefined as view must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view) with passing an empty object as view must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Even read(view) with passing ArrayBufferView like object as view must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read() on an errored stream Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(), then error() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view) on an errored stream Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view), then error() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Throwing in pull function must error the stream Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Throwing in pull in response to read() must be ignored if the stream is errored in it Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Throwing in pull in response to read(view) function must error the stream Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Throwing in pull in response to read(view) must be ignored if the stream is errored in it Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL calling respond() twice on the same byobRequest should throw Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL calling respondWithNewView() twice on the same byobRequest should throw Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL calling respond(0) twice on the same byobRequest should throw even when closed Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL pull() resolving should not make releaseLock() possible Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: default reader + autoAllocateChunkSize + byobRequest interaction Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStreamBYOBReader can be constructed directly Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStreamBYOBReader constructor requires a ReadableStream argument Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStreamBYOBReader constructor requires an unlocked ReadableStream Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStreamBYOBReader constructor requires a ReadableStream with type "bytes" Failed to construct 'ReadableStream': bytes type is not yet implemented
-PASS ReadableStream constructor should not accept a strategy with a size defined if type is "bytes"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/general.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/general.any.serviceworker-expected.txt
deleted file mode 100644
index 97c2cf1..0000000
--- a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/general.any.serviceworker-expected.txt
+++ /dev/null
@@ -1,83 +0,0 @@
-This is a testharness.js-based test.
-Found 76 tests; 2 PASS, 74 FAIL, 0 TIMEOUT, 0 NOTRUN.
-PASS getReader({mode: "byob"}) throws on non-bytes streams
-FAIL ReadableStream with byte source can be constructed with no errors Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL getReader({mode}) must perform ToString() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Construct and expect start and pull being called Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: No automatic pull call if start doesn't finish Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Construct with highWaterMark of 0 Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: desiredSize when closed Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: desiredSize when errored Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: getReader(), then releaseLock() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: getReader() with mode set to byob, then releaseLock() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Test that closing a stream does not release a reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Test that closing a stream does not release a BYOB reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Test that erroring a stream does not release a reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Test that erroring a stream does not release a BYOB reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: releaseLock() on ReadableStreamDefaultReader with pending read() must throw Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Automatic pull() after start() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Automatic pull() after start() and read() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: autoAllocateChunkSize Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Mix of auto allocate and BYOB Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Automatic pull() after start() and read(view) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), getReader(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Push source that doesn't understand pull signal Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: pull() function is not callable assert_throws_js: constructor should throw function "() => new ReadableStream({
-    pull: 'foo',
-    type: 'bytes'
-  })" threw object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented" ("RangeError") expected instance of function "function TypeError() { [native code] }" ("TypeError")
-FAIL ReadableStream with byte source: enqueue() with Uint16Array, getReader(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), read(view) partially, then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: getReader(), enqueue(), close(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), close(), getReader(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Respond to pull() by enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Respond to pull() by enqueue() asynchronously Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Respond to multiple pull() by separate enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view), then respond() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view), then respond() with a transferred ArrayBuffer Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view), then respond() with too big value Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respond(3) to read(view) with 2 element Uint16Array enqueues the 1 byte remainder Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), getReader(), then cancel() (mode = not BYOB) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), getReader(), then cancel() (mode = BYOB) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: getReader(), read(view), then cancel() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: cancel() with partially filled pending pull() request Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) where view.buffer is not fully covered by view Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Multiple enqueue(), getReader(), then read(view) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) with a bigger view Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) with smaller views Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue() 1 byte, getReader(), then read(view) with Uint16Array Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue() 3 byte, getReader(), then read(view) with 2-element Uint16Array Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view) with Uint16Array on close()-d stream with 1 byte enqueue()-d must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: A stream must be errored if close()-d before fulfilling read(view) with Uint16Array Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Throw if close()-ed more than once Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Throw on enqueue() after close() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view), then respond() and close() in pull() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view) with Uint32Array, then fill it by multiple respond() calls Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read() twice, then enqueue() twice Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Multiple read(view), close() and respond() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Multiple read(view), big enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Multiple read(view) and multiple enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view) with passing undefined as view must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view) with passing an empty object as view must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Even read(view) with passing ArrayBufferView like object as view must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read() on an errored stream Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(), then error() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view) on an errored stream Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view), then error() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Throwing in pull function must error the stream Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Throwing in pull in response to read() must be ignored if the stream is errored in it Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Throwing in pull in response to read(view) function must error the stream Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Throwing in pull in response to read(view) must be ignored if the stream is errored in it Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL calling respond() twice on the same byobRequest should throw Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL calling respondWithNewView() twice on the same byobRequest should throw Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL calling respond(0) twice on the same byobRequest should throw even when closed Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL pull() resolving should not make releaseLock() possible Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: default reader + autoAllocateChunkSize + byobRequest interaction Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStreamBYOBReader can be constructed directly Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStreamBYOBReader constructor requires a ReadableStream argument Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStreamBYOBReader constructor requires an unlocked ReadableStream Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStreamBYOBReader constructor requires a ReadableStream with type "bytes" Failed to construct 'ReadableStream': bytes type is not yet implemented
-PASS ReadableStream constructor should not accept a strategy with a size defined if type is "bytes"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/general.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/general.any.sharedworker-expected.txt
deleted file mode 100644
index 97c2cf1..0000000
--- a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/general.any.sharedworker-expected.txt
+++ /dev/null
@@ -1,83 +0,0 @@
-This is a testharness.js-based test.
-Found 76 tests; 2 PASS, 74 FAIL, 0 TIMEOUT, 0 NOTRUN.
-PASS getReader({mode: "byob"}) throws on non-bytes streams
-FAIL ReadableStream with byte source can be constructed with no errors Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL getReader({mode}) must perform ToString() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Construct and expect start and pull being called Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: No automatic pull call if start doesn't finish Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Construct with highWaterMark of 0 Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: desiredSize when closed Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: desiredSize when errored Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: getReader(), then releaseLock() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: getReader() with mode set to byob, then releaseLock() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Test that closing a stream does not release a reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Test that closing a stream does not release a BYOB reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Test that erroring a stream does not release a reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Test that erroring a stream does not release a BYOB reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: releaseLock() on ReadableStreamDefaultReader with pending read() must throw Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Automatic pull() after start() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Automatic pull() after start() and read() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: autoAllocateChunkSize Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Mix of auto allocate and BYOB Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Automatic pull() after start() and read(view) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), getReader(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Push source that doesn't understand pull signal Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: pull() function is not callable assert_throws_js: constructor should throw function "() => new ReadableStream({
-    pull: 'foo',
-    type: 'bytes'
-  })" threw object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented" ("RangeError") expected instance of function "function TypeError() { [native code] }" ("TypeError")
-FAIL ReadableStream with byte source: enqueue() with Uint16Array, getReader(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), read(view) partially, then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: getReader(), enqueue(), close(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), close(), getReader(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Respond to pull() by enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Respond to pull() by enqueue() asynchronously Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Respond to multiple pull() by separate enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view), then respond() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view), then respond() with a transferred ArrayBuffer Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view), then respond() with too big value Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respond(3) to read(view) with 2 element Uint16Array enqueues the 1 byte remainder Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), getReader(), then cancel() (mode = not BYOB) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), getReader(), then cancel() (mode = BYOB) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: getReader(), read(view), then cancel() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: cancel() with partially filled pending pull() request Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) where view.buffer is not fully covered by view Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Multiple enqueue(), getReader(), then read(view) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) with a bigger view Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) with smaller views Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue() 1 byte, getReader(), then read(view) with Uint16Array Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue() 3 byte, getReader(), then read(view) with 2-element Uint16Array Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view) with Uint16Array on close()-d stream with 1 byte enqueue()-d must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: A stream must be errored if close()-d before fulfilling read(view) with Uint16Array Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Throw if close()-ed more than once Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Throw on enqueue() after close() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view), then respond() and close() in pull() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view) with Uint32Array, then fill it by multiple respond() calls Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read() twice, then enqueue() twice Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Multiple read(view), close() and respond() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Multiple read(view), big enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Multiple read(view) and multiple enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view) with passing undefined as view must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view) with passing an empty object as view must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Even read(view) with passing ArrayBufferView like object as view must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read() on an errored stream Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(), then error() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view) on an errored stream Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view), then error() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Throwing in pull function must error the stream Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Throwing in pull in response to read() must be ignored if the stream is errored in it Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Throwing in pull in response to read(view) function must error the stream Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Throwing in pull in response to read(view) must be ignored if the stream is errored in it Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL calling respond() twice on the same byobRequest should throw Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL calling respondWithNewView() twice on the same byobRequest should throw Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL calling respond(0) twice on the same byobRequest should throw even when closed Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL pull() resolving should not make releaseLock() possible Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: default reader + autoAllocateChunkSize + byobRequest interaction Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStreamBYOBReader can be constructed directly Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStreamBYOBReader constructor requires a ReadableStream argument Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStreamBYOBReader constructor requires an unlocked ReadableStream Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStreamBYOBReader constructor requires a ReadableStream with type "bytes" Failed to construct 'ReadableStream': bytes type is not yet implemented
-PASS ReadableStream constructor should not accept a strategy with a size defined if type is "bytes"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/general.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/general.any.worker-expected.txt
deleted file mode 100644
index 97c2cf1..0000000
--- a/third_party/blink/web_tests/external/wpt/streams/readable-byte-streams/general.any.worker-expected.txt
+++ /dev/null
@@ -1,83 +0,0 @@
-This is a testharness.js-based test.
-Found 76 tests; 2 PASS, 74 FAIL, 0 TIMEOUT, 0 NOTRUN.
-PASS getReader({mode: "byob"}) throws on non-bytes streams
-FAIL ReadableStream with byte source can be constructed with no errors Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL getReader({mode}) must perform ToString() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Construct and expect start and pull being called Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: No automatic pull call if start doesn't finish Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Construct with highWaterMark of 0 Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: desiredSize when closed Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: desiredSize when errored Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: getReader(), then releaseLock() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: getReader() with mode set to byob, then releaseLock() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Test that closing a stream does not release a reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Test that closing a stream does not release a BYOB reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Test that erroring a stream does not release a reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Test that erroring a stream does not release a BYOB reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: releaseLock() on ReadableStreamDefaultReader with pending read() must throw Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Automatic pull() after start() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Automatic pull() after start() and read() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: autoAllocateChunkSize Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Mix of auto allocate and BYOB Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Automatic pull() after start() and read(view) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), getReader(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Push source that doesn't understand pull signal Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: pull() function is not callable assert_throws_js: constructor should throw function "() => new ReadableStream({
-    pull: 'foo',
-    type: 'bytes'
-  })" threw object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented" ("RangeError") expected instance of function "function TypeError() { [native code] }" ("TypeError")
-FAIL ReadableStream with byte source: enqueue() with Uint16Array, getReader(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), read(view) partially, then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: getReader(), enqueue(), close(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), close(), getReader(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Respond to pull() by enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Respond to pull() by enqueue() asynchronously Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Respond to multiple pull() by separate enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view), then respond() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view), then respond() with a transferred ArrayBuffer Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view), then respond() with too big value Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: respond(3) to read(view) with 2 element Uint16Array enqueues the 1 byte remainder Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), getReader(), then cancel() (mode = not BYOB) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), getReader(), then cancel() (mode = BYOB) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: getReader(), read(view), then cancel() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: cancel() with partially filled pending pull() request Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) where view.buffer is not fully covered by view Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Multiple enqueue(), getReader(), then read(view) Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) with a bigger view Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) with smaller views Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue() 1 byte, getReader(), then read(view) with Uint16Array Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: enqueue() 3 byte, getReader(), then read(view) with 2-element Uint16Array Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view) with Uint16Array on close()-d stream with 1 byte enqueue()-d must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: A stream must be errored if close()-d before fulfilling read(view) with Uint16Array Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Throw if close()-ed more than once Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Throw on enqueue() after close() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view), then respond() and close() in pull() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view) with Uint32Array, then fill it by multiple respond() calls Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read() twice, then enqueue() twice Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Multiple read(view), close() and respond() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Multiple read(view), big enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Multiple read(view) and multiple enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view) with passing undefined as view must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view) with passing an empty object as view must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Even read(view) with passing ArrayBufferView like object as view must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read() on an errored stream Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(), then error() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view) on an errored stream Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: read(view), then error() Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Throwing in pull function must error the stream Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Throwing in pull in response to read() must be ignored if the stream is errored in it Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Throwing in pull in response to read(view) function must error the stream Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: Throwing in pull in response to read(view) must be ignored if the stream is errored in it Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL calling respond() twice on the same byobRequest should throw Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL calling respondWithNewView() twice on the same byobRequest should throw Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL calling respond(0) twice on the same byobRequest should throw even when closed Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL pull() resolving should not make releaseLock() possible Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStream with byte source: default reader + autoAllocateChunkSize + byobRequest interaction Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStreamBYOBReader can be constructed directly Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStreamBYOBReader constructor requires a ReadableStream argument Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStreamBYOBReader constructor requires an unlocked ReadableStream Failed to construct 'ReadableStream': bytes type is not yet implemented
-FAIL ReadableStreamBYOBReader constructor requires a ReadableStream with type "bytes" Failed to construct 'ReadableStream': bytes type is not yet implemented
-PASS ReadableStream constructor should not accept a strategy with a size defined if type is "bytes"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/subresource-integrity/DIR_METADATA b/third_party/blink/web_tests/external/wpt/subresource-integrity/DIR_METADATA
new file mode 100644
index 0000000..56cf7f3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/subresource-integrity/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>SecurityFeature"
+}
+team_email: "security-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/subresource-integrity/OWNERS b/third_party/blink/web_tests/external/wpt/subresource-integrity/OWNERS
index e8e1bb11..75bf0dee 100644
--- a/third_party/blink/web_tests/external/wpt/subresource-integrity/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/subresource-integrity/OWNERS
@@ -1,4 +1,2 @@
-# TEAM: security-dev@chromium.org
-# COMPONENT: Blink>SecurityFeature
 mkwst@chromium.org
 jochen@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/svg/DIR_METADATA b/third_party/blink/web_tests/external/wpt/svg/DIR_METADATA
new file mode 100644
index 0000000..9468b404
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>SVG"
+}
+team_email: "paint-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/svg/OWNERS b/third_party/blink/web_tests/external/wpt/svg/OWNERS
deleted file mode 100644
index cf0ed9aa..0000000
--- a/third_party/blink/web_tests/external/wpt/svg/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# TEAM: paint-dev@chromium.org
-# COMPONENT: Blink>SVG
-# WPT-NOTIFY: true
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/touch-events/DIR_METADATA b/third_party/blink/web_tests/external/wpt/touch-events/DIR_METADATA
new file mode 100644
index 0000000..4a2c8aa
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/touch-events/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Input"
+}
+team_email: "input-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/touch-events/OWNERS b/third_party/blink/web_tests/external/wpt/touch-events/OWNERS
index 46d4a5d..9258d11 100644
--- a/third_party/blink/web_tests/external/wpt/touch-events/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/touch-events/OWNERS
@@ -1,4 +1 @@
-# TEAM: input-dev@chromium.org
-# COMPONENT: Blink>Input
-# WPT-NOTIFY: true
 nzolghadr@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/DIR_METADATA b/third_party/blink/web_tests/external/wpt/trusted-types/DIR_METADATA
new file mode 100644
index 0000000..56cf7f3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/trusted-types/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>SecurityFeature"
+}
+team_email: "security-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/OWNERS b/third_party/blink/web_tests/external/wpt/trusted-types/OWNERS
index 43db381..3f84563 100644
--- a/third_party/blink/web_tests/external/wpt/trusted-types/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/trusted-types/OWNERS
@@ -1,3 +1 @@
-# TEAM: security-dev@chromium.org
-# COMPONENT: Blink>SecurityFeature
 mkwst@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/uievents/DIR_METADATA b/third_party/blink/web_tests/external/wpt/uievents/DIR_METADATA
new file mode 100644
index 0000000..4a2c8aa
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/uievents/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Input"
+}
+team_email: "input-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/uievents/OWNERS b/third_party/blink/web_tests/external/wpt/uievents/OWNERS
index 8ad136a..26a49787 100644
--- a/third_party/blink/web_tests/external/wpt/uievents/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/uievents/OWNERS
@@ -1,4 +1 @@
-# TEAM: input-dev@chromium.org
-# COMPONENT: Blink>Input
-# WPT-NOTIFY: true
 dtapuska@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/DIR_METADATA b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/DIR_METADATA
new file mode 100644
index 0000000..56cf7f3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>SecurityFeature"
+}
+team_email: "security-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/OWNERS b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/OWNERS
index 43db381..3f84563 100644
--- a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/OWNERS
@@ -1,3 +1 @@
-# TEAM: security-dev@chromium.org
-# COMPONENT: Blink>SecurityFeature
 mkwst@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/url/DIR_METADATA b/third_party/blink/web_tests/external/wpt/url/DIR_METADATA
new file mode 100644
index 0000000..72f55a0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/url/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>Network"
+}
+team_email: "blink-network-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/url/OWNERS b/third_party/blink/web_tests/external/wpt/url/OWNERS
deleted file mode 100644
index 8263c35..0000000
--- a/third_party/blink/web_tests/external/wpt/url/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# TEAM: blink-network-dev@chromium.org
-# COMPONENT: Blink>Network
diff --git a/third_party/blink/web_tests/external/wpt/user-timing/DIR_METADATA b/third_party/blink/web_tests/external/wpt/user-timing/DIR_METADATA
new file mode 100644
index 0000000..45b72a6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/user-timing/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>PerformanceAPIs"
+}
+team_email: "speed-metrics-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/user-timing/OWNERS b/third_party/blink/web_tests/external/wpt/user-timing/OWNERS
deleted file mode 100644
index f4011d2b..0000000
--- a/third_party/blink/web_tests/external/wpt/user-timing/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# TEAM: speed-metrics-dev@chromium.org
-# COMPONENT: Blink>PerformanceAPIs
-# WPT-NOTIFY: true
diff --git a/third_party/blink/web_tests/external/wpt/vibration/DIR_METADATA b/third_party/blink/web_tests/external/wpt/vibration/DIR_METADATA
new file mode 100644
index 0000000..e66495f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/vibration/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>Vibration"
+}
+team_email: "platform-capabilities@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/vibration/OWNERS b/third_party/blink/web_tests/external/wpt/vibration/OWNERS
deleted file mode 100644
index 4d14efd..0000000
--- a/third_party/blink/web_tests/external/wpt/vibration/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# TEAM: platform-capabilities@chromium.org
-# COMPONENT: Blink>Vibration
diff --git a/third_party/blink/web_tests/external/wpt/visual-viewport/DIR_METADATA b/third_party/blink/web_tests/external/wpt/visual-viewport/DIR_METADATA
new file mode 100644
index 0000000..4a2c8aa
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/visual-viewport/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Input"
+}
+team_email: "input-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/visual-viewport/OWNERS b/third_party/blink/web_tests/external/wpt/visual-viewport/OWNERS
index e7e04516..9f9aedfa 100644
--- a/third_party/blink/web_tests/external/wpt/visual-viewport/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/visual-viewport/OWNERS
@@ -1,4 +1 @@
-# TEAM: input-dev@chromium.org
-# COMPONENT: Blink>Input
-# WPT-NOTIFY: true
 bokan@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/wasm/DIR_METADATA b/third_party/blink/web_tests/external/wpt/wasm/DIR_METADATA
new file mode 100644
index 0000000..cb8992c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/wasm/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>JavaScript>WebAssembly"
+}
diff --git a/third_party/blink/web_tests/external/wpt/wasm/OWNERS b/third_party/blink/web_tests/external/wpt/wasm/OWNERS
index 317ea70..633a0b1 100644
--- a/third_party/blink/web_tests/external/wpt/wasm/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/wasm/OWNERS
@@ -1,2 +1 @@
-# COMPONENT: Blink>JavaScript>WebAssembly
 binji@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/DIR_METADATA b/third_party/blink/web_tests/external/wpt/web-animations/DIR_METADATA
new file mode 100644
index 0000000..d7b326b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/web-animations/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>Animation"
+}
+team_email: "animations-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/OWNERS b/third_party/blink/web_tests/external/wpt/web-animations/OWNERS
index 9bafb3b..50e5c84 100644
--- a/third_party/blink/web_tests/external/wpt/web-animations/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/web-animations/OWNERS
@@ -1,3 +1 @@
-# TEAM: animations-dev@chromium.org
-# COMPONENT: Blink>Animation
 meade@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/web-locks/DIR_METADATA b/third_party/blink/web_tests/external/wpt/web-locks/DIR_METADATA
new file mode 100644
index 0000000..cc6fcfa
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/web-locks/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>Storage"
+}
+team_email: "storage-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/web-locks/OWNERS b/third_party/blink/web_tests/external/wpt/web-locks/OWNERS
deleted file mode 100644
index 5ca6cf5f..0000000
--- a/third_party/blink/web_tests/external/wpt/web-locks/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# TEAM: storage-dev@chromium.org
-# COMPONENT: Blink>Storage
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/DIR_METADATA b/third_party/blink/web_tests/external/wpt/web-nfc/DIR_METADATA
new file mode 100644
index 0000000..b409764
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/web-nfc/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>NFC"
+}
+team_email: "device-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/OWNERS b/third_party/blink/web_tests/external/wpt/web-nfc/OWNERS
index 2a0e8201..0243a40 100644
--- a/third_party/blink/web_tests/external/wpt/web-nfc/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/web-nfc/OWNERS
@@ -1,4 +1,2 @@
-# TEAM: device-dev@chromium.org
-# COMPONENT: Blink>NFC
 kenneth.r.christiansen@intel.com
 rijubrata.bhaumik@intel.com
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/DIR_METADATA b/third_party/blink/web_tests/external/wpt/webaudio/DIR_METADATA
new file mode 100644
index 0000000..4130bdc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webaudio/DIR_METADATA
@@ -0,0 +1,6 @@
+monorail {
+  component: "Blink>WebAudio"
+}
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/OWNERS b/third_party/blink/web_tests/external/wpt/webaudio/OWNERS
index a4cc14b..a837fc9b 100644
--- a/third_party/blink/web_tests/external/wpt/webaudio/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/webaudio/OWNERS
@@ -1,4 +1,2 @@
-# COMPONENT: Blink>WebAudio
-# WPT-NOTIFY: true
 hongchan@chromium.org
 rtoy@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/webauthn/DIR_METADATA b/third_party/blink/web_tests/external/wpt/webauthn/DIR_METADATA
new file mode 100644
index 0000000..177a021
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webauthn/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>WebAuthentication"
+}
+team_email: "identity-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/webauthn/OWNERS b/third_party/blink/web_tests/external/wpt/webauthn/OWNERS
index b694735f..bf4ea08 100644
--- a/third_party/blink/web_tests/external/wpt/webauthn/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/webauthn/OWNERS
@@ -1,6 +1,2 @@
 file://device/fido/OWNERS
 nsatragno@chromium.org
-
-# COMPONENT: Blink>WebAuthentication
-# TEAM: identity-dev@chromium.org
-# WPT-NOTIFY: true
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/perform_actions/DIR_METADATA b/third_party/blink/web_tests/external/wpt/webdriver/tests/perform_actions/DIR_METADATA
new file mode 100644
index 0000000..4a2c8aa
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/perform_actions/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Blink>Input"
+}
+team_email: "input-dev@chromium.org"
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/perform_actions/OWNERS b/third_party/blink/web_tests/external/wpt/webdriver/tests/perform_actions/OWNERS
deleted file mode 100644
index 1775c1c..0000000
--- a/third_party/blink/web_tests/external/wpt/webdriver/tests/perform_actions/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# TEAM: input-dev@chromium.org
-# COMPONENT: Blink>Input
-# WPT-NOTIFY: true
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/DIR_METADATA b/third_party/blink/web_tests/external/wpt/webgpu/DIR_METADATA
new file mode 100644
index 0000000..1bd921c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webgpu/DIR_METADATA
@@ -0,0 +1,6 @@
+monorail {
+  component: "Blink>WebGPU"
+}
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/OWNERS b/third_party/blink/web_tests/external/wpt/webgpu/OWNERS
index 0902cf56..2e37d5e 100644
--- a/third_party/blink/web_tests/external/wpt/webgpu/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/webgpu/OWNERS
@@ -1,3 +1 @@
-# COMPONENT: Blink>WebGPU
-# WPT-NOTIFY: true
 file://third_party/blink/renderer/modules/webgpu/OWNERS
diff --git a/third_party/blink/web_tests/external/wpt/workers/semantics/interface-objects/002.worker-expected.txt b/third_party/blink/web_tests/external/wpt/workers/semantics/interface-objects/002.worker-expected.txt
index 3e0b101..f37a7e7 100644
--- a/third_party/blink/web_tests/external/wpt/workers/semantics/interface-objects/002.worker-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/workers/semantics/interface-objects/002.worker-expected.txt
@@ -17,9 +17,9 @@
 PASS The PageTransitionEvent interface object should not be exposed.
 PASS The DOMImplementation interface object should not be exposed.
 FAIL The ReadableStreamDefaultReader interface object should not be exposed. assert_false: expected false got true
-PASS The ReadableStreamBYOBReader interface object should not be exposed.
+FAIL The ReadableStreamBYOBReader interface object should not be exposed. assert_false: expected false got true
 PASS The ReadableStreamDefaultController interface object should not be exposed.
-PASS The ReadableByteStreamController interface object should not be exposed.
+FAIL The ReadableByteStreamController interface object should not be exposed. assert_false: expected false got true
 FAIL The WritableStreamDefaultWriter interface object should not be exposed. assert_false: expected false got true
 PASS The WritableStreamDefaultController interface object should not be exposed.
 PASS The IDBEnvironment interface object should not be exposed.
diff --git a/third_party/blink/web_tests/external/wpt/workers/semantics/interface-objects/004.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/workers/semantics/interface-objects/004.any.sharedworker-expected.txt
index 7e4635f..8d98263 100644
--- a/third_party/blink/web_tests/external/wpt/workers/semantics/interface-objects/004.any.sharedworker-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/workers/semantics/interface-objects/004.any.sharedworker-expected.txt
@@ -15,9 +15,9 @@
 PASS The HashChangeEvent interface object should not be exposed
 PASS The PageTransitionEvent interface object should not be exposed
 FAIL The ReadableStreamDefaultReader interface object should not be exposed assert_false: expected false got true
-PASS The ReadableStreamBYOBReader interface object should not be exposed
+FAIL The ReadableStreamBYOBReader interface object should not be exposed assert_false: expected false got true
 PASS The ReadableStreamDefaultController interface object should not be exposed
-PASS The ReadableByteStreamController interface object should not be exposed
+FAIL The ReadableByteStreamController interface object should not be exposed assert_false: expected false got true
 FAIL The WritableStreamDefaultWriter interface object should not be exposed assert_false: expected false got true
 PASS The WritableStreamDefaultController interface object should not be exposed
 PASS The IDBEnvironment interface object should not be exposed
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-1-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-1-expected.txt
deleted file mode 100644
index 3e4dfa22..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-1-expected.txt
+++ /dev/null
@@ -1,72 +0,0 @@
-Verifies JavaScript pretty-printing functionality.
-
-
-Running: multipleVariableDeclarations
-====== 8< ------
-var a = 1
-  , b = {}
-  , c = 2
-  , d = "hello world";
-var a, b, c, d = 2, e, f = 3;
-
------- >8 ======
-Correct mapping for <{}>
-Correct mapping for <hello>
-Correct mapping for <;>
-
-Running: emptyObjectExpression
-====== 8< ------
-var a = {}
-
------- >8 ======
-Correct mapping for <{>
-Correct mapping for <}>
-Correct mapping for <a>
-
-Running: breakContinueStatements
-====== 8< ------
-for (var i in set)
-    if (i % 2 === 0)
-        break;
-    else
-        continue;
-
------- >8 ======
-Correct mapping for <break>
-Correct mapping for <continue>
-Correct mapping for <2>
-Correct mapping for <else>
-
-Running: chainedIfStatements
-====== 8< ------
-if (a % 7 === 0)
-    b = 1;
-else if (a % 9 === 1)
-    b = 2;
-else if (a % 5 === 3) {
-    b = a / 2;
-    b++;
-} else
-    b = 3;
-
------- >8 ======
-Correct mapping for <7>
-Correct mapping for <9>
-Correct mapping for <3>
-Correct mapping for <++>
-
-Running: tryCatchStatement
-====== 8< ------
-try {
-    a(b());
-} catch (e) {
-    f()
-} finally {
-    f();
-}
-
------- >8 ======
-Correct mapping for <try>
-Correct mapping for <catch>
-Correct mapping for <finally>
-
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-1.js b/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-1.js
deleted file mode 100644
index 9bc0928..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-1.js
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-(async function() {
-  TestRunner.addResult(`Verifies JavaScript pretty-printing functionality.\n`);
-  await TestRunner.loadModule('sources_test_runner');
-  await TestRunner.showPanel('sources');
-  await TestRunner.addScriptTag('debugger/resources/obfuscated.js');
-
-  var testJSFormatter = SourcesTestRunner.testPrettyPrint.bind(SourcesTestRunner, 'text/javascript');
-
-  TestRunner.runTestSuite([
-    function multipleVariableDeclarations(next) {
-      var mappingQueries = ['{}', 'hello', ';'];
-      testJSFormatter('var a=1,b={},c=2,d="hello world";var a,b,c,d=2,e,f=3;', mappingQueries, next);
-    },
-
-    function emptyObjectExpression(next) {
-      var mappingQueries = ['{', '}', 'a'];
-      testJSFormatter('var a={}', mappingQueries, next);
-    },
-
-    function breakContinueStatements(next) {
-      var mappingQueries = ['break', 'continue', '2', 'else'];
-      testJSFormatter('for(var i in set)if(i%2===0)break;else continue;', mappingQueries, next);
-    },
-
-    function chainedIfStatements(next) {
-      var mappingQueries = ['7', '9', '3', '++'];
-      testJSFormatter(
-          'if(a%7===0)b=1;else if(a%9===1) b =  2;else if(a%5===3){b=a/2;b++;} else b= 3;', mappingQueries, next);
-    },
-
-    function tryCatchStatement(next) {
-      var mappingQueries = ['try', 'catch', 'finally'];
-      testJSFormatter('try{a(b());}catch(e){f()}finally{f();}', mappingQueries, next);
-    },
-  ]);
-})();
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-10-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-10-expected.txt
deleted file mode 100644
index 5999afb7..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-10-expected.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-Verifies JavaScript pretty-printing functionality.
-
-
-Running: objectSpread
-====== 8< ------
-const a = {
-    a: 4,
-    ...{
-        a: 5,
-        b: 42
-    }
-};
-
------- >8 ======
-
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-10.js b/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-10.js
deleted file mode 100644
index dd401786..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-10.js
+++ /dev/null
@@ -1,18 +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.
-
-(async function() {
-  TestRunner.addResult(`Verifies JavaScript pretty-printing functionality.\n`);
-  await TestRunner.loadModule('sources_test_runner');
-  await TestRunner.showPanel('sources');
-
-  var testJSFormatter = SourcesTestRunner.testPrettyPrint.bind(SourcesTestRunner, 'text/javascript');
-
-  TestRunner.runTestSuite([
-    function objectSpread(next) {
-      var mappingQueries = [];
-      testJSFormatter('const a = {a:4,...{a: 5,b: 42}};', mappingQueries, next);
-    },
-  ]);
-})();
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-2-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-2-expected.txt
deleted file mode 100644
index 627afa41..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-2-expected.txt
+++ /dev/null
@@ -1,63 +0,0 @@
-Verifies JavaScript pretty-printing functionality.
-
-
-Running: forLoopWithIfStatementWithoutBlockStatements
-====== 8< ------
-for (var value of map)
-    if (value.length % 3 === 0)
-        console.log(value);
-
------- >8 ======
-Correct mapping for <length>
-Correct mapping for <console>
-Correct mapping for <of>
-
-Running: objectExpressionProperties
-====== 8< ------
-var mapping = {
-    original: [1, 2, 3],
-    formatted: [],
-    count: 0
-}
-
------- >8 ======
-Correct mapping for <mapping>
-Correct mapping for <original>
-Correct mapping for <formatted>
-
-Running: blockFormatting
-====== 8< ------
-{
-    print(1);
-    print(2);
-}
-
------- >8 ======
-Correct mapping for <(1)>
-Correct mapping for <(2)>
-
-Running: assignmentFormatting
-====== 8< ------
-var exp = 'a string';
-c = +a + (0 > a ? b : 0);
-c = (1);
-var a = (1);
-
------- >8 ======
-Correct mapping for <string>
-
-Running: objectLiteralFormatting
-====== 8< ------
-var obj = {
-    'foo': 1,
-    bar: "2",
-    cat: {
-        dog: '1989'
-    }
-}
-
------- >8 ======
-Correct mapping for <dog>
-Correct mapping for <1989>
-Correct mapping for <foo>
-
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-2.js b/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-2.js
deleted file mode 100644
index 00879c8..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-2.js
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-(async function() {
-  TestRunner.addResult(`Verifies JavaScript pretty-printing functionality.\n`);
-  await TestRunner.loadModule('sources_test_runner');
-  await TestRunner.showPanel('sources');
-  await TestRunner.addScriptTag('debugger/resources/obfuscated.js');
-
-  var testJSFormatter = SourcesTestRunner.testPrettyPrint.bind(SourcesTestRunner, 'text/javascript');
-
-  TestRunner.runTestSuite([
-    function forLoopWithIfStatementWithoutBlockStatements(next) {
-      var mappingQueries = ['length', 'console', 'of'];
-      testJSFormatter('for(var value of map)if (value.length%3===0)console.log(value);', mappingQueries, next);
-    },
-
-    function objectExpressionProperties(next) {
-      var mappingQueries = ['mapping', 'original', 'formatted'];
-      testJSFormatter('var mapping={original:[1,2,3],formatted:[],count:0}', mappingQueries, next);
-    },
-
-    function blockFormatting(next) {
-      var mappingQueries = ['(1)', '(2)'];
-      testJSFormatter('{ print(1); print(2); }', mappingQueries, next);
-    },
-
-    function assignmentFormatting(next) {
-      var mappingQueries = ['string'];
-      testJSFormatter('var exp=\'a string\';c=+a+(0>a?b:0);c=(1);var a=(1);', mappingQueries, next);
-    },
-
-    function objectLiteralFormatting(next) {
-      var mappingQueries = ['dog', '1989', 'foo'];
-      testJSFormatter('var obj={\'foo\':1,bar:"2",cat:{dog:\'1989\'}}', mappingQueries, next);
-    },
-  ]);
-})();
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-3-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-3-expected.txt
deleted file mode 100644
index c90de76..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-3-expected.txt
+++ /dev/null
@@ -1,66 +0,0 @@
-Verifies JavaScript pretty-printing functionality.
-
-
-Running: ifStatements
-====== 8< ------
-if (a < b)
-    log(a);
-else
-    log(b);
-if (a < b) {
-    log(a)
-} else {
-    log(b);
-}
-if (a === b)
-    log('equals');
-if (a !== b) {
-    log('non-eq');
-}
-
------- >8 ======
-Correct mapping for <===>
-Correct mapping for <!==>
-Correct mapping for <non-eq>
-
-Running: arrayLiteralFormatting
-====== 8< ------
-var arr = [3, 2, 1, 0]
-
------- >8 ======
-Correct mapping for <3>
-Correct mapping for <2>
-Correct mapping for <1>
-Correct mapping for <0>
-
-Running: ifFormatting
-====== 8< ------
-if (a > b && b > c) {
-    print(a);
-    print(b);
-}
-
------- >8 ======
-Correct mapping for <&&>
-Correct mapping for <print(a)>
-
-Running: ternarOperatorFormatting
-====== 8< ------
-a > b ? a : b
-
------- >8 ======
-Correct mapping for <?>
-Correct mapping for <:>
-
-Running: labeledStatementFormatting
-====== 8< ------
-firstLoop: while (true) {
-    break firstLoop;
-    continue firstLoop;
-}
-
------- >8 ======
-Correct mapping for <break>
-Correct mapping for <continue>
-Correct mapping for <while>
-
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-3.js b/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-3.js
deleted file mode 100644
index dea1308..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-3.js
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-(async function() {
-  TestRunner.addResult(`Verifies JavaScript pretty-printing functionality.\n`);
-  await TestRunner.loadModule('sources_test_runner');
-  await TestRunner.showPanel('sources');
-  await TestRunner.addScriptTag('debugger/resources/obfuscated.js');
-
-  var testJSFormatter = SourcesTestRunner.testPrettyPrint.bind(SourcesTestRunner, 'text/javascript');
-
-  TestRunner.runTestSuite([
-    function ifStatements(next) {
-      var mappingQueries = ['===', '!==', 'non-eq'];
-      testJSFormatter(
-          'if(a<b)log(a);else log(b);if(a<b){log(a)}else{log(b);}if(a===b)log(\'equals\');if(a!==b){log(\'non-eq\');}',
-          mappingQueries, next);
-    },
-
-    function arrayLiteralFormatting(next) {
-      var mappingQueries = ['3', '2', '1', '0'];
-      testJSFormatter('var arr=[3,2,1,0]', mappingQueries, next);
-    },
-
-    function ifFormatting(next) {
-      var mappingQueries = ['&&', 'print(a)'];
-      testJSFormatter('if(a>b&&b>c){print(a);print(b);}', mappingQueries, next);
-    },
-
-    function ternarOperatorFormatting(next) {
-      var mappingQueries = ['?', ':'];
-      testJSFormatter('a>b?a:b', mappingQueries, next);
-    },
-
-    function labeledStatementFormatting(next) {
-      var mappingQueries = ['break', 'continue', 'while'];
-      testJSFormatter('firstLoop:while(true){break firstLoop;continue firstLoop;}', mappingQueries, next);
-    },
-  ]);
-})();
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-4-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-4-expected.txt
deleted file mode 100644
index 96f3d48..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-4-expected.txt
+++ /dev/null
@@ -1,76 +0,0 @@
-Verifies JavaScript pretty-printing functionality.
-
-
-Running: withStatementFormatting
-====== 8< ------
-with (obj)
-    log('first');
-with (nice) {
-    log(1);
-    log(2);
-}
-done();
-
------- >8 ======
-Correct mapping for <first>
-Correct mapping for <obj>
-Correct mapping for <nice>
-Correct mapping for <1>
-Correct mapping for <2>
-Correct mapping for <done>
-
-Running: switchStatementFormatting
-====== 8< ------
-switch (a) {
-case 1, 3:
-    log("odd");
-    break;
-case 2:
-    log("even");
-    break;
-case 42:
-case 89:
-    log(a);
-default:
-    log("interesting");
-    log(a);
-}
-log("done");
-
------- >8 ======
-Correct mapping for <even>
-Correct mapping for <odd>
-Correct mapping for <89>
-Correct mapping for <done>
-
-Running: whileFormatting
-====== 8< ------
-while (true) {
-    print('infinity');
-}
-
------- >8 ======
-Correct mapping for <while>
-Correct mapping for <infinity>
-Correct mapping for <);>
-
-Running: doWhileFormatting
-====== 8< ------
-do {
-    print('infinity');
-} while (true);
------- >8 ======
-Correct mapping for <while>
-Correct mapping for <infinity>
-
-Running: functionFormatting
-====== 8< ------
-function test(a, b, c) {
-    a *= b;
-    return c + a;
-}
-
------- >8 ======
-Correct mapping for <return>
-Correct mapping for <*=>
-
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-4.js b/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-4.js
deleted file mode 100644
index f400481..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-4.js
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-(async function() {
-  TestRunner.addResult(`Verifies JavaScript pretty-printing functionality.\n`);
-  await TestRunner.loadModule('sources_test_runner');
-  await TestRunner.showPanel('sources');
-  await TestRunner.addScriptTag('debugger/resources/obfuscated.js');
-
-  var testJSFormatter = SourcesTestRunner.testPrettyPrint.bind(SourcesTestRunner, 'text/javascript');
-
-  TestRunner.runTestSuite([
-    function withStatementFormatting(next) {
-      var mappingQueries = ['first', 'obj', 'nice', '1', '2', 'done'];
-      testJSFormatter('with(obj)log(\'first\');with(nice){log(1);log(2);}done();', mappingQueries, next);
-    },
-
-    function switchStatementFormatting(next) {
-      var mappingQueries = ['even', 'odd', '89', 'done'];
-      testJSFormatter(
-          'switch (a) { case 1, 3: log("odd");break;case 2:log("even");break;case 42:case 89: log(a);default:log("interesting");log(a);}log("done");',
-          mappingQueries, next);
-    },
-
-    function whileFormatting(next) {
-      var mappingQueries = ['while', 'infinity', ');'];
-      testJSFormatter('while(true){print(\'infinity\');}', mappingQueries, next);
-    },
-
-    function doWhileFormatting(next) {
-      var mappingQueries = ['while', 'infinity'];
-      testJSFormatter('do{print(\'infinity\');}while(true);', mappingQueries, next);
-    },
-
-    function functionFormatting(next) {
-      var mappingQueries = ['return', '*='];
-      testJSFormatter('function test(a,b,c){a*=b;return c+a;}', mappingQueries, next);
-    },
-  ]);
-})();
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-5-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-5-expected.txt
deleted file mode 100644
index be3d728..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-5-expected.txt
+++ /dev/null
@@ -1,125 +0,0 @@
-Verifies JavaScript pretty-printing functionality.
-
-
-Running: forInFormatting
-====== 8< ------
-for (var key in myMap)
-    print(key);
-
------- >8 ======
-Correct mapping for <myMap>
-Correct mapping for <print>
-
-Running: forOfFormatting
-====== 8< ------
-for (var value of myMap)
-    print(value);
-
------- >8 ======
-Correct mapping for <myMap>
-Correct mapping for <print>
-
-Running: commaBetweenStatementsFormatting
-====== 8< ------
-rebuild(),
-show(),
-hasNew ? refresh() : noop();
-
------- >8 ======
-Correct mapping for <noop>
-Correct mapping for <hasNew>
-
-Running: complexScriptFormatting
-====== 8< ------
-function formatted1() {
-    var variable1 = 0;
-}
-
-function withComments() {
-    // comment
-    return "functionWithComments";
-}
-
-try {
-    onmessage = function(event) {
-        var source = event.data;
-        var formattedSource = beautify(source);
-        var mapping = buildMapping(source, formattedSource);
-        postMessage({
-            formattedSource: formattedSource,
-            mapping: mapping
-        })
-    }
-    ;
-    function beautify(source) {
-        var ast = parse.parse(source);
-        var beautifyOptions = {
-            indent_level: 4,
-            indent_start: 0,
-            quote_keys: false,
-            space_colon: false
-        };
-        return process.gen_code(ast, beautifyOptions)
-    }
-    function buildMapping(source, formattedSource) {
-        var mapping = {
-            original: [],
-            formatted: []
-        };
-        var lastPosition = 0;
-        var regexp = /(^|[^\\])\b((?=\D)[\$\.\w]+)\b/g;
-        while (true) {
-            var match = regexp.exec(formattedSource);
-            if (!match)
-                break;
-            var position = source.indexOf(match[2], lastPosition);
-            if (position === -1)
-                throw "No match found in original source for " + match[2];
-            mapping.original.push(position);
-            mapping.formatted.push(match.index + match[1].length);
-            lastPosition = position + match[2].length
-        }
-        return mapping
-    }
-    function require() {
-        return parse
-    }
-    var exports = {};
-    importScripts("UglifyJS/parse-js.js");
-    var parse = exports;
-    var exports = {};
-    importScripts("UglifyJS/process.js");
-    var process = exports;
-} catch (e) {}
-
-function formatted2() {
-    var variable2 = 0;
-}
-
------- >8 ======
-Correct mapping for <function>
-Correct mapping for <formatted1>
-Correct mapping for <variable1>
-Correct mapping for <    return "functionWithComments">
-Correct mapping for <onmessage>
-Correct mapping for <indent_start>
-Correct mapping for <function require>
-Correct mapping for <var regexp>
-Correct mapping for <importScripts>
-Correct mapping for <formatted2>
-
-Running: ifStatementIndentRegression
-====== 8< ------
-{
-    if (a > b) {
-        a();
-        pretty();
-    } else if (a + b)
-        e();
-    reset();
-}
-
------- >8 ======
-Correct mapping for <pretty>
-Correct mapping for <reset>
-
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-5.js b/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-5.js
deleted file mode 100644
index 2d33571..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-5.js
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-(async function() {
-  TestRunner.addResult(`Verifies JavaScript pretty-printing functionality.\n`);
-  await TestRunner.loadModule('sources_test_runner');
-  await TestRunner.showPanel('sources');
-  await TestRunner.addScriptTag('debugger/resources/obfuscated.js');
-
-  var testJSFormatter = SourcesTestRunner.testPrettyPrint.bind(SourcesTestRunner, 'text/javascript');
-
-  TestRunner.runTestSuite([
-    function forInFormatting(next) {
-      var mappingQueries = ['myMap', 'print'];
-      testJSFormatter('for(var key in myMap)print(key);', mappingQueries, next);
-    },
-
-    function forOfFormatting(next) {
-      var mappingQueries = ['myMap', 'print'];
-      testJSFormatter('for(var value of myMap)print(value);', mappingQueries, next);
-    },
-
-    function commaBetweenStatementsFormatting(next) {
-      var mappingQueries = ['noop', 'hasNew'];
-      testJSFormatter('rebuild(),show(),hasNew?refresh():noop();', mappingQueries, next);
-    },
-
-    function complexScriptFormatting(next) {
-      SourcesTestRunner.showScriptSource('obfuscated.js', didShowScriptSource);
-
-      function didShowScriptSource(sourceFrame) {
-        var mappingQueries = [
-          'function', 'formatted1', 'variable1', '    return "functionWithComments"', 'onmessage', 'indent_start',
-          'function require', 'var regexp', 'importScripts', 'formatted2'
-        ];
-        testJSFormatter(sourceFrame._textEditor.text(), mappingQueries, next);
-      }
-    },
-
-    function ifStatementIndentRegression(next) {
-      var mappingQueries = ['pretty', 'reset'];
-      testJSFormatter('{if (a>b){a();pretty();}else if (a+b)e();reset();}', mappingQueries, next);
-    },
-  ]);
-})();
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-6-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-6-expected.txt
deleted file mode 100644
index ab1a048..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-6-expected.txt
+++ /dev/null
@@ -1,101 +0,0 @@
-Verifies JavaScript pretty-printing functionality.
-
-
-Running: trailingCommentsTest
-====== 8< ------
-noop();
-//#sourceMappingURL=program.js.map
-
------- >8 ======
-
-Running: inlinedScriptFormatting
-====== 8< ------
-<html>
-    <body>
-        <script>
-            function f() {}
-        </script>
-        <script>
-            function g() {
-                var a;
-                window.return = 10;
-                if (a)
-                    return;
-            }
-        </script>
-    </body>
-</html>
-
------- >8 ======
-
-Running: generatorFormatter
-====== 8< ------
-function *max() {
-    var a = yield;
-    var b = yield 10;
-    if (a > b)
-        return a;
-    else
-        return b;
-}
-
------- >8 ======
-Correct mapping for <max>
-Correct mapping for <*>
-Correct mapping for <else>
-
-Running: blockCommentFormatter
-====== 8< ------
-/** this
- * is
- * block
- * comment
- */
-var a = 10;
-
------- >8 ======
-Correct mapping for <this>
-Correct mapping for <is>
-Correct mapping for <block>
-Correct mapping for <comment>
-Correct mapping for <var>
-Correct mapping for <10>
-
-Running: lexicalScoping
-====== 8< ------
-for (var i = 0; i < names.length; ++i) {
-    let name = names[i];
-    let person = persons[i];
-}
-
------- >8 ======
-Correct mapping for <for>
-Correct mapping for <person>
-Correct mapping for <name>
-Correct mapping for <}>
-
-Running: anonimousFunctionAsParameter
-====== 8< ------
-setTimeout(function() {
-    alert(1);
-}, 2000);
-
------- >8 ======
-Correct mapping for <setTimeout>
-Correct mapping for <function>
-Correct mapping for <alert>
-Correct mapping for <2000>
-
-Running: arrowFunction
-====== 8< ------
-function test(arg) {
-    console.log(arg);
-}
-test(a=>a + 2);
-
------- >8 ======
-Correct mapping for <function>
-Correct mapping for <console>
-Correct mapping for <=>>
-Correct mapping for <2>
-
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-6.js b/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-6.js
deleted file mode 100644
index 26bf696c..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-6.js
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-(async function() {
-  TestRunner.addResult(`Verifies JavaScript pretty-printing functionality.\n`);
-  await TestRunner.loadModule('sources_test_runner');
-  await TestRunner.showPanel('sources');
-  await TestRunner.addScriptTag('debugger/resources/obfuscated.js');
-
-  var testJSFormatter = SourcesTestRunner.testPrettyPrint.bind(SourcesTestRunner, 'text/javascript');
-
-  TestRunner.runTestSuite([
-    function trailingCommentsTest(next) {
-      var mappingQueries = [];
-      testJSFormatter('noop(); //#sourceMappingURL=program.js.map', mappingQueries, next);
-    },
-
-    function inlinedScriptFormatting(next) {
-      var content = '<html><body><script>function f(){}<' +
-          '/script><script>function g(){var a;window.return = 10;if (a) return;}<' +
-          '/script></body></html>';
-      SourcesTestRunner.testPrettyPrint('text/html', content, [], next);
-    },
-
-    function generatorFormatter(next) {
-      var mappingQueries = ['max', '*', 'else'];
-      testJSFormatter(
-          'function *max(){var a=yield;var b=yield 10;if(a>b)return a;else return b;}', mappingQueries, next);
-    },
-
-    function blockCommentFormatter(next) {
-      var mappingQueries = ['this', 'is', 'block', 'comment', 'var', '10'];
-      testJSFormatter('/** this\n * is\n * block\n * comment\n */\nvar a=10;', mappingQueries, next);
-    },
-
-    function lexicalScoping(next) {
-      var mappingQueries = ['for', 'person', 'name', '}'];
-      testJSFormatter(
-          'for(var i=0;i<names.length;++i){let name=names[i];let person=persons[i];}', mappingQueries, next);
-    },
-
-    function anonimousFunctionAsParameter(next) {
-      var mappingQueries = ['setTimeout', 'function', 'alert', '2000'];
-      testJSFormatter('setTimeout(function(){alert(1);},2000);', mappingQueries, next);
-    },
-
-    function arrowFunction(next) {
-      var mappingQueries = ['function', 'console', '=>', '2'];
-      testJSFormatter('function test(arg){console.log(arg);}test(a=>a+2);', mappingQueries, next);
-    }
-  ]);
-})();
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-7-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-7-expected.txt
deleted file mode 100644
index 95982df..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-7-expected.txt
+++ /dev/null
@@ -1,90 +0,0 @@
-Verifies JavaScript pretty-printing functionality.
-
-
-Running: semicolonAfterFunctionExpression
-====== 8< ------
-var onClick = function() {
-    console.log('click!');
-};
-console.log('done');
-
------- >8 ======
-Correct mapping for <onClick>
-Correct mapping for <function>
-Correct mapping for <console>
-Correct mapping for <log>
-Correct mapping for <click!>
-Correct mapping for <done>
-
-Running: semicolonAfterMultipleFunctionExpressions
-====== 8< ------
-var onStart = function() {
-    a();
-}
-  , onFinish = function() {
-    b();
-};
-
------- >8 ======
-Correct mapping for <onStart>
-Correct mapping for <onFinish>
-Correct mapping for <a()>
-Correct mapping for <b()>
-
-Running: semicolonAfterEmptyFunctionExpressions
-====== 8< ------
-var onStart = function() {}
-  , delay = 1000
-  , belay = document.activeElement;
-
------- >8 ======
-Correct mapping for <onStart>
-Correct mapping for <delay>
-Correct mapping for <1000>
-Correct mapping for <belay>
-Correct mapping for <activeElement>
-
-Running: continueStatementFormatting
-====== 8< ------
-function foo() {
-    while (1) {
-        if (a)
-            continue;
-        test();
-    }
-}
-
------- >8 ======
-Correct mapping for <function>
-Correct mapping for <1>
-Correct mapping for <continue>
-Correct mapping for <test>
-
-Running: inconsistentSpaceAfterNull
-====== 8< ------
-1 || null;
-
------- >8 ======
-Correct mapping for <||>
-Correct mapping for <null>
-Correct mapping for <;>
-
-Running: squashMultipleNewlines
-====== 8< ------
-a();
-
-b();
-
------- >8 ======
-Correct mapping for <a>
-Correct mapping for <b>
-
-Running: ensureExponentialOperator
-====== 8< ------
-2 ** 3
-
------- >8 ======
-Correct mapping for <2>
-Correct mapping for <**>
-Correct mapping for <3>
-
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-7.js b/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-7.js
deleted file mode 100644
index 000a4aaa..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-7.js
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-(async function() {
-  TestRunner.addResult(`Verifies JavaScript pretty-printing functionality.\n`);
-  await TestRunner.loadModule('sources_test_runner');
-  await TestRunner.showPanel('sources');
-
-  var testJSFormatter = SourcesTestRunner.testPrettyPrint.bind(SourcesTestRunner, 'text/javascript');
-
-  TestRunner.runTestSuite([
-    function semicolonAfterFunctionExpression(next) {
-      var mappingQueries = ['onClick', 'function', 'console', 'log', 'click!', 'done'];
-      testJSFormatter(
-          'var onClick = function() { console.log(\'click!\'); };console.log(\'done\');', mappingQueries, next);
-    },
-
-    function semicolonAfterMultipleFunctionExpressions(next) {
-      var mappingQueries = ['onStart', 'onFinish', 'a()', 'b()'];
-      testJSFormatter('var onStart = function() { a(); }, onFinish = function() { b(); };', mappingQueries, next);
-    },
-
-    function semicolonAfterEmptyFunctionExpressions(next) {
-      var mappingQueries = ['onStart', 'delay', '1000', 'belay', 'activeElement'];
-      testJSFormatter('var onStart = function() {}, delay=1000, belay=document.activeElement;', mappingQueries, next);
-    },
-
-    function continueStatementFormatting(next) {
-      var mappingQueries = ['function', '1', 'continue', 'test'];
-      testJSFormatter('function foo(){while(1){if (a)continue;test();}}', mappingQueries, next);
-    },
-
-    function inconsistentSpaceAfterNull(next) {
-      var mappingQueries = ['||', 'null', ';'];
-      testJSFormatter('1||null;', mappingQueries, next);
-    },
-
-    function squashMultipleNewlines(next) {
-      var mappingQueries = ['a', 'b'];
-      testJSFormatter('a();\n\n\n\n\n\n\n\n\nb();', mappingQueries, next);
-    },
-
-    function ensureExponentialOperator(next) {
-      var mappingQueries = ['2', '**', '3'];
-      testJSFormatter('2**3', mappingQueries, next);
-    },
-  ]);
-})();
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-8-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-8-expected.txt
deleted file mode 100644
index 6c3f1cf..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-8-expected.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-Verifies JavaScript pretty-printing functionality.
-
-
-Running: asyncAwaitSupport
-====== 8< ------
-async function foo() {
-    return await Promise.resolve(1);
-}
-
------- >8 ======
-Correct mapping for <async>
-Correct mapping for <function>
-Correct mapping for <foo>
-Correct mapping for <return>
-Correct mapping for <Promise>
-Correct mapping for <resolve>
-
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-8.js b/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-8.js
deleted file mode 100644
index 90b4112..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-8.js
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-(async function() {
-  TestRunner.addResult(`Verifies JavaScript pretty-printing functionality.\n`);
-  await TestRunner.loadModule('sources_test_runner');
-  await TestRunner.showPanel('sources');
-
-  var testJSFormatter = SourcesTestRunner.testPrettyPrint.bind(SourcesTestRunner, 'text/javascript');
-
-  TestRunner.runTestSuite([
-    function asyncAwaitSupport(next) {
-      var mappingQueries = ['async', 'function', 'foo', 'return', 'Promise', 'resolve'];
-      testJSFormatter('async function foo() {return await Promise.resolve(1);}', mappingQueries, next);
-    },
-  ]);
-})();
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-9-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-9-expected.txt
deleted file mode 100644
index 100a911..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-9-expected.txt
+++ /dev/null
@@ -1,38 +0,0 @@
-Verifies JavaScript pretty-printing functionality.
-
-
-Running: parenthesizedExpressions
-====== 8< ------
-if ((a))
-    ((b));
-else
-    (c);
-
------- >8 ======
-Correct mapping for <if>
-Correct mapping for <((a))>
-Correct mapping for <((b));>
-Correct mapping for <else>
-Correct mapping for <(c)>
-
-Running: objectDesctructuring
-====== 8< ------
-let {x, y} = getXYFromTouchOrPointer(e);
-
------- >8 ======
-Correct mapping for <let>
-Correct mapping for <y>
-Correct mapping for <getXYFromTouchOrPointer>
-Correct mapping for <e>
-
-Running: objectDesctructuringInFunctionExpression
-====== 8< ------
-var test = function({x, y}) {
-    foo(x, y);
-}
-
------- >8 ======
-Correct mapping for <test>
-Correct mapping for <function>
-Correct mapping for <foo>
-
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-9.js b/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-9.js
deleted file mode 100644
index 448d5c63..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-9.js
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-(async function() {
-  TestRunner.addResult(`Verifies JavaScript pretty-printing functionality.\n`);
-  await TestRunner.loadModule('sources_test_runner');
-  await TestRunner.showPanel('sources');
-
-  var testJSFormatter = SourcesTestRunner.testPrettyPrint.bind(SourcesTestRunner, 'text/javascript');
-
-  TestRunner.runTestSuite([
-    function parenthesizedExpressions(next) {
-      var mappingQueries = ['if', '((a))', '((b));', 'else', '(c)'];
-      testJSFormatter('if((a))((b));else (c);', mappingQueries, next);
-    },
-
-    function objectDesctructuring(next) {
-      var mappingQueries = ['let', 'y', 'getXYFromTouchOrPointer', 'e'];
-      testJSFormatter('let{x,y}=getXYFromTouchOrPointer(e);', mappingQueries, next);
-    },
-
-    function objectDesctructuringInFunctionExpression(next) {
-      var mappingQueries = ['test', 'function', 'foo'];
-      testJSFormatter('var test = function({x,y}){foo(x,y);}', mappingQueries, next);
-    },
-  ]);
-})();
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-classes-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-classes-expected.txt
deleted file mode 100644
index 06080dc..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-classes-expected.txt
+++ /dev/null
@@ -1,103 +0,0 @@
-Verifies JavaScript pretty-printing functionality.
-
-
-Running: emptyClass
-====== 8< ------
-class Test {
-}
-
------- >8 ======
-Correct mapping for <Test>
-Correct mapping for <class>
-
-Running: emptyConstructor
-====== 8< ------
-class Test {
-    constructor() {}
-}
-
------- >8 ======
-Correct mapping for <Test>
-Correct mapping for <class>
-Correct mapping for <constructor>
-
-Running: simpleClass
-====== 8< ------
-class Test {
-    constructor() {
-        this.bar = 10;
-    }
-    givemebar() {
-        return this.bar;
-    }
-}
-
------- >8 ======
-Correct mapping for <Test>
-Correct mapping for <class>
-Correct mapping for <constructor>
-
-Running: extendedClass
-====== 8< ------
-class Foo extends Bar {
-    constructor(name) {
-        super(name);
-    }
-    getName() {
-        return super.getName();
-    }
-}
-
------- >8 ======
-Correct mapping for <Foo>
-Correct mapping for <Bar>
-Correct mapping for <extends>
-Correct mapping for <super>
-Correct mapping for <name>
-
-Running: twoConsecutiveClasses
-====== 8< ------
-class A {
-}
-class B extends A {
-    constructor() {
-        super();
-    }
-}
-
------- >8 ======
-Correct mapping for <B>
-Correct mapping for <extends>
-Correct mapping for <constructor>
-Correct mapping for <super>
-
-Running: staticMethod
-====== 8< ------
-class Employer {
-    static count() {
-        this._counter = (this._counter || 0) + 1;
-        return this._counter;
-    }
-}
-
------- >8 ======
-Correct mapping for <Employer>
-Correct mapping for <static>
-Correct mapping for <1>
-Correct mapping for <return>
-
-Running: classExpression
-====== 8< ------
-new (class {
-    constructor() {
-        debugger
-    }
-}
-)
-
------- >8 ======
-Correct mapping for <new>
-Correct mapping for <class>
-Correct mapping for <constructor>
-Correct mapping for <debugger>
-
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-classes.js b/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-classes.js
deleted file mode 100644
index ad2bf4c..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-classes.js
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-(async function() {
-  TestRunner.addResult(`Verifies JavaScript pretty-printing functionality.\n`);
-  await TestRunner.loadModule('sources_test_runner');
-  await TestRunner.showPanel('sources');
-  await TestRunner.addScriptTag('debugger/resources/obfuscated.js');
-
-  var testJSFormatter = SourcesTestRunner.testPrettyPrint.bind(SourcesTestRunner, 'text/javascript');
-
-  TestRunner.runTestSuite([
-    function emptyClass(next) {
-      var mappingQueries = ['Test', 'class'];
-      testJSFormatter('class Test{}', mappingQueries, next);
-    },
-
-    function emptyConstructor(next) {
-      var mappingQueries = ['Test', 'class', 'constructor'];
-      testJSFormatter('class Test{constructor(){}}', mappingQueries, next);
-    },
-
-    function simpleClass(next) {
-      var mappingQueries = ['Test', 'class', 'constructor'];
-      testJSFormatter('class Test{constructor(){this.bar=10;}givemebar(){return this.bar;}}', mappingQueries, next);
-    },
-
-    function extendedClass(next) {
-      var mappingQueries = ['Foo', 'Bar', 'extends', 'super', 'name'];
-      testJSFormatter(
-          'class Foo extends Bar{constructor(name){super(name);}getName(){return super.getName();}}', mappingQueries,
-          next);
-    },
-
-    function twoConsecutiveClasses(next) {
-      var mappingQueries = ['B', 'extends', 'constructor', 'super'];
-      testJSFormatter('class A{}class B extends A{constructor(){super();}}', mappingQueries, next);
-    },
-
-    function staticMethod(next) {
-      var mappingQueries = ['Employer', 'static', '1', 'return'];
-      testJSFormatter(
-          'class Employer{static count(){this._counter = (this._counter || 0) + 1; return this._counter;}}',
-          mappingQueries, next);
-    },
-
-    function classExpression(next) {
-      var mappingQueries = ['new', 'class', 'constructor', 'debugger'];
-      testJSFormatter('new(class{constructor(){debugger}})', mappingQueries, next);
-    },
-  ]);
-})();
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-template-literals-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-template-literals-expected.txt
deleted file mode 100644
index 925409b..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-template-literals-expected.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-Verifies JavaScript pretty-printing functionality.
-
-
-Running: simpleLiteral
-====== 8< ------
-var foo = `bar`;
-
------- >8 ======
-Correct mapping for <foo>
-Correct mapping for <bar>
-
-Running: multilineLiteral
-====== 8< ------
-var foo = `this
-bar`;
-
------- >8 ======
-Correct mapping for <foo>
-Correct mapping for <bar>
-
-Running: stringSubstitution
-====== 8< ------
-var a = `I have ${credit + cash}$`;
-
------- >8 ======
-Correct mapping for <credit>
-Correct mapping for <cash>
-
-Running: multipleStringSubstitution
-====== 8< ------
-var a = `${name} has ${credit + cash}${currency ? currency : "$"}`;
-
------- >8 ======
-Correct mapping for <credit>
-Correct mapping for <cash>
-
-Running: taggedTemplate
-====== 8< ------
-escapeHtml`<div class=${classnName} width=${a + b}/>`;
-
------- >8 ======
-Correct mapping for <escapeHtml>
-Correct mapping for <width>
-
-Running: escapedApostrophe
-====== 8< ------
-var a=`That`s great!`;
------- >8 ======
-Correct mapping for <That>
-Correct mapping for <great>
-
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-template-literals.js b/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-template-literals.js
deleted file mode 100644
index 9c97d7cb..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/pretty-print-javascript-template-literals.js
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-(async function() {
-  TestRunner.addResult(`Verifies JavaScript pretty-printing functionality.\n`);
-  await TestRunner.loadModule('sources_test_runner');
-  await TestRunner.showPanel('sources');
-  await TestRunner.addScriptTag('debugger/resources/obfuscated.js');
-
-  var testJSFormatter = SourcesTestRunner.testPrettyPrint.bind(SourcesTestRunner, 'text/javascript');
-
-  TestRunner.runTestSuite([
-    function simpleLiteral(next) {
-      var mappingQueries = ['foo', 'bar'];
-      testJSFormatter('var foo = `bar`;', mappingQueries, next);
-    },
-
-    function multilineLiteral(next) {
-      var mappingQueries = ['foo', 'bar'];
-      testJSFormatter('var foo = `this\nbar`;', mappingQueries, next);
-    },
-
-    function stringSubstitution(next) {
-      var mappingQueries = ['credit', 'cash'];
-      testJSFormatter('var a=`I have ${credit+cash}$`;', mappingQueries, next);
-    },
-
-    function multipleStringSubstitution(next) {
-      var mappingQueries = ['credit', 'cash'];
-      testJSFormatter('var a=`${name} has ${credit+cash}${currency?currency:"$"}`;', mappingQueries, next);
-    },
-
-    function taggedTemplate(next) {
-      var mappingQueries = ['escapeHtml', 'width'];
-      testJSFormatter('escapeHtml`<div class=${classnName} width=${a+b}/>`;', mappingQueries, next);
-    },
-
-    function escapedApostrophe(next) {
-      var mappingQueries = ['That', 'great'];
-      testJSFormatter('var a=`That\`s great!`;', mappingQueries, next);
-    }
-  ]);
-})();
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 8eb814b..8e2f361 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
@@ -1278,6 +1278,14 @@
     method receiveDatagrams
     method receiveStreams
     method sendDatagrams
+interface ReadableByteStreamController
+    attribute @@toStringTag
+    getter byobRequest
+    getter desiredSize
+    method close
+    method constructor
+    method enqueue
+    method error
 interface ReadableStream
     attribute @@toStringTag
     getter locked
@@ -1287,6 +1295,19 @@
     method pipeThrough
     method pipeTo
     method tee
+interface ReadableStreamBYOBReader
+    attribute @@toStringTag
+    getter closed
+    method cancel
+    method constructor
+    method read
+    method releaseLock
+interface ReadableStreamBYOBRequest
+    attribute @@toStringTag
+    getter view
+    method constructor
+    method respond
+    method respondWithNewView
 interface ReadableStreamDefaultReader
     attribute @@toStringTag
     getter closed
diff --git a/third_party/blink/web_tests/http/tests/streams/chromium/get-reader-byob.html b/third_party/blink/web_tests/http/tests/streams/chromium/get-reader-byob.html
deleted file mode 100644
index 61a03225..0000000
--- a/third_party/blink/web_tests/http/tests/streams/chromium/get-reader-byob.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script>
-test(() => {
-  const rs = new ReadableStream();
-  assert_throws_js(TypeError, () => rs.getReader({mode: 'byob'}),
-                   'a TypeError should be thrown');
-}, 'getReader() with mode "byob" should throw a TypeError');
-</script>
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 a4ddbb8..0d43280 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
@@ -1262,6 +1262,14 @@
 [Worker]     method receiveDatagrams
 [Worker]     method receiveStreams
 [Worker]     method sendDatagrams
+[Worker] interface ReadableByteStreamController
+[Worker]     attribute @@toStringTag
+[Worker]     getter byobRequest
+[Worker]     getter desiredSize
+[Worker]     method close
+[Worker]     method constructor
+[Worker]     method enqueue
+[Worker]     method error
 [Worker] interface ReadableStream
 [Worker]     attribute @@toStringTag
 [Worker]     getter locked
@@ -1271,6 +1279,19 @@
 [Worker]     method pipeThrough
 [Worker]     method pipeTo
 [Worker]     method tee
+[Worker] interface ReadableStreamBYOBReader
+[Worker]     attribute @@toStringTag
+[Worker]     getter closed
+[Worker]     method cancel
+[Worker]     method constructor
+[Worker]     method read
+[Worker]     method releaseLock
+[Worker] interface ReadableStreamBYOBRequest
+[Worker]     attribute @@toStringTag
+[Worker]     getter view
+[Worker]     method constructor
+[Worker]     method respond
+[Worker]     method respondWithNewView
 [Worker] interface ReadableStreamDefaultReader
 [Worker]     attribute @@toStringTag
 [Worker]     getter closed
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 9ad654c..0203a5d7 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
@@ -6615,6 +6615,14 @@
     method setStartBefore
     method surroundContents
     method toString
+interface ReadableByteStreamController
+    attribute @@toStringTag
+    getter byobRequest
+    getter desiredSize
+    method close
+    method constructor
+    method enqueue
+    method error
 interface ReadableStream
     attribute @@toStringTag
     getter locked
@@ -6624,6 +6632,19 @@
     method pipeThrough
     method pipeTo
     method tee
+interface ReadableStreamBYOBReader
+    attribute @@toStringTag
+    getter closed
+    method cancel
+    method constructor
+    method read
+    method releaseLock
+interface ReadableStreamBYOBRequest
+    attribute @@toStringTag
+    getter view
+    method constructor
+    method respond
+    method respondWithNewView
 interface ReadableStreamDefaultReader
     attribute @@toStringTag
     getter closed
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 014ca2839..678e6108 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
@@ -1167,6 +1167,14 @@
 [Worker]     method receiveDatagrams
 [Worker]     method receiveStreams
 [Worker]     method sendDatagrams
+[Worker] interface ReadableByteStreamController
+[Worker]     attribute @@toStringTag
+[Worker]     getter byobRequest
+[Worker]     getter desiredSize
+[Worker]     method close
+[Worker]     method constructor
+[Worker]     method enqueue
+[Worker]     method error
 [Worker] interface ReadableStream
 [Worker]     attribute @@toStringTag
 [Worker]     getter locked
@@ -1176,6 +1184,19 @@
 [Worker]     method pipeThrough
 [Worker]     method pipeTo
 [Worker]     method tee
+[Worker] interface ReadableStreamBYOBReader
+[Worker]     attribute @@toStringTag
+[Worker]     getter closed
+[Worker]     method cancel
+[Worker]     method constructor
+[Worker]     method read
+[Worker]     method releaseLock
+[Worker] interface ReadableStreamBYOBRequest
+[Worker]     attribute @@toStringTag
+[Worker]     getter view
+[Worker]     method constructor
+[Worker]     method respond
+[Worker]     method respondWithNewView
 [Worker] interface ReadableStreamDefaultReader
 [Worker]     attribute @@toStringTag
 [Worker]     getter closed
diff --git a/third_party/boringssl/DIR_METADATA b/third_party/boringssl/DIR_METADATA
new file mode 100644
index 0000000..72c19cd
--- /dev/null
+++ b/third_party/boringssl/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Internals>Network>SSL"
+}
+team_email: "net-dev@chromium.org"
diff --git a/third_party/boringssl/OWNERS b/third_party/boringssl/OWNERS
index 54fb4be..411f841 100644
--- a/third_party/boringssl/OWNERS
+++ b/third_party/boringssl/OWNERS
@@ -2,6 +2,3 @@
 davidben@chromium.org
 rsleevi@chromium.org
 svaldez@chromium.org
-
-# COMPONENT: Internals>Network>SSL
-# TEAM: net-dev@chromium.org
diff --git a/third_party/bouncycastle/DIR_METADATA b/third_party/bouncycastle/DIR_METADATA
new file mode 100644
index 0000000..5abea21
--- /dev/null
+++ b/third_party/bouncycastle/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Test>Android"
+}
diff --git a/third_party/bouncycastle/OWNERS b/third_party/bouncycastle/OWNERS
index 8fd43ad6..d107d25c 100644
--- a/third_party/bouncycastle/OWNERS
+++ b/third_party/bouncycastle/OWNERS
@@ -1,5 +1,3 @@
 bjoyce@chromium.org
 hypan@google.com
 yzjr@google.com
-
-# COMPONENT: Test>Android
diff --git a/third_party/breakpad/DIR_METADATA b/third_party/breakpad/DIR_METADATA
new file mode 100644
index 0000000..2028e515
--- /dev/null
+++ b/third_party/breakpad/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Internals>CrashReporting"
+}
+team_email: "google-breakpad-dev@googlegroups.com"
diff --git a/third_party/breakpad/OWNERS b/third_party/breakpad/OWNERS
index c70e545..d38d4ab 100644
--- a/third_party/breakpad/OWNERS
+++ b/third_party/breakpad/OWNERS
@@ -1,5 +1,2 @@
 mark@chromium.org
 thestig@chromium.org
-
-# TEAM: google-breakpad-dev@googlegroups.com
-# COMPONENT: Internals>CrashReporting
diff --git a/third_party/brotli/DIR_METADATA b/third_party/brotli/DIR_METADATA
new file mode 100644
index 0000000..be778358
--- /dev/null
+++ b/third_party/brotli/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>WebFonts"
+}
+team_email: "loading-dev@chromium.org"
diff --git a/third_party/brotli/OWNERS b/third_party/brotli/OWNERS
index 9416e2a3..458697e6 100644
--- a/third_party/brotli/OWNERS
+++ b/third_party/brotli/OWNERS
@@ -1,5 +1,2 @@
 ksakamoto@chromium.org
 bashi@chromium.org
-
-# COMPONENT: Blink>WebFonts
-# TEAM: loading-dev@chromium.org
diff --git a/third_party/bspatch/DIR_METADATA b/third_party/bspatch/DIR_METADATA
new file mode 100644
index 0000000..9123604d
--- /dev/null
+++ b/third_party/bspatch/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>Installer"
+}
diff --git a/third_party/bspatch/OWNERS b/third_party/bspatch/OWNERS
index c11ac94..e69de29 100644
--- a/third_party/bspatch/OWNERS
+++ b/third_party/bspatch/OWNERS
@@ -1 +0,0 @@
-# COMPONENT: Internals>Installer
diff --git a/third_party/byte_buddy/DIR_METADATA b/third_party/byte_buddy/DIR_METADATA
new file mode 100644
index 0000000..5abea21
--- /dev/null
+++ b/third_party/byte_buddy/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Test>Android"
+}
diff --git a/third_party/byte_buddy/OWNERS b/third_party/byte_buddy/OWNERS
index 8fd43ad6..d107d25c 100644
--- a/third_party/byte_buddy/OWNERS
+++ b/third_party/byte_buddy/OWNERS
@@ -1,5 +1,3 @@
 bjoyce@chromium.org
 hypan@google.com
 yzjr@google.com
-
-# COMPONENT: Test>Android
diff --git a/third_party/ced/DIR_METADATA b/third_party/ced/DIR_METADATA
new file mode 100644
index 0000000..cde4806c
--- /dev/null
+++ b/third_party/ced/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>TextEncoding"
+}
diff --git a/third_party/ced/OWNERS b/third_party/ced/OWNERS
index 38383bf..885c9ea 100644
--- a/third_party/ced/OWNERS
+++ b/third_party/ced/OWNERS
@@ -1,3 +1,2 @@
 jinsukkim@chromium.org
-jshin@chromium.org
-# COMPONENT: Blink>TextEncoding
+jshin@chromium.org
\ No newline at end of file
diff --git a/third_party/chaijs/DIR_METADATA b/third_party/chaijs/DIR_METADATA
new file mode 100644
index 0000000..8325efa
--- /dev/null
+++ b/third_party/chaijs/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>WebUI"
+}
diff --git a/third_party/chaijs/OWNERS b/third_party/chaijs/OWNERS
index ceda05c..241797ac 100644
--- a/third_party/chaijs/OWNERS
+++ b/third_party/chaijs/OWNERS
@@ -1,2 +1 @@
-dpapad@chromium.org
-# COMPONENT: UI>Browser>WebUI
+dpapad@chromium.org
\ No newline at end of file
diff --git a/third_party/chromevox/DIR_METADATA b/third_party/chromevox/DIR_METADATA
new file mode 100644
index 0000000..299fade
--- /dev/null
+++ b/third_party/chromevox/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Accessibility"
+}
+team_email: "chromium-accessibility@chromium.org"
diff --git a/third_party/chromevox/OWNERS b/third_party/chromevox/OWNERS
index 7d496ba..dfab84a0 100644
--- a/third_party/chromevox/OWNERS
+++ b/third_party/chromevox/OWNERS
@@ -2,6 +2,3 @@
 dmazzoni@chromium.org
 dtseng@chromium.org
 plundblad@chromium.org
-
-# TEAM: chromium-accessibility@chromium.org
-# COMPONENT: UI>Accessibility
diff --git a/third_party/cld_3/DIR_METADATA b/third_party/cld_3/DIR_METADATA
new file mode 100644
index 0000000..f750899
--- /dev/null
+++ b/third_party/cld_3/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>Language>Translate"
+}
diff --git a/third_party/cld_3/OWNERS b/third_party/cld_3/OWNERS
index 8fc87a1..99c5de0 100644
--- a/third_party/cld_3/OWNERS
+++ b/third_party/cld_3/OWNERS
@@ -1,3 +1,2 @@
 andrewhayden@chromium.org
-abakalov@chromium.org
-# COMPONENT: UI>Browser>Language>Translate
+abakalov@chromium.org
\ No newline at end of file
diff --git a/third_party/closure_compiler/DIR_METADATA b/third_party/closure_compiler/DIR_METADATA
new file mode 100644
index 0000000..8325efa
--- /dev/null
+++ b/third_party/closure_compiler/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>WebUI"
+}
diff --git a/third_party/closure_compiler/OWNERS b/third_party/closure_compiler/OWNERS
index 350e69a..e889f3e 100644
--- a/third_party/closure_compiler/OWNERS
+++ b/third_party/closure_compiler/OWNERS
@@ -1,4 +1,3 @@
 calamity@chromium.org
 dpapad@chromium.org
-fukino@chromium.org
-# COMPONENT: UI>Browser>WebUI
+fukino@chromium.org
\ No newline at end of file
diff --git a/third_party/closure_compiler/externs/DIR_METADATA b/third_party/closure_compiler/externs/DIR_METADATA
new file mode 100644
index 0000000..8325efa
--- /dev/null
+++ b/third_party/closure_compiler/externs/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>WebUI"
+}
diff --git a/third_party/closure_compiler/externs/OWNERS b/third_party/closure_compiler/externs/OWNERS
index fa50a87..45dc7b4 100644
--- a/third_party/closure_compiler/externs/OWNERS
+++ b/third_party/closure_compiler/externs/OWNERS
@@ -6,5 +6,4 @@
 per-file automation.js=file://ui/accessibility/OWNERS
 per-file file_manager_private.js=file://ui/file_manager/OWNERS
 per-file input_method_private.js=file://ui/base/ime/OWNERS
-per-file terminal_private.js=file://chrome/browser/chromeos/guest_os/OWNERS
-# COMPONENT: UI>Browser>WebUI
+per-file terminal_private.js=file://chrome/browser/chromeos/guest_os/OWNERS
\ No newline at end of file
diff --git a/third_party/colorama/DIR_METADATA b/third_party/colorama/DIR_METADATA
new file mode 100644
index 0000000..983ea01
--- /dev/null
+++ b/third_party/colorama/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Tools"
+}
diff --git a/third_party/colorama/OWNERS b/third_party/colorama/OWNERS
index 32e3eca0..e69de29 100644
--- a/third_party/colorama/OWNERS
+++ b/third_party/colorama/OWNERS
@@ -1 +0,0 @@
-# COMPONENT: Tools
diff --git a/third_party/crashpad/DIR_METADATA b/third_party/crashpad/DIR_METADATA
new file mode 100644
index 0000000..ab965ef
--- /dev/null
+++ b/third_party/crashpad/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Internals>CrashReporting"
+}
+team_email: "crashpad-dev@chromium.org"
diff --git a/third_party/crashpad/OWNERS b/third_party/crashpad/OWNERS
index fa76be3f..7c6c8b82 100644
--- a/third_party/crashpad/OWNERS
+++ b/third_party/crashpad/OWNERS
@@ -11,6 +11,3 @@
 mark@chromium.org
 rsesek@chromium.org
 scottmg@chromium.org
-
-# TEAM: crashpad-dev@chromium.org
-# COMPONENT: Internals>CrashReporting
diff --git a/third_party/d3/DIR_METADATA b/third_party/d3/DIR_METADATA
new file mode 100644
index 0000000..11910074
--- /dev/null
+++ b/third_party/d3/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "OS>Systems>Diagnostics"
+}
diff --git a/third_party/d3/OWNERS b/third_party/d3/OWNERS
index 1cebebb..98e270d 100644
--- a/third_party/d3/OWNERS
+++ b/third_party/d3/OWNERS
@@ -1,6 +1,3 @@
 siggi@chromium.org
 chrisha@chromium.org
 joonbug@chromium.org
-
-# COMPONENT: Internals>ResourceCoordinator
-# COMPONENT: OS>Systems>Diagnostics
\ No newline at end of file
diff --git a/third_party/dav1d/DIR_METADATA b/third_party/dav1d/DIR_METADATA
new file mode 100644
index 0000000..e7517784
--- /dev/null
+++ b/third_party/dav1d/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>Media>Codecs"
+}
diff --git a/third_party/dav1d/OWNERS b/third_party/dav1d/OWNERS
index eace771..df9058b 100644
--- a/third_party/dav1d/OWNERS
+++ b/third_party/dav1d/OWNERS
@@ -1,2 +1 @@
-# COMPONENT: Internals>Media>Codecs
-file://media/OWNERS
+file://media/OWNERS
\ No newline at end of file
diff --git a/third_party/decklink/DIR_METADATA b/third_party/decklink/DIR_METADATA
new file mode 100644
index 0000000..cb95d8a
--- /dev/null
+++ b/third_party/decklink/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>GetUserMedia"
+}
+team_email: "webrtc-dev@chromium.org"
diff --git a/third_party/decklink/OWNERS b/third_party/decklink/OWNERS
index 4aa9f9c..7fb3670 100644
--- a/third_party/decklink/OWNERS
+++ b/third_party/decklink/OWNERS
@@ -1,5 +1,2 @@
 magjed@chromium.org
 tommi@chromium.org
-
-# TEAM: webrtc-dev@chromium.org
-# COMPONENT: Blink>GetUserMedia
diff --git a/third_party/devscripts/DIR_METADATA b/third_party/devscripts/DIR_METADATA
new file mode 100644
index 0000000..14b5edb
--- /dev/null
+++ b/third_party/devscripts/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals"
+}
diff --git a/third_party/devscripts/OWNERS b/third_party/devscripts/OWNERS
index 48b47ad0..17e4b81 100644
--- a/third_party/devscripts/OWNERS
+++ b/third_party/devscripts/OWNERS
@@ -1,2 +1 @@
-thestig@chromium.org
-# COMPONENT: Internals
+thestig@chromium.org
\ No newline at end of file
diff --git a/third_party/dom_distiller_js/DIR_METADATA b/third_party/dom_distiller_js/DIR_METADATA
new file mode 100644
index 0000000..56645bbf
--- /dev/null
+++ b/third_party/dom_distiller_js/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Browser>ReaderMode"
+}
+team_email: "dom-distiller-eng@google.com"
diff --git a/third_party/dom_distiller_js/OWNERS b/third_party/dom_distiller_js/OWNERS
index 0501554..c7686a9 100644
--- a/third_party/dom_distiller_js/OWNERS
+++ b/third_party/dom_distiller_js/OWNERS
@@ -2,6 +2,3 @@
 nyquist@chromium.org
 wychen@chromium.org
 yfriedman@chromium.org
-
-# COMPONENT: UI>Browser>ReaderMode
-# TEAM: dom-distiller-eng@google.com
diff --git a/third_party/dpkg-shlibdeps/DIR_METADATA b/third_party/dpkg-shlibdeps/DIR_METADATA
new file mode 100644
index 0000000..983ea01
--- /dev/null
+++ b/third_party/dpkg-shlibdeps/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Tools"
+}
diff --git a/third_party/dpkg-shlibdeps/OWNERS b/third_party/dpkg-shlibdeps/OWNERS
index 65ca995..296dc0d 100644
--- a/third_party/dpkg-shlibdeps/OWNERS
+++ b/third_party/dpkg-shlibdeps/OWNERS
@@ -1,4 +1,2 @@
 thestig@chromium.org
 thomasanderson@chromium.org
-
-# COMPONENT: Tools
diff --git a/third_party/eigen3/DIR_METADATA b/third_party/eigen3/DIR_METADATA
new file mode 100644
index 0000000..f21921424
--- /dev/null
+++ b/third_party/eigen3/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>OptimizationGuide"
+}
diff --git a/third_party/eigen3/OWNERS b/third_party/eigen3/OWNERS
index f14a8b97..d9918ce6 100644
--- a/third_party/eigen3/OWNERS
+++ b/third_party/eigen3/OWNERS
@@ -1,4 +1,3 @@
 mcrouse@chromium.org
 sophiechang@chromium.org
-tbansal@chromium.org
-# COMPONENT: Internals>OptimizationGuide
+tbansal@chromium.org
\ No newline at end of file
diff --git a/third_party/emoji-segmenter/DIR_METADATA b/third_party/emoji-segmenter/DIR_METADATA
new file mode 100644
index 0000000..7cf5d55
--- /dev/null
+++ b/third_party/emoji-segmenter/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>Fonts>Emoji"
+}
diff --git a/third_party/emoji-segmenter/OWNERS b/third_party/emoji-segmenter/OWNERS
index b937818..a0d6c05 100644
--- a/third_party/emoji-segmenter/OWNERS
+++ b/third_party/emoji-segmenter/OWNERS
@@ -1,5 +1,3 @@
 behdad@chromium.org
 drott@chromium.org
 eae@chromium.org
-
-# COMPONENT: Blink>Fonts>Emoji
diff --git a/third_party/espresso/DIR_METADATA b/third_party/espresso/DIR_METADATA
new file mode 100644
index 0000000..5abea21
--- /dev/null
+++ b/third_party/espresso/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Test>Android"
+}
diff --git a/third_party/espresso/OWNERS b/third_party/espresso/OWNERS
index 8fd43ad6..d107d25c 100644
--- a/third_party/espresso/OWNERS
+++ b/third_party/espresso/OWNERS
@@ -1,5 +1,3 @@
 bjoyce@chromium.org
 hypan@google.com
 yzjr@google.com
-
-# COMPONENT: Test>Android
diff --git a/third_party/expat/DIR_METADATA b/third_party/expat/DIR_METADATA
new file mode 100644
index 0000000..a224a64
--- /dev/null
+++ b/third_party/expat/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>XML"
+}
+team_email: "skia-discuss@googlegroups.com"
diff --git a/third_party/expat/OWNERS b/third_party/expat/OWNERS
index 029bb66..ae8e6d3 100644
--- a/third_party/expat/OWNERS
+++ b/third_party/expat/OWNERS
@@ -1,4 +1,2 @@
 bungeman@chromium.org
-dcheng@chromium.org
-# COMPONENT: Blink>XML
-# TEAM: skia-discuss@googlegroups.com
+dcheng@chromium.org
\ No newline at end of file
diff --git a/third_party/farmhash/DIR_METADATA b/third_party/farmhash/DIR_METADATA
new file mode 100644
index 0000000..f21921424
--- /dev/null
+++ b/third_party/farmhash/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>OptimizationGuide"
+}
diff --git a/third_party/farmhash/OWNERS b/third_party/farmhash/OWNERS
index f14a8b97..d9918ce6 100644
--- a/third_party/farmhash/OWNERS
+++ b/third_party/farmhash/OWNERS
@@ -1,4 +1,3 @@
 mcrouse@chromium.org
 sophiechang@chromium.org
-tbansal@chromium.org
-# COMPONENT: Internals>OptimizationGuide
+tbansal@chromium.org
\ No newline at end of file
diff --git a/third_party/protobuf/BUILD.gn b/third_party/protobuf/BUILD.gn
index a916f19e..64add5c 100644
--- a/third_party/protobuf/BUILD.gn
+++ b/third_party/protobuf/BUILD.gn
@@ -217,6 +217,14 @@
   }
 }
 
+source_set("delimited_mesage_util") {
+  sources = [
+    "src/google/protobuf/util/delimited_message_util.cc",
+    "src/google/protobuf/util/delimited_message_util.h",
+  ]
+  deps = [ ":protobuf_lite" ]
+}
+
 # This is the full, heavy protobuf lib that's needed for c++ .protos that don't
 # specify the LITE_RUNTIME option. The protocol compiler itself (protoc) falls
 # into that category. Do not use in Chrome code.
diff --git a/third_party/protobuf/README.chromium b/third_party/protobuf/README.chromium
index 4cc54da..ec90f30 100644
--- a/third_party/protobuf/README.chromium
+++ b/third_party/protobuf/README.chromium
@@ -79,4 +79,9 @@
 
 - 0022-Allow-deprecated-fields.patch
 
-  Allows depreacated fields to be used without extra C++ compiler warnings.
\ No newline at end of file
+  Allows depreacated fields to be used without extra C++ compiler warnings.
+
+- 0023-fix-delimited-message-parsing.patch
+
+  Fixes a bug in delimited message parsing and serialization, as fixed in
+  protobuf commit with hash bd9a7104e11740e4bcfbde46c190c2d908ef331a
diff --git a/third_party/protobuf/patches/0023-fix-delimited-message-parsing.patch b/third_party/protobuf/patches/0023-fix-delimited-message-parsing.patch
new file mode 100644
index 0000000..808d476
--- /dev/null
+++ b/third_party/protobuf/patches/0023-fix-delimited-message-parsing.patch
@@ -0,0 +1,63 @@
+diff --git a/src/google/protobuf/util/delimited_message_util.cc b/src/google/protobuf/util/delimited_message_util.cc
+index 425dc2cfdff8..80cab309be3d 100644
+--- a/src/google/protobuf/util/delimited_message_util.cc
++++ b/src/google/protobuf/util/delimited_message_util.cc
+@@ -74,12 +74,18 @@ bool ParseDelimitedFromCodedStream(MessageLite* message,
+     return false;
+   }
+ 
++  // Get the position after any size bytes have been read (and only the message
++  // itself remains).
++  int position_after_size = input->CurrentPosition();
++
+   // Tell the stream not to read beyond that size.
+   io::CodedInputStream::Limit limit = input->PushLimit(size);
+ 
+   // Parse the message.
+   if (!message->MergeFromCodedStream(input)) return false;
+   if (!input->ConsumedEntireMessage()) return false;
++  if (input->CurrentPosition() - position_after_size != static_cast<int>(size))
++    return false;
+ 
+   // Release the limit.
+   input->PopLimit(limit);
+diff --git a/src/google/protobuf/util/delimited_message_util_test.cc b/src/google/protobuf/util/delimited_message_util_test.cc
+index 9ed67784ee1c..9483a646e738 100644
+--- a/src/google/protobuf/util/delimited_message_util_test.cc
++++ b/src/google/protobuf/util/delimited_message_util_test.cc
+@@ -82,6 +82,35 @@ TEST(DelimitedMessageUtilTest, DelimitedMessages) {
+   }
+ }
+ 
++TEST(DelimitedMessageUtilTest, FailsAtEndOfStream) {
++  std::stringstream full_stream;
++  std::stringstream partial_stream;
++
++  {
++    protobuf_unittest::ForeignMessage message;
++    message.set_c(42);
++    message.set_d(24);
++    EXPECT_TRUE(SerializeDelimitedToOstream(message, &full_stream));
++
++    std::string full_output = full_stream.str();
++    ASSERT_GT(full_output.size(), size_t{2});
++    ASSERT_EQ(full_output[0], 4);
++
++    partial_stream << full_output[0] << full_output[1] << full_output[2];
++  }
++
++  {
++    bool clean_eof;
++    io::IstreamInputStream zstream(&partial_stream);
++
++    protobuf_unittest::ForeignMessage message;
++    clean_eof = true;
++    EXPECT_FALSE(ParseDelimitedFromZeroCopyStream(&message,
++        &zstream, &clean_eof));
++    EXPECT_FALSE(clean_eof);
++  }
++}
++
+ }  // namespace util
+ }  // namespace protobuf
+ }  // namespace google
diff --git a/third_party/protobuf/src/google/protobuf/util/delimited_message_util.cc b/third_party/protobuf/src/google/protobuf/util/delimited_message_util.cc
index 425dc2cf..80cab309 100644
--- a/third_party/protobuf/src/google/protobuf/util/delimited_message_util.cc
+++ b/third_party/protobuf/src/google/protobuf/util/delimited_message_util.cc
@@ -74,12 +74,18 @@
     return false;
   }
 
+  // Get the position after any size bytes have been read (and only the message
+  // itself remains).
+  int position_after_size = input->CurrentPosition();
+
   // Tell the stream not to read beyond that size.
   io::CodedInputStream::Limit limit = input->PushLimit(size);
 
   // Parse the message.
   if (!message->MergeFromCodedStream(input)) return false;
   if (!input->ConsumedEntireMessage()) return false;
+  if (input->CurrentPosition() - position_after_size != static_cast<int>(size))
+    return false;
 
   // Release the limit.
   input->PopLimit(limit);
diff --git a/third_party/protobuf/src/google/protobuf/util/delimited_message_util_test.cc b/third_party/protobuf/src/google/protobuf/util/delimited_message_util_test.cc
index 9ed6778..9483a64 100644
--- a/third_party/protobuf/src/google/protobuf/util/delimited_message_util_test.cc
+++ b/third_party/protobuf/src/google/protobuf/util/delimited_message_util_test.cc
@@ -82,6 +82,35 @@
   }
 }
 
+TEST(DelimitedMessageUtilTest, FailsAtEndOfStream) {
+  std::stringstream full_stream;
+  std::stringstream partial_stream;
+
+  {
+    protobuf_unittest::ForeignMessage message;
+    message.set_c(42);
+    message.set_d(24);
+    EXPECT_TRUE(SerializeDelimitedToOstream(message, &full_stream));
+
+    std::string full_output = full_stream.str();
+    ASSERT_GT(full_output.size(), size_t{2});
+    ASSERT_EQ(full_output[0], 4);
+
+    partial_stream << full_output[0] << full_output[1] << full_output[2];
+  }
+
+  {
+    bool clean_eof;
+    io::IstreamInputStream zstream(&partial_stream);
+
+    protobuf_unittest::ForeignMessage message;
+    clean_eof = true;
+    EXPECT_FALSE(ParseDelimitedFromZeroCopyStream(&message,
+        &zstream, &clean_eof));
+    EXPECT_FALSE(clean_eof);
+  }
+}
+
 }  // namespace util
 }  // namespace protobuf
 }  // namespace google
diff --git a/third_party/zlib/google/zip_reader.cc b/third_party/zlib/google/zip_reader.cc
index 8b4bb4a..96e9ff0 100644
--- a/third_party/zlib/google/zip_reader.cc
+++ b/third_party/zlib/google/zip_reader.cc
@@ -10,10 +10,9 @@
 #include "base/files/file.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "build/build_config.h"
 #include "third_party/zlib/google/zip_internal.h"
 
@@ -296,11 +295,11 @@
   // If this is a directory, just create it and return.
   if (current_entry_info()->is_directory()) {
     if (base::CreateDirectory(output_file_path)) {
-      base::ThreadTaskRunnerHandle::Get()->PostTask(
+      base::SequencedTaskRunnerHandle::Get()->PostTask(
           FROM_HERE, std::move(success_callback));
     } else {
       DVLOG(1) << "Unzip failed: unable to create directory.";
-      base::ThreadTaskRunnerHandle::Get()->PostTask(
+      base::SequencedTaskRunnerHandle::Get()->PostTask(
           FROM_HERE, std::move(failure_callback));
     }
     return;
@@ -308,16 +307,16 @@
 
   if (unzOpenCurrentFile(zip_file_) != UNZ_OK) {
     DVLOG(1) << "Unzip failed: unable to open current zip entry.";
-    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
-                                                  std::move(failure_callback));
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, std::move(failure_callback));
     return;
   }
 
   base::FilePath output_dir_path = output_file_path.DirName();
   if (!base::CreateDirectory(output_dir_path)) {
     DVLOG(1) << "Unzip failed: unable to create containing directory.";
-    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
-                                                  std::move(failure_callback));
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, std::move(failure_callback));
     return;
   }
 
@@ -327,12 +326,12 @@
   if (!output_file.IsValid()) {
     DVLOG(1) << "Unzip failed: unable to create platform file at "
              << output_file_path.value();
-    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
-                                                  std::move(failure_callback));
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, std::move(failure_callback));
     return;
   }
 
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(&ZipReader::ExtractChunk, weak_ptr_factory_.GetWeakPtr(),
                      Passed(std::move(output_file)),
@@ -434,7 +433,7 @@
 
     progress_callback.Run(current_progress);
 
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::BindOnce(&ZipReader::ExtractChunk, weak_ptr_factory_.GetWeakPtr(),
                        Passed(std::move(output_file)),
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index d810b8e..f6cc4305 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -3446,6 +3446,13 @@
   <int value="9" label="Timeout"/>
 </enum>
 
+<enum name="ArcProvisioningCheckInError">
+  <summary>Defines ARC GMS check-in failure reasons</summary>
+  <int value="1" label="Check-in failed"/>
+  <int value="2" label="Timeout"/>
+  <int value="3" label="Internal error"/>
+</enum>
+
 <!-- These values must be in sync with ProvisionConstants in CloudDPC code -->
 
 <enum name="ArcProvisioningCloudFlowError">
@@ -3487,6 +3494,9 @@
 </enum>
 
 <enum name="ArcProvisioningResult">
+  <obsolete>
+    Removed in Dec 2020. Replaced by ArcProvisioningStatus.
+  </obsolete>
   <summary>Defines Arc Provisioning success and failure reasons</summary>
   <int value="0" label="Success"/>
   <int value="1" label="Unclassified failure"/>
@@ -3515,6 +3525,34 @@
   <int value="24" label="Cloud provision flow failed"/>
 </enum>
 
+<enum name="ArcProvisioningSignInError">
+  <summary>Defines ARC GMS sign-in failure reasons</summary>
+  <int value="1" label="Network error"/>
+  <int value="2" label="Sign-in service unavailble"/>
+  <int value="3" label="Bad authentication"/>
+  <int value="4" label="Unknown error"/>
+  <int value="5" label="Timeout"/>
+  <int value="6" label="Internal error"/>
+</enum>
+
+<enum name="ArcProvisioningStatus">
+  <summary>Defines ARC GMS check-in failure reasons</summary>
+  <int value="0" label="Success"/>
+  <int value="1" label="Unclassified failure"/>
+  <int value="2" label="GMS sign-in failed"/>
+  <int value="3" label="GMS check-in failed"/>
+  <int value="4" label="Cloud provision flow failed"/>
+  <int value="5" label="Mojo version mistmached"/>
+  <int value="6" label="ARC provisioning timeout"/>
+  <int value="7" label="Chrome provisioning timeout"/>
+  <int value="8" label="ARC instance is stopped before complete provisioning"/>
+  <int value="9" label="Disabled"/>
+  <int value="10" label="Chrome server communication error"/>
+  <int value="11" label="Network is unavailable"/>
+  <int value="12" label="Unsupported account type"/>
+  <int value="13" label="Account is not present in Chrome"/>
+</enum>
+
 <enum name="ArcSdkVersionUpgradeType">
   <summary>Defines the types of ARC SDK version upgrade</summary>
   <int value="0" label="NO_UPGRADE"/>
@@ -16883,6 +16921,7 @@
   <int value="2" label="Status Bar Issues Counter"/>
   <int value="3" label="Hamburger Menu"/>
   <int value="4" label="Adorner"/>
+  <int value="5" label="Command Menu"/>
 </enum>
 
 <enum name="DevToolsIssuesPanelResourceOpened">
@@ -30425,6 +30464,8 @@
   <int value="3738" label="CrossOriginJsonTypeForScript"/>
   <int value="3739" label="SameOriginStrictNosniffWouldBlock"/>
   <int value="3740" label="CrossOriginStrictNosniffWouldBlock"/>
+  <int value="3741" label="CSSSelectorPseudoDir"/>
+  <int value="3742" label="CrossOriginSubframeWithoutEmbeddingControl"/>
 </enum>
 
 <enum name="FeaturePolicyAllowlistType">
@@ -45333,6 +45374,7 @@
   <int value="1343516821" label="ignore-previews-blocklist"/>
   <int value="1343713259" label="ArcPrintSpoolerExperiment:disabled"/>
   <int value="1344833841" label="ImeThread:enabled"/>
+  <int value="1345192233" label="VaapiVideoDecoder:enabled"/>
   <int value="1346994602" label="SyncPseudoUSSDictionary:enabled"/>
   <int value="1349100152"
       label="AutofillEnablePasswordInfoBarAccountIndicationFooter:disabled"/>
@@ -45357,6 +45399,7 @@
   <int value="1361073386" label="ContentSuggestionsNotifications:enabled"/>
   <int value="1363136936" label="VrCustomTabBrowsing:enabled"/>
   <int value="1363151585" label="SyncPseudoUSSAppList:enabled"/>
+  <int value="1367406392" label="VaapiVideoDecoder:disabled"/>
   <int value="1367467733" label="AutoplayIgnoreWebAudio:enabled"/>
   <int value="1367487214" label="VaapiJpegImageDecodeAcceleration:enabled"/>
   <int value="1367529437" label="NTPAssetDownloadSuggestions:enabled"/>
@@ -50379,6 +50422,13 @@
   <int value="8" label="Unsupported attachment type"/>
 </enum>
 
+<enum name="NearbyShareVisibility">
+  <int value="0" label="Unknown"/>
+  <int value="1" label="No one"/>
+  <int value="2" label="All contacts"/>
+  <int value="3" label="Selected contacts"/>
+</enum>
+
 <enum name="NearOomDetectionEndReason">
   <obsolete>
     Removed in Feb 2020.
diff --git a/tools/metrics/histograms/histograms_xml/android/histograms.xml b/tools/metrics/histograms/histograms_xml/android/histograms.xml
index 60002d6..6e407c0 100644
--- a/tools/metrics/histograms/histograms_xml/android/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/android/histograms.xml
@@ -2432,7 +2432,7 @@
 </histogram>
 
 <histogram name="Android.WebView.Gfx.HardwareDrawType"
-    enum="WebViewDrawAndSubmissionType" expires_after="2020-12-15">
+    enum="WebViewDrawAndSubmissionType" expires_after="2021-06-15">
   <owner>vasilyt@chromium.org</owner>
   <owner>boliu@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/arc/histograms.xml b/tools/metrics/histograms/histograms_xml/arc/histograms.xml
index 076f8a03..d3a32b4 100644
--- a/tools/metrics/histograms/histograms_xml/arc/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/arc/histograms.xml
@@ -864,8 +864,20 @@
   <summary>Time taken for ARC to render a PDF for print preview.</summary>
 </histogram>
 
+<histogram base="true" name="Arc.Provisioning.CheckInError"
+    enum="ArcProvisioningCheckInError" expires_after="2021-12-01">
+<!-- Name completed by histogram_suffixes name="ArcUserTypes" -->
+
+  <owner>mhasank@google.com</owner>
+  <owner>arc-core@google.com</owner>
+  <summary>
+    The error that occurred during GMS check-in operation. Recorded when ARC++
+    provisioning flow fails.
+  </summary>
+</histogram>
+
 <histogram base="true" name="Arc.Provisioning.CloudFlowError"
-    enum="ArcProvisioningCloudFlowError" expires_after="2021-07-01">
+    enum="ArcProvisioningCloudFlowError" expires_after="2021-12-01">
 <!-- Name completed by histogram_suffixes name="ArcUserTypes" -->
 
   <owner>mhasank@google.com</owner>
@@ -878,6 +890,9 @@
 
 <histogram base="true" name="Arc.Provisioning.Result"
     enum="ArcProvisioningResult" expires_after="2021-07-01">
+  <obsolete>
+    Removed in Dec 2020. Now reported as Arc.Provisioning.Status.
+  </obsolete>
 <!-- Name completed by histogram_suffixes name="ArcUserTypes" -->
 
   <owner>alexchau@google.com</owner>
@@ -888,6 +903,27 @@
   </summary>
 </histogram>
 
+<histogram base="true" name="Arc.Provisioning.SignInError"
+    enum="ArcProvisioningSignInError" expires_after="2021-12-01">
+<!-- Name completed by histogram_suffixes name="ArcUserTypes" -->
+
+  <owner>mhasank@google.com</owner>
+  <owner>arc-core@google.com</owner>
+  <summary>
+    The error that occured during GMS sign-in operation. Recorded when ARC++
+    provisioning flow fails.
+  </summary>
+</histogram>
+
+<histogram base="true" name="Arc.Provisioning.Status"
+    enum="ArcProvisioningStatus" expires_after="2021-12-01">
+<!-- Name completed by histogram_suffixes name="ArcUserTypes" -->
+
+  <owner>mhasank@google.com</owner>
+  <owner>arc-core@google.com</owner>
+  <summary>The status (success or error) of ARC++ provisioning.</summary>
+</histogram>
+
 <histogram name="Arc.Provisioning.TimeDelta.Failure" units="ms"
     expires_after="2021-05-02">
 <!-- Name completed by histogram_suffixes name="ArcUserTypes" -->
@@ -911,11 +947,12 @@
   </summary>
 </histogram>
 
-<histogram name="Arc.Reauthorization.Result" enum="ArcProvisioningResult"
+<histogram name="Arc.Reauthorization.Result" enum="ArcProvisioningStatus"
     expires_after="2021-02-07">
 <!-- Name completed by histogram_suffixes name="ArcUserTypes" -->
 
   <owner>khmel@google.com</owner>
+  <owner>arc-core@gmail.com</owner>
   <summary>
     The result (success or the type of failure) of ARC reauthorization.
   </summary>
@@ -978,7 +1015,7 @@
   </summary>
 </histogram>
 
-<histogram name="Arc.Secondary.Signin.Result" enum="ArcProvisioningResult"
+<histogram name="Arc.Secondary.Signin.Result" enum="ArcProvisioningStatus"
     expires_after="2021-05-16">
   <owner>sinhak@google.com</owner>
   <owner>jhorwich@google.com</owner>
diff --git a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
index ea1d9d9..cde6379 100644
--- a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
+++ b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
@@ -1023,8 +1023,11 @@
   <affected-histogram name="Arc.PlayAutoInstallRequest.State"/>
   <affected-histogram name="Arc.PlayAutoInstallRequest.TimeDelta"/>
   <affected-histogram name="Arc.PlayStoreShown.TimeDelta"/>
+  <affected-histogram name="Arc.Provisioning.CheckInError"/>
   <affected-histogram name="Arc.Provisioning.CloudFlowError"/>
   <affected-histogram name="Arc.Provisioning.Result"/>
+  <affected-histogram name="Arc.Provisioning.SignInError"/>
+  <affected-histogram name="Arc.Provisioning.Status"/>
   <affected-histogram name="Arc.Provisioning.TimeDelta.Failure"/>
   <affected-histogram name="Arc.Provisioning.TimeDelta.Success"/>
   <affected-histogram name="Arc.Reauthorization.Result"/>
diff --git a/tools/metrics/histograms/histograms_xml/others/histograms.xml b/tools/metrics/histograms/histograms_xml/others/histograms.xml
index 06b3dc03..af8b247 100644
--- a/tools/metrics/histograms/histograms_xml/others/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/others/histograms.xml
@@ -9984,6 +9984,17 @@
   </token>
 </histogram>
 
+<histogram name="Nearby.Share.VisibilityChoice" enum="NearbyShareVisibility"
+    expires_after="2021-08-19">
+  <owner>nohle@chromium.org</owner>
+  <owner>better-together-dev@google.com</owner>
+  <summary>
+    Records the user's chosen degree of visibility to their contacts, selected
+    during onboarding or updated in settings. Emitted at login for users that
+    have Nearby Share enabled.
+  </summary>
+</histogram>
+
 <histogram name="net.HttpIdentSrcURL" units="requests" expires_after="M85">
   <owner>tsepez@chromium.org</owner>
   <summary>
@@ -11674,17 +11685,21 @@
 </histogram>
 
 <histogram name="Privacy.CookieControlsSetting" enum="CookieControlsMode"
-    expires_after="M89">
+    expires_after="never">
+<!-- expires-never: tracked as an important privacy metric. -->
+
   <owner>dullweber@chromium.org</owner>
   <owner>huanzhong@chromium.org</owner>
   <summary>
-    Whether the cookie controls setting is enabled. Recorded at the Profile
-    startup.
+    Whether third-party cookies are blocked in incognito mode or completely.
+    Recorded at the Profile startup.
   </summary>
 </histogram>
 
 <histogram name="Privacy.DoNotTrackSetting" enum="BooleanEnabled"
-    expires_after="2021-05-16">
+    expires_after="never">
+<!-- expires-never: tracked as an important privacy metric. -->
+
   <owner>mkwst@chromium.org</owner>
   <owner>msramek@chromium.org</owner>
   <summary>
@@ -11694,7 +11709,7 @@
 </histogram>
 
 <histogram name="Privacy.ThirdPartyCookieBlockingEnabledForSite" enum="Boolean"
-    expires_after="M89">
+    expires_after="M93">
   <owner>dullweber@chromium.org</owner>
   <owner>huanzhong@chromium.org</owner>
   <summary>
@@ -17708,7 +17723,7 @@
 </histogram>
 
 <histogram name="WebsiteSettings.Action" enum="WebsiteSettingsAction"
-    expires_after="M90">
+    expires_after="M93">
   <owner>estark@chromium.org</owner>
   <owner>dullweber@chromium.org</owner>
   <summary>
diff --git a/tools/privacy_budget/blink_apis/BUILD.gn b/tools/privacy_budget/blink_apis/BUILD.gn
index 4da17c0..5fba75b 100644
--- a/tools/privacy_budget/blink_apis/BUILD.gn
+++ b/tools/privacy_budget/blink_apis/BUILD.gn
@@ -20,7 +20,8 @@
   inputs = [
     web_idl_database_filepath,
     "blink_api_proto.py",
-    "generate_blink_api_db.py"
+    "generate_blink_api_db.py",
+    "web_feature.py",
   ]
   output_data_file = "${root_build_dir}/blink_apis.textpb"
   outputs = [ output_data_file ]
@@ -30,6 +31,10 @@
     rebase_path(web_idl_database_filepath, root_build_dir),
     "--output",
     rebase_path(output_data_file, root_build_dir),
+    "--web_feature_mojom",
+    rebase_path(
+        "//third_party/blink/public/mojom/web_feature/web_feature.mojom",
+        root_build_dir),
     "--path",
     string_join(":",
                 [
diff --git a/tools/privacy_budget/blink_apis/blink_api_proto.py b/tools/privacy_budget/blink_apis/blink_api_proto.py
index 6830e93..e3ed7060 100644
--- a/tools/privacy_budget/blink_apis/blink_api_proto.py
+++ b/tools/privacy_budget/blink_apis/blink_api_proto.py
@@ -14,10 +14,13 @@
     """BlinkApiProto converts a WebIdlDatabase to
     a identifiability.blink_apis.Snapshot proto defined in
     proto/blink_apis.proto"""
-    def __init__(self, web_idl_pickle, proto_out_file, chromium_revision):
+
+    def __init__(self, web_idl_pickle, proto_out_file, chromium_revision,
+                 web_features):
         self.web_idl_database = web_idl.Database.read_from_file(web_idl_pickle)
         self.proto_out_file = proto_out_file
         self.snapshot = pb.Snapshot()
+        self.web_features = web_features
         if chromium_revision:
             self.snapshot.chromium_revision = chromium_revision
 
@@ -41,7 +44,7 @@
 
         for function in self.web_idl_database.callback_functions:
             self._ConvertIdlOperation(self.snapshot.callback_functions.add(),
-                                      function)
+                                      function, None)
 
         for interface in self.web_idl_database.callback_interfaces:
             self._ConvertIdlInterfaceLike(
@@ -64,22 +67,43 @@
             return pb.HIGH_ENTROPY_DIRECT
         assert False, "Unknown HighEntropy value {}".format(val)
 
-    def _GetUseCounter(self, parent, measure, measure_as):
-        if measure_as:
-            return measure_as.value
-        if measure:
-            use_counter = capitalize(parent.identifier)
-            if not isinstance(parent, web_idl.Interface):
-                use_counter = (capitalize(parent.owner.identifier) + '_' +
-                               use_counter)
-            return use_counter
-        return None
+    def _GetUseCounter(self, member, parent, ext_attrs):
+        assert isinstance(ext_attrs, web_idl.ExtendedAttributes)
+        assert parent is None or hasattr(parent, 'identifier')
+
+        if 'MeasureAs' in ext_attrs:
+            return ext_attrs.value_of('MeasureAs')
+
+        if 'Measure' not in ext_attrs:
+            return None
+
+        if parent is not None:
+            prefix = '%s_%s' % (capitalize(
+                parent.identifier), capitalize(member.identifier))
+        else:
+            prefix = capitalize(member.identifier)
+
+        suffix = ""
+        if isinstance(member, web_idl.FunctionLike):
+            if len(member.arguments) == 0 and member.is_getter:
+                suffix = "AttributeGetter"
+            elif len(member.arguments) == 1 and member.is_setter:
+                suffix = "AttributeSetter"
+            else:
+                suffix = "Method"
+        elif isinstance(member, web_idl.Attribute):
+            suffix = "AttributeGetter"
+        else:
+            assert False, repr(member)
+
+        return "V8" + prefix + "_" + suffix
 
     def _ConvertIdlType(self, dest, idl_type):
         assert isinstance(idl_type, web_idl.IdlType)
 
         dest.idl_type_string = idl_type.type_name_without_extended_attributes
-        self._ConvertExtendedAttributes(dest.extended_attributes, idl_type)
+        self._ConvertExtendedAttributes(dest.extended_attributes, idl_type,
+                                        None)
 
         # Only look at named definitions. Simple, primitive types don't define
         # named identifiers.
@@ -96,8 +120,8 @@
         depends_on.remove(idl_type.type_name_without_extended_attributes)
         dest.depends_on[:] = list(depends_on)
 
-    def _ConvertExtendedAttributes(self, dest, parent):
-        attr = parent.extended_attributes
+    def _ConvertExtendedAttributes(self, dest, member, interface):
+        attr = member.extended_attributes
         assert isinstance(attr, web_idl.ExtendedAttributes)
         dest.cross_origin_isolated = ('CrossOriginIsolated' in attr)
         if 'Exposed' in attr:
@@ -111,25 +135,27 @@
                 for v in exposed.values:
                     e = dest.exposed.add()
                     e.interface = v
-                    e.member = parent.identifier
+                    e.member = member.identifier
 
         setattr(dest, 'global', ('Global' in attr))
         dest.same_object = ('SameObject' in attr)
         dest.secure_context = ('SecureContext' in attr)
         dest.high_entropy = self._GetHighEntropyType(attr.get('HighEntropy'))
         if 'Measure' in attr or 'MeasureAs' in attr:
-            dest.use_counter = self._GetUseCounter(parent, attr.get('Measure'),
-                                                   attr.get('MeasureAs'))
+            dest.use_counter = self._GetUseCounter(member, interface, attr)
+            dest.use_counter_feature_value = self.web_features[
+                dest.use_counter]
         if 'RuntimeEnabled' in attr:
             dest.runtime_enabled = attr.value_of('RuntimeEnabled')
         if 'ImplementedAs' in attr:
             dest.implemented_as = attr.value_of('ImplementedAs')
 
-    def _ConvertIdlAttribute(self, dest, attr):
+    def _ConvertIdlAttribute(self, dest, attr, interface):
         dest.name = attr.identifier
         dest.is_static = attr.is_static
         dest.is_readonly = attr.is_readonly
-        self._ConvertExtendedAttributes(dest.extended_attributes, attr)
+        self._ConvertExtendedAttributes(dest.extended_attributes, attr,
+                                        interface)
         self._ConvertIdlType(dest.idl_type, attr.idl_type)
         self._ConvertSourceLocation(dest.source_location, attr.debug_info)
 
@@ -144,12 +170,13 @@
             return pb.SPECIAL_OP_STRINGIFIER
         return pb.SPECIAL_OP_UNSPECIFIED
 
-    def _ConvertIdlOperation(self, dest, op):
+    def _ConvertIdlOperation(self, dest, op, parent):
         dest.name = op.identifier
         dest.static = op.is_static
         dest.special_op_type = self._GetSpecialOperationType(op)
         self._ConvertIdlType(dest.return_type, op.return_type)
         self._ConvertSourceLocation(dest.source_location, op.debug_info)
+        self._ConvertExtendedAttributes(dest.extended_attributes, op, parent)
         for arg in op.arguments:
             self._ConvertIdlType(dest.arguments.add(), arg.idl_type)
 
@@ -158,30 +185,32 @@
         dest.values[:] = enumer.values
         self._ConvertSourceLocation(dest.source_location, enumer.debug_info)
 
-    def _ConvertIdlConstant(self, dest, constant):
+    def _ConvertIdlConstant(self, dest, constant, parent):
         dest.name = constant.identifier
         dest.value = constant.value.literal
-        self._ConvertExtendedAttributes(dest.extended_attributes, constant)
+        self._ConvertExtendedAttributes(dest.extended_attributes, constant,
+                                        parent)
         self._ConvertIdlType(dest.idl_type, constant.idl_type)
         self._ConvertSourceLocation(dest.source_location, constant.debug_info)
 
-    def _ConvertIdlInterfaceLike(self, dest, interface):
-        dest.name = interface.identifier
-        if hasattr(interface, 'inherited') and interface.inherited:
-            dest.inherits_from = interface.inherited.identifier
-        self._ConvertExtendedAttributes(dest.extended_attributes, interface)
-        self._ConvertSourceLocation(dest.source_location, interface.debug_info)
-        for attr in interface.attributes:
-            self._ConvertIdlAttribute(dest.attributes.add(), attr)
-        for op in interface.operations:
-            self._ConvertIdlOperation(dest.operations.add(), op)
-        for constant in interface.constants:
-            self._ConvertIdlConstant(dest.constants.add(), constant)
+    def _ConvertIdlInterfaceLike(self, dest, parent):
+        dest.name = parent.identifier
+        if hasattr(parent, 'inherited') and parent.inherited:
+            dest.inherits_from = parent.inherited.identifier
+        self._ConvertExtendedAttributes(dest.extended_attributes, parent, None)
+        self._ConvertSourceLocation(dest.source_location, parent.debug_info)
+        for attr in parent.attributes:
+            self._ConvertIdlAttribute(dest.attributes.add(), attr, parent)
+        for op in parent.operations:
+            self._ConvertIdlOperation(dest.operations.add(), op, parent)
+        for constant in parent.constants:
+            self._ConvertIdlConstant(dest.constants.add(), constant, parent)
 
-    def _ConvertDictionaryMember(self, dest, member):
+    def _ConvertDictionaryMember(self, dest, member, interface):
         assert isinstance(member, web_idl.DictionaryMember)
         dest.name = member.identifier
-        self._ConvertExtendedAttributes(dest.extended_attributes, member)
+        self._ConvertExtendedAttributes(dest.extended_attributes, member,
+                                        interface)
         self._ConvertIdlType(dest.idl_type, member.idl_type)
         self._ConvertSourceLocation(dest.source_location, member.debug_info)
 
@@ -193,7 +222,8 @@
         if dictionary.inherited:
             dest.inherits_from = dictionary.inherited.identifier
         for member in dictionary.members:
-            self._ConvertDictionaryMember(dest.members.add(), member)
+            self._ConvertDictionaryMember(dest.members.add(), member,
+                                          dictionary)
 
     def _ConvertIdlTypedef(self, dest, typedef):
         assert isinstance(typedef, web_idl.Typedef)
@@ -217,4 +247,5 @@
 
         if source_file:
             dest.filename = source_file
+
             dest.line = line_no
diff --git a/tools/privacy_budget/blink_apis/generate_blink_api_db.py b/tools/privacy_budget/blink_apis/generate_blink_api_db.py
index 0a8d3de..98a25a59 100755
--- a/tools/privacy_budget/blink_apis/generate_blink_api_db.py
+++ b/tools/privacy_budget/blink_apis/generate_blink_api_db.py
@@ -17,7 +17,6 @@
 # >
 #
 # [VPYTHON:END]
-
 """
 Generate a database of Blink APIs.
 
@@ -51,39 +50,44 @@
 
 
 def parse_options():
-  parser = argparse.ArgumentParser(description="%prog [options]")
-  parser.add_argument("--web_idl_database",
-                      type=str,
-                      help="filepath of the input database")
-  parser.add_argument("--output", type=str, help="filepath of output file")
-  parser.add_argument("--path", type=str, help="Additions to sys.path")
-  parser.add_argument(
-      "--chromium_revision",
-      type=str,
-      help="Chromium revision (git hash) for the source of Blink WebIDL DB")
-  args = parser.parse_args()
+    parser = argparse.ArgumentParser(description="%prog [options]")
+    parser.add_argument("--web_idl_database",
+                        type=str,
+                        help="filepath of the input database")
+    parser.add_argument("--web_feature_mojom",
+                        type=str,
+                        help="path of web_feature.mojom")
+    parser.add_argument("--output", type=str, help="filepath of output file")
+    parser.add_argument("--path", type=str, help="Additions to sys.path")
+    parser.add_argument(
+        "--chromium_revision",
+        type=str,
+        help="Chromium revision (git hash) for the source of Blink WebIDL DB")
+    args = parser.parse_args()
 
-  required_option_names = ("web_idl_database", "output")
-  for opt_name in required_option_names:
-    if getattr(args, opt_name) is None:
-      parser.error("--{} is a required option.".format(opt_name))
+    required_option_names = ("web_idl_database", "output", "web_feature_mojom")
+    for opt_name in required_option_names:
+        if getattr(args, opt_name) is None:
+            parser.error("--{} is a required option.".format(opt_name))
 
-  if args.path:
-    for p in args.path.split(':'):
-      sys.path.append(p)
+    if args.path:
+        for p in args.path.split(':'):
+            sys.path.append(p)
 
-  return args
+    return args
 
 
 def main():
-  args = parse_options()
+    args = parse_options()
 
-  from blink_api_proto import BlinkApiProto
-  p = BlinkApiProto(args.web_idl_database, args.output,
-                    args.chromium_revision)
-  p.Parse()
-  p.WriteTo(args.output)
+    from blink_api_proto import BlinkApiProto
+    from web_feature import WebFeature
+    w = WebFeature(args.web_feature_mojom)
+    p = BlinkApiProto(args.web_idl_database, args.output,
+                      args.chromium_revision, w)
+    p.Parse()
+    p.WriteTo(args.output)
 
 
 if __name__ == '__main__':
-  main()
+    main()
diff --git a/tools/privacy_budget/blink_apis/proto/blink_apis.proto b/tools/privacy_budget/blink_apis/proto/blink_apis.proto
index 87272e5..cba0a51 100644
--- a/tools/privacy_budget/blink_apis/proto/blink_apis.proto
+++ b/tools/privacy_budget/blink_apis/proto/blink_apis.proto
@@ -40,6 +40,7 @@
 //
 // The latter are described in:
 // https://chromium.googlesource.com/chromium/src/+/master/third_party/blink/renderer/bindings/IDLExtendedAttributes.md
+// Next ID: 13
 message ExtendedAttributes {
   // https://heycam.github.io/webidl/#CrossOriginIsolated
   bool cross_origin_isolated = 1;
@@ -74,6 +75,9 @@
   // https://chromium.googlesource.com/chromium/src/+/master/third_party/blink/renderer/bindings/IDLExtendedAttributes.md#measure_i_m_a_c
   string use_counter = 7;
 
+  // The numeric value of the Use Counter feature constant.
+  int64 use_counter_feature_value = 12;
+
   // Value of [RuntimeEnabled]
   // https://chromium.googlesource.com/chromium/src/+/master/third_party/blink/renderer/bindings/IDLExtendedAttributes.md#runtimeenabled_i_m_a_c
   // Empty or undefined string is equivalent to there not being
diff --git a/tools/privacy_budget/blink_apis/web_feature.py b/tools/privacy_budget/blink_apis/web_feature.py
new file mode 100644
index 0000000..249a5ec6
--- /dev/null
+++ b/tools/privacy_budget/blink_apis/web_feature.py
@@ -0,0 +1,29 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import re
+
+
+class WebFeature(object):
+    def __init__(self, web_feature_path):
+        assert os.path.isfile(
+            web_feature_path), "%s not found" % (web_feature_path)
+
+        const_def = re.compile(r'\s*k(\w*)\s*=\s*(\d*)\s*,.*')
+
+        self.features = {}
+
+        with open(web_feature_path, 'r') as f:
+            for line in f.readlines():
+                match = const_def.match(line)
+                if match:
+                    self.features[match.group(1)] = int(match.group(2))
+
+    def __contains__(self, val):
+        return val in self.features
+
+    def __getitem__(self, val):
+        assert val in self, "%s not in mojom" % (val)
+        return self.features[val]
diff --git a/ui/chromeos/file_manager_strings.grdp b/ui/chromeos/file_manager_strings.grdp
index e1770b7..e2badd0 100644
--- a/ui/chromeos/file_manager_strings.grdp
+++ b/ui/chromeos/file_manager_strings.grdp
@@ -871,6 +871,15 @@
   <message name="IDS_FILE_BROWSER_DELETE_ERROR" desc="Message informing about error while deleting an item or items.">
     An error occurred. Some items may not have been deleted.
   </message>
+  <message name="IDS_FILE_BROWSER_RESTORE_FROM_TRASH_FILE_NAME" desc="File Manager status message shown when restoring items from trash / recycle bin.">
+    Restoring "<ph name="FILENAME">$1<ex>photo.jpg</ex></ph>"...
+  </message>
+  <message name="IDS_FILE_BROWSER_RESTORE_FROM_TRASH_ITEMS_REMAINING" desc="File Manager status message shown when restoring items from trash / recycle bin. 'Item' is used here as a generic term for file or directory.">
+    Restoring <ph name="COUNT">$1<ex>10</ex></ph> items...
+  </message>
+  <message name="IDS_FILE_BROWSER_RESTORE_FROM_TRASH_ERROR" desc="Message informing about error while restoring an item or items from the trash / recycle bin.">
+    An error occurred. Some items may not have been restored.
+  </message>
 
   <message name="IDS_FILE_BROWSER_COPY_PROGRESS_SUMMARY" desc="Summary message for multiple copying tasks above the progress bar.">
     Copying...
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_RESTORE_FROM_TRASH_ERROR.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_RESTORE_FROM_TRASH_ERROR.png.sha1
new file mode 100644
index 0000000..89c54252
--- /dev/null
+++ b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_RESTORE_FROM_TRASH_ERROR.png.sha1
@@ -0,0 +1 @@
+42de77dc9621353c359adc8c7680cfdc3779fe02
\ No newline at end of file
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_RESTORE_FROM_TRASH_FILE_NAME.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_RESTORE_FROM_TRASH_FILE_NAME.png.sha1
new file mode 100644
index 0000000..ce408ad
--- /dev/null
+++ b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_RESTORE_FROM_TRASH_FILE_NAME.png.sha1
@@ -0,0 +1 @@
+c2db6f361fb7903ba2bc4a6358ca6789d637bfd6
\ No newline at end of file
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_RESTORE_FROM_TRASH_ITEMS_REMAINING.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_RESTORE_FROM_TRASH_ITEMS_REMAINING.png.sha1
new file mode 100644
index 0000000..60ff5838
--- /dev/null
+++ b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_RESTORE_FROM_TRASH_ITEMS_REMAINING.png.sha1
@@ -0,0 +1 @@
+783c32c08aa357b08961501189b7258e54aa3406
\ No newline at end of file
diff --git a/ui/compositor/BUILD.gn b/ui/compositor/BUILD.gn
index bc03547..9383a56 100644
--- a/ui/compositor/BUILD.gn
+++ b/ui/compositor/BUILD.gn
@@ -69,8 +69,6 @@
     "throughput_tracker.cc",
     "throughput_tracker.h",
     "throughput_tracker_host.h",
-    "total_animation_throughput_reporter.cc",
-    "total_animation_throughput_reporter.h",
     "transform_animation_curve_adapter.cc",
     "transform_animation_curve_adapter.h",
     "transform_recorder.cc",
@@ -240,7 +238,6 @@
     "layer_owner_unittest.cc",
     "layer_unittest.cc",
     "run_all_unittests.cc",
-    "total_animation_throughput_reporter_unittest.cc",
     "transform_animation_curve_adapter_unittest.cc",
   ]
 
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc
index d0ffe90..07c2a39 100644
--- a/ui/compositor/compositor.cc
+++ b/ui/compositor/compositor.cc
@@ -576,23 +576,13 @@
 }
 
 void Compositor::AddAnimationObserver(CompositorAnimationObserver* observer) {
-  if (!animation_observer_list_.has_observers()) {
-    for (auto& obs : observer_list_)
-      obs.OnFirstAnimationStarted(this);
-  }
   animation_observer_list_.AddObserver(observer);
   host_->SetNeedsAnimate();
 }
 
 void Compositor::RemoveAnimationObserver(
     CompositorAnimationObserver* observer) {
-  if (!animation_observer_list_.HasObserver(observer))
-    return;
   animation_observer_list_.RemoveObserver(observer);
-  if (!animation_observer_list_.has_observers()) {
-    for (auto& obs : observer_list_)
-      obs.OnLastAnimationEnded(this);
-  }
 }
 
 bool Compositor::HasAnimationObserver(
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h
index f9bf9e1..bb08a017 100644
--- a/ui/compositor/compositor.h
+++ b/ui/compositor/compositor.h
@@ -409,7 +409,6 @@
 
  private:
   friend class base::RefCounted<Compositor>;
-  friend class TotalAnimationThroughputReporter;
 
   // Called when collected metrics for the tracker of |tracker_id| is ready.
   void ReportMetricsForTracker(
diff --git a/ui/compositor/compositor_observer.h b/ui/compositor/compositor_observer.h
index a14b75b5..32c6e49 100644
--- a/ui/compositor/compositor_observer.h
+++ b/ui/compositor/compositor_observer.h
@@ -60,9 +60,6 @@
   virtual void OnDidPresentCompositorFrame(
       uint32_t frame_token,
       const gfx::PresentationFeedback& feedback) {}
-
-  virtual void OnFirstAnimationStarted(Compositor* compositor) {}
-  virtual void OnLastAnimationEnded(Compositor* compositor) {}
 };
 
 }  // namespace ui
diff --git a/ui/compositor/total_animation_throughput_reporter.cc b/ui/compositor/total_animation_throughput_reporter.cc
deleted file mode 100644
index 2d85c436..0000000
--- a/ui/compositor/total_animation_throughput_reporter.cc
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/compositor/total_animation_throughput_reporter.h"
-
-#include "base/logging.h"
-#include "ui/compositor/compositor.h"
-
-namespace ui {
-
-TotalAnimationThroughputReporter::TotalAnimationThroughputReporter(
-    ui::Compositor* compositor,
-    ReportOnceCallback once_callback,
-    bool should_delete)
-    : TotalAnimationThroughputReporter(compositor,
-                                       ReportRepeatingCallback(),
-                                       std::move(once_callback),
-                                       should_delete) {}
-
-TotalAnimationThroughputReporter::TotalAnimationThroughputReporter(
-    ui::Compositor* compositor,
-    ReportRepeatingCallback repeating_callback)
-    : TotalAnimationThroughputReporter(compositor,
-                                       repeating_callback,
-                                       ReportOnceCallback(),
-                                       /*should_delete=*/false) {}
-
-TotalAnimationThroughputReporter::~TotalAnimationThroughputReporter() {
-  if (throughput_tracker_)
-    throughput_tracker_->Cancel();
-  if (compositor_)
-    compositor_->RemoveObserver(this);
-}
-
-void TotalAnimationThroughputReporter::OnFirstAnimationStarted(
-    ui::Compositor* compositor) {
-  throughput_tracker_ = compositor->RequestNewThroughputTracker();
-  throughput_tracker_->Start(base::BindRepeating(
-      &TotalAnimationThroughputReporter::Report, ptr_factory_.GetWeakPtr()));
-}
-
-void TotalAnimationThroughputReporter::OnLastAnimationEnded(
-    ui::Compositor* compositor) {
-  throughput_tracker_->Stop();
-  throughput_tracker_.reset();
-}
-
-void TotalAnimationThroughputReporter::OnCompositingShuttingDown(
-    ui::Compositor* compositor) {
-  if (throughput_tracker_) {
-    throughput_tracker_->Cancel();
-    throughput_tracker_.reset();
-  }
-  compositor->RemoveObserver(this);
-  compositor_ = nullptr;
-  if (should_delete_)
-    delete this;
-}
-
-TotalAnimationThroughputReporter::TotalAnimationThroughputReporter(
-    ui::Compositor* compositor,
-    ReportRepeatingCallback repeating_callback,
-    ReportOnceCallback once_callback,
-    bool should_delete)
-    : compositor_(compositor),
-      report_repeating_callback_(repeating_callback),
-      report_once_callback_(std::move(once_callback)),
-      should_delete_(should_delete) {
-  DCHECK_NE(report_repeating_callback_.is_null(),
-            report_once_callback_.is_null());
-
-  compositor_->AddObserver(this);
-  if (compositor->animation_observer_list_.has_observers())
-    OnFirstAnimationStarted(compositor_);
-}
-
-void TotalAnimationThroughputReporter::Report(
-    const cc::FrameSequenceMetrics::CustomReportData& data) {
-  if (!report_once_callback_.is_null()) {
-    compositor_->RemoveObserver(this);
-    std::move(report_once_callback_).Run(data);
-    if (should_delete_)
-      delete this;
-    return;
-  }
-  if (!report_repeating_callback_.is_null())
-    report_repeating_callback_.Run(data);
-}
-
-}  // namespace ui
diff --git a/ui/compositor/total_animation_throughput_reporter.h b/ui/compositor/total_animation_throughput_reporter.h
deleted file mode 100644
index 6edc347..0000000
--- a/ui/compositor/total_animation_throughput_reporter.h
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_COMPOSITOR_TOTAL_ANIMATION_THROUGHPUT_REPORTER_H_
-#define UI_COMPOSITOR_TOTAL_ANIMATION_THROUGHPUT_REPORTER_H_
-
-#include <memory>
-
-#include "base/callback_forward.h"
-#include "base/memory/weak_ptr.h"
-#include "base/optional.h"
-#include "cc/metrics/frame_sequence_metrics.h"
-#include "ui/compositor/compositor_export.h"
-#include "ui/compositor/compositor_observer.h"
-#include "ui/compositor/throughput_tracker.h"
-
-namespace ui {
-
-// Reports cc::FrameSequenceMetrics::ThroughputData between the first animation
-// start and the last animation ends on a compositor.
-//
-// Please see AnimationThroughputReporter for the definition of the throughput
-// and jack metrics.
-//
-// See also docs/speed/graphics_metrics_definitions.md.
-//
-// cc::FrameSequenceMetrics::CustomReportData contains the numbers of produced
-// frames, expected frames and jank count.
-//
-// The tracking starts when the first animation observer is added to the
-// compositor, then stopped when the last animation observer is removed.  The
-// report callback is invoked on the next begin frame if there is enough data.
-// Since this observes multiple animations, aborting one of animations will
-// not cancel the tracking, and the data will be reported as normal.
-class COMPOSITOR_EXPORT TotalAnimationThroughputReporter
-    : public CompositorObserver {
- public:
-  using ReportOnceCallback = base::OnceCallback<void(
-      const cc::FrameSequenceMetrics::CustomReportData& data)>;
-  using ReportRepeatingCallback = base::RepeatingCallback<void(
-      const cc::FrameSequenceMetrics::CustomReportData& data)>;
-
-  // Create a TotalAnimationThroughputReporter that observes
-  // the total animation throughput just once. If |should_delete|
-  // is true, then the object will be deleted after callback is
-  // invoked.
-  TotalAnimationThroughputReporter(Compositor* compositor,
-                                   ReportOnceCallback callback,
-                                   bool should_delete);
-
-  // Create a persistent TotalAnimationThroughputReporter, which
-  // will call the callback every time the last animation is finished.
-  TotalAnimationThroughputReporter(Compositor* compositor,
-                                   ReportRepeatingCallback callback);
-
-  TotalAnimationThroughputReporter(const TotalAnimationThroughputReporter&) =
-      delete;
-  TotalAnimationThroughputReporter& operator=(
-      const TotalAnimationThroughputReporter&) = delete;
-  ~TotalAnimationThroughputReporter() override;
-
-  // CompositorObserver:
-  void OnFirstAnimationStarted(Compositor* compositor) override;
-  void OnLastAnimationEnded(Compositor* compositor) override;
-  void OnCompositingShuttingDown(Compositor* compositor) override;
-
-  bool IsMeasuringForTesting() const { return bool{throughput_tracker_}; }
-
- private:
-  TotalAnimationThroughputReporter(Compositor* compositor,
-                                   ReportRepeatingCallback repeating_callback,
-                                   ReportOnceCallback once_callback,
-                                   bool should_delete);
-
-  void Report(const cc::FrameSequenceMetrics::CustomReportData& data);
-
-  Compositor* compositor_;
-  ReportRepeatingCallback report_repeating_callback_;
-  ReportOnceCallback report_once_callback_;
-  bool should_delete_ = false;
-  base::Optional<ThroughputTracker> throughput_tracker_;
-
-  base::WeakPtrFactory<TotalAnimationThroughputReporter> ptr_factory_{this};
-};
-
-}  // namespace ui
-
-#endif  // UI_COMPOSITOR_TOTAL_ANIMATION_THROUGHPUT_REPORTER_H_
diff --git a/ui/compositor/total_animation_throughput_reporter_unittest.cc b/ui/compositor/total_animation_throughput_reporter_unittest.cc
deleted file mode 100644
index 9b61549..0000000
--- a/ui/compositor/total_animation_throughput_reporter_unittest.cc
+++ /dev/null
@@ -1,380 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/compositor/total_animation_throughput_reporter.h"
-
-#include <memory>
-
-#include "base/run_loop.h"
-#include "base/test/bind.h"
-#include "base/time/time.h"
-#include "build/build_config.h"
-#include "cc/metrics/frame_sequence_metrics.h"
-#include "ui/compositor/layer.h"
-#include "ui/compositor/layer_animation_sequence.h"
-#include "ui/compositor/layer_animator.h"
-#include "ui/compositor/scoped_layer_animation_settings.h"
-#include "ui/compositor/test/animation_throughput_reporter_test_base.h"
-#include "ui/gfx/geometry/rect.h"
-
-#if defined(OS_WIN)
-// TestCompositor doesn't work with MOCK_TIME on Windows. crbug.com/1152103
-#define MAYBE_SingleAnimation DISABLED_SingleAnimation
-#define MAYBE_StopAnimation DISABLED_StopAnimation
-#define MAYBE_MultipleAnimations DISABLED_MultipleAnimations
-#define MAYBE_MultipleAnimationsOnSingleLayer \
-  DISABLED_MultipleAnimationsOnSingleLayer
-#define MAYBE_AddAnimationWhileAnimating DISABLED_AddAnimationWhileAnimating
-#define MAYBE_RemoveWhileAnimating DISABLED_RemoveWhileAnimating
-#define MAYBE_StartWhileAnimating DISABLED_StartWhileAnimating
-#define MAYBE_PersistedAnimation DISABLED_PersistedAnimation
-#define MAYBE_OnceReporter DISABLED_OnceReporter
-#define MAYBE_OnceReporterShouldDelete DISABLED_OnceReporterShouldDelete
-#else
-#define MAYBE_SingleAnimation SingleAnimation
-#define MAYBE_StopAnimation StopAnimation
-#define MAYBE_MultipleAnimations MultipleAnimations
-#define MAYBE_MultipleAnimationsOnSingleLayer MultipleAnimationsOnSingleLayer
-#define MAYBE_AddAnimationWhileAnimating AddAnimationWhileAnimating
-#define MAYBE_RemoveWhileAnimating RemoveWhileAnimating
-#define MAYBE_StartWhileAnimating StartWhileAnimating
-#define MAYBE_PersistedAnimation PersistedAnimation
-#define MAYBE_OnceReporter OnceReporter
-#define MAYBE_OnceReporterShouldDelete OnceReporterShouldDelete
-#endif
-
-namespace ui {
-namespace {
-
-class TestReporter : public TotalAnimationThroughputReporter {
- public:
-  explicit TestReporter(ui::Compositor* compositor)
-      : ui::TotalAnimationThroughputReporter(
-            compositor,
-            base::BindRepeating(&TestReporter::Reported,
-                                base::Unretained(this))) {}
-  TestReporter(ui::Compositor* compositor, bool should_delete)
-      : ui::TotalAnimationThroughputReporter(
-            compositor,
-            base::BindOnce(&TestReporter::Reported, base::Unretained(this)),
-            should_delete) {}
-
-  TestReporter(const TestReporter&) = delete;
-  TestReporter& operator=(const TestReporter&) = delete;
-  ~TestReporter() override = default;
-
-  bool reported() const { return reported_; }
-
-  void reset() { reported_ = false; }
-
- private:
-  void Reported(const cc::FrameSequenceMetrics::CustomReportData&) {
-    reported_ = true;
-  }
-
-  bool reported_ = false;
-};
-
-}  // namespace
-
-using TotalAnimationThroughputReporterTest =
-    AnimationThroughputReporterTestBase;
-
-TEST_F(TotalAnimationThroughputReporterTest, MAYBE_SingleAnimation) {
-  Layer layer;
-  layer.SetOpacity(0.5f);
-  root_layer()->Add(&layer);
-
-  TestReporter reporter(compositor());
-  {
-    LayerAnimator* animator = layer.GetAnimator();
-
-    ScopedLayerAnimationSettings settings(animator);
-    settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(48));
-    layer.SetOpacity(1.0f);
-  }
-  Advance(base::TimeDelta::FromMilliseconds(32));
-  EXPECT_FALSE(reporter.reported());
-  Advance(base::TimeDelta::FromMilliseconds(32));
-  EXPECT_TRUE(reporter.reported());
-}
-
-// Tests the stopping last animation will trigger the animation.
-TEST_F(TotalAnimationThroughputReporterTest, MAYBE_StopAnimation) {
-  Layer layer;
-  layer.SetOpacity(0.5f);
-  root_layer()->Add(&layer);
-
-  TestReporter reporter(compositor());
-  {
-    LayerAnimator* animator = layer.GetAnimator();
-
-    ScopedLayerAnimationSettings settings(animator);
-    settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(48));
-    layer.SetOpacity(1.0f);
-  }
-
-  Advance(base::TimeDelta::FromMilliseconds(16));
-  EXPECT_FALSE(reporter.reported());
-  layer.GetAnimator()->StopAnimating();
-  Advance(base::TimeDelta::FromMilliseconds(16));
-  EXPECT_TRUE(reporter.reported());
-}
-
-// Tests the longest animation will trigger the report.
-TEST_F(TotalAnimationThroughputReporterTest, MAYBE_MultipleAnimations) {
-  Layer layer1;
-  layer1.SetOpacity(0.5f);
-  root_layer()->Add(&layer1);
-
-  TestReporter reporter(compositor());
-  {
-    LayerAnimator* animator = layer1.GetAnimator();
-
-    ScopedLayerAnimationSettings settings(animator);
-    settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(48));
-    layer1.SetOpacity(1.0f);
-  }
-  Layer layer2;
-  layer2.SetOpacity(0.5f);
-  root_layer()->Add(&layer2);
-
-  {
-    LayerAnimator* animator = layer2.GetAnimator();
-
-    ScopedLayerAnimationSettings settings(animator);
-    settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(96));
-    layer2.SetOpacity(1.0f);
-  }
-
-  Advance(base::TimeDelta::FromMilliseconds(32));
-  EXPECT_FALSE(reporter.reported());
-  Advance(base::TimeDelta::FromMilliseconds(32));
-  EXPECT_FALSE(reporter.reported());
-  Advance(base::TimeDelta::FromMilliseconds(200));
-  EXPECT_TRUE(reporter.reported());
-}
-
-// Tests the longest animation on a single layer will triger the report.
-TEST_F(TotalAnimationThroughputReporterTest,
-       MAYBE_MultipleAnimationsOnSingleLayer) {
-  Layer layer;
-  layer.SetOpacity(0.5f);
-  layer.SetLayerBrightness(0.5f);
-  root_layer()->Add(&layer);
-
-  TestReporter reporter(compositor());
-  {
-    LayerAnimator* animator = layer.GetAnimator();
-
-    ScopedLayerAnimationSettings settings(animator);
-    settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(48));
-    layer.SetOpacity(1.0f);
-  }
-  {
-    LayerAnimator* animator = layer.GetAnimator();
-
-    ScopedLayerAnimationSettings settings(animator);
-    settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(96));
-    layer.SetLayerBrightness(1.0f);
-  }
-
-  Advance(base::TimeDelta::FromMilliseconds(64));
-  EXPECT_FALSE(reporter.reported());
-  Advance(base::TimeDelta::FromMilliseconds(48));
-  EXPECT_TRUE(reporter.reported());
-}
-
-// Tests adding new animation will extends the duration.
-TEST_F(TotalAnimationThroughputReporterTest, MAYBE_AddAnimationWhileAnimating) {
-  Layer layer1;
-  layer1.SetOpacity(0.5f);
-  root_layer()->Add(&layer1);
-
-  TestReporter reporter(compositor());
-  {
-    LayerAnimator* animator = layer1.GetAnimator();
-
-    ScopedLayerAnimationSettings settings(animator);
-    settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(48));
-    layer1.SetOpacity(1.0f);
-  }
-
-  Advance(base::TimeDelta::FromMilliseconds(32));
-  EXPECT_FALSE(reporter.reported());
-
-  // Add new animation while animating.
-  Layer layer2;
-  layer2.SetOpacity(0.5f);
-  root_layer()->Add(&layer2);
-
-  {
-    LayerAnimator* animator = layer2.GetAnimator();
-
-    ScopedLayerAnimationSettings settings(animator);
-    settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(48));
-    layer2.SetOpacity(1.0f);
-  }
-
-  // The animation time is extended.
-  Advance(base::TimeDelta::FromMilliseconds(32));
-  EXPECT_FALSE(reporter.reported());
-
-  Advance(base::TimeDelta::FromMilliseconds(32));
-  EXPECT_TRUE(reporter.reported());
-}
-
-// Tests removing last animation will call report callback.
-TEST_F(TotalAnimationThroughputReporterTest, MAYBE_RemoveWhileAnimating) {
-  auto layer1 = std::make_unique<Layer>();
-  layer1->SetOpacity(0.5f);
-  root_layer()->Add(layer1.get());
-
-  TestReporter reporter(compositor());
-  {
-    LayerAnimator* animator = layer1->GetAnimator();
-
-    ScopedLayerAnimationSettings settings(animator);
-    settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(100));
-    layer1->SetOpacity(1.0f);
-  }
-
-  Layer layer2;
-  layer2.SetOpacity(0.5f);
-  root_layer()->Add(&layer2);
-
-  {
-    LayerAnimator* animator = layer2.GetAnimator();
-
-    ScopedLayerAnimationSettings settings(animator);
-    settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(48));
-    layer2.SetOpacity(1.0f);
-  }
-  Advance(base::TimeDelta::FromMilliseconds(48));
-  EXPECT_FALSE(reporter.reported());
-  layer1.reset();
-  // Aborting will be processed in next frame.
-  Advance(base::TimeDelta::FromMilliseconds(16));
-  EXPECT_TRUE(reporter.reported());
-}
-
-// Make sure the reporter can start measuring even if the animation
-// has started.
-TEST_F(TotalAnimationThroughputReporterTest, MAYBE_StartWhileAnimating) {
-  Layer layer;
-  layer.SetOpacity(0.5f);
-  root_layer()->Add(&layer);
-
-  {
-    LayerAnimator* animator = layer.GetAnimator();
-
-    ScopedLayerAnimationSettings settings(animator);
-    settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(48));
-    layer.SetOpacity(1.0f);
-  }
-  Advance(base::TimeDelta::FromMilliseconds(16));
-
-  TestReporter reporter(compositor());
-  EXPECT_TRUE(reporter.IsMeasuringForTesting());
-  Advance(base::TimeDelta::FromMilliseconds(100));
-  EXPECT_TRUE(reporter.reported());
-}
-
-// Tests the reporter is called multiple times for persistent animation.
-TEST_F(TotalAnimationThroughputReporterTest, MAYBE_PersistedAnimation) {
-  Layer layer;
-  layer.SetOpacity(0.5f);
-  root_layer()->Add(&layer);
-
-  // Set a persisted animator to |layer|.
-  LayerAnimator* animator =
-      new LayerAnimator(base::TimeDelta::FromMilliseconds(48));
-  layer.SetAnimator(animator);
-
-  // |reporter| keeps reporting as long as it is alive.
-  TestReporter reporter(compositor());
-
-  // Report data for animation of opacity goes to 1.
-  layer.SetOpacity(1.0f);
-  Advance(base::TimeDelta::FromMilliseconds(100));
-  EXPECT_TRUE(reporter.reported());
-
-  // Report data for animation of opacity goes to 0.5.
-  reporter.reset();
-  layer.SetOpacity(0.5f);
-  Advance(base::TimeDelta::FromMilliseconds(100));
-  EXPECT_TRUE(reporter.reported());
-}
-
-// Make sure the once reporter is called only once.
-TEST_F(TotalAnimationThroughputReporterTest, MAYBE_OnceReporter) {
-  Layer layer;
-  layer.SetOpacity(0.5f);
-  root_layer()->Add(&layer);
-
-  // Set a persisted animator to |layer|.
-  LayerAnimator* animator =
-      new LayerAnimator(base::TimeDelta::FromMilliseconds(32));
-  layer.SetAnimator(animator);
-
-  TestReporter reporter(compositor(), /*should_delete=*/false);
-
-  // Report data for animation of opacity goes to 1.
-  layer.SetOpacity(1.0f);
-  Advance(base::TimeDelta::FromMilliseconds(100));
-  EXPECT_TRUE(reporter.reported());
-
-  // Report data for animation of opacity goes to 0.5.
-  reporter.reset();
-  layer.SetOpacity(1.0f);
-  Advance(base::TimeDelta::FromMilliseconds(100));
-  EXPECT_FALSE(reporter.reported());
-}
-
-// One reporter marked as "should_delete" should be deleted when
-// reported.
-TEST_F(TotalAnimationThroughputReporterTest, MAYBE_OnceReporterShouldDelete) {
-  class DeleteTestReporter : public TotalAnimationThroughputReporter {
-   public:
-    DeleteTestReporter(Compositor* compositor,
-                       ReportOnceCallback callback,
-                       bool* deleted)
-        : TotalAnimationThroughputReporter(compositor,
-                                           std::move(callback),
-                                           true),
-          deleted_(deleted) {}
-    ~DeleteTestReporter() override { *deleted_ = true; }
-
-   private:
-    bool* deleted_;
-  };
-
-  Layer layer;
-  layer.SetOpacity(0.5f);
-  root_layer()->Add(&layer);
-
-  // Set a persisted animator to |layer|.
-  LayerAnimator* animator =
-      new LayerAnimator(base::TimeDelta::FromMilliseconds(32));
-  layer.SetAnimator(animator);
-
-  // |reporter| keeps reporting as long as it is alive.
-  bool reported = false;
-  bool deleted = false;
-  new DeleteTestReporter(
-      compositor(),
-      base::BindLambdaForTesting(
-          [&](const cc::FrameSequenceMetrics::CustomReportData&) {
-            reported = true;
-          }),
-      &deleted);
-
-  // Report data for animation of opacity goes to 1.
-  layer.SetOpacity(1.0f);
-  Advance(base::TimeDelta::FromMilliseconds(100));
-  EXPECT_TRUE(reported);
-  EXPECT_TRUE(deleted);
-}
-
-}  // namespace ui
diff --git a/ui/file_manager/externs/background/file_operation_manager.js b/ui/file_manager/externs/background/file_operation_manager.js
index 8436bdf..0a7c74c 100644
--- a/ui/file_manager/externs/background/file_operation_manager.js
+++ b/ui/file_manager/externs/background/file_operation_manager.js
@@ -66,9 +66,9 @@
   deleteEntries(entries) {}
 
   /**
-   * Restores files from trash.
+   * Schedules the files to be restored.
    *
-   * @param {Array<!FilesAppEntry>} entries The trash entries.
+   * @param {!Array<!FilesAppEntry>} entries The trash entries.
    */
   restoreDeleted(entries) {}
 
diff --git a/ui/file_manager/file_manager/background/js/file_operation_handler.js b/ui/file_manager/file_manager/background/js/file_operation_handler.js
index 67dda3a4..48a2408 100644
--- a/ui/file_manager/file_manager/background/js/file_operation_handler.js
+++ b/ui/file_manager/file_manager/background/js/file_operation_handler.js
@@ -122,8 +122,10 @@
   }
 
   /**
-   * Handles the delete event.
-   * @param {Event} event The delete event.
+   * Handles the delete event, and also the restore event which is similar to
+   * delete in that as items complete, they are removed from the containing
+   * directory.
+   * @param {Event} event The delete or restore event.
    * @private
    */
   onDeleteProgress_(event) {
@@ -139,7 +141,7 @@
         item = new ProgressCenterItem();
         item.id = event.taskId;
         item.type = ProgressItemType.DELETE;
-        item.message = FileOperationHandler.getDeleteMessage_(event);
+        item.message = FileOperationHandler.getMessage_(event);
         item.progressMax = event.totalBytes;
         item.progressValue = event.processedBytes;
         item.cancelCallback = this.fileOperationManager_.requestTaskCancel.bind(
@@ -158,7 +160,7 @@
           console.error('Cannot find deleting item.');
           return;
         }
-        item.message = FileOperationHandler.getDeleteMessage_(event);
+        item.message = FileOperationHandler.getMessage_(event);
         item.progressMax = event.totalBytes;
         item.progressValue = event.processedBytes;
         if (!pending) {
@@ -179,7 +181,7 @@
         }
 
         // Update the item.
-        item.message = FileOperationHandler.getDeleteMessage_(event);
+        item.message = FileOperationHandler.getMessage_(event);
         if (event.reason === EventType.SUCCESS) {
           item.state = ProgressItemState.COMPLETED;
           item.progressValue = item.progressMax;
@@ -230,11 +232,11 @@
             name += '/';
           }
           switch (event.status.operationType) {
-            case 'COPY':
+            case util.FileOperationType.COPY:
               return strf('COPY_TARGET_EXISTS_ERROR', name);
-            case 'MOVE':
+            case util.FileOperationType.MOVE:
               return strf('MOVE_TARGET_EXISTS_ERROR', name);
-            case 'ZIP':
+            case util.FileOperationType.ZIP:
               return strf('ZIP_TARGET_EXISTS_ERROR', name);
             default:
               return strf('TRANSFER_TARGET_EXISTS_ERROR', name);
@@ -243,11 +245,11 @@
         case util.FileOperationErrorType.FILESYSTEM_ERROR:
           const detail = util.getFileErrorString(event.error.data.name);
           switch (event.status.operationType) {
-            case 'COPY':
+            case util.FileOperationType.COPY:
               return strf('COPY_FILESYSTEM_ERROR', detail);
-            case 'MOVE':
+            case util.FileOperationType.MOVE:
               return strf('MOVE_FILESYSTEM_ERROR', detail);
-            case 'ZIP':
+            case util.FileOperationType.ZIP:
               return strf('ZIP_FILESYSTEM_ERROR', detail);
             default:
               return strf('TRANSFER_FILESYSTEM_ERROR', detail);
@@ -255,12 +257,16 @@
 
         default:
           switch (event.status.operationType) {
-            case 'COPY':
+            case util.FileOperationType.COPY:
               return strf('COPY_UNEXPECTED_ERROR', event.error.code);
-            case 'MOVE':
+            case util.FileOperationType.MOVE:
               return strf('MOVE_UNEXPECTED_ERROR', event.error.code);
-            case 'ZIP':
+            case util.FileOperationType.ZIP:
               return strf('ZIP_UNEXPECTED_ERROR', event.error.code);
+            case util.FileOperationType.DELETE:
+              return str('DELETE_ERROR');
+            case util.FileOperationType.RESTORE:
+              return str('RESTORE_FROM_TRASH_ERROR');
             default:
               return strf('TRANSFER_UNEXPECTED_ERROR', event.error.code);
           }
@@ -268,24 +274,32 @@
     } else if (event.status.numRemainingItems === 1) {
       const name = event.status.processingEntryName;
       switch (event.status.operationType) {
-        case 'COPY':
+        case util.FileOperationType.COPY:
           return strf('COPY_FILE_NAME', name);
-        case 'MOVE':
+        case util.FileOperationType.MOVE:
           return strf('MOVE_FILE_NAME', name);
-        case 'ZIP':
+        case util.FileOperationType.ZIP:
           return strf('ZIP_FILE_NAME', name);
+        case util.FileOperationType.DELETE:
+          return strf('DELETE_FILE_NAME', name);
+        case util.FileOperationType.RESTORE:
+          return strf('RESTORE_FROM_TRASH_FILE_NAME', name);
         default:
           return strf('TRANSFER_FILE_NAME', name);
       }
     } else {
       const remainNumber = event.status.numRemainingItems;
       switch (event.status.operationType) {
-        case 'COPY':
+        case util.FileOperationType.COPY:
           return strf('COPY_ITEMS_REMAINING', remainNumber);
-        case 'MOVE':
+        case util.FileOperationType.MOVE:
           return strf('MOVE_ITEMS_REMAINING', remainNumber);
-        case 'ZIP':
+        case util.FileOperationType.ZIP:
           return strf('ZIP_ITEMS_REMAINING', remainNumber);
+        case util.FileOperationType.DELETE:
+          return strf('DELETE_ITEMS_REMAINING', remainNumber);
+        case util.FileOperationType.RESTORE:
+          return strf('RESTORE_FROM_TRASH_ITEMS_REMAINING', remainNumber);
         default:
           return strf('TRANSFER_ITEMS_REMAINING', remainNumber);
       }
@@ -293,26 +307,6 @@
   }
 
   /**
-   * Generates a delete message from the event.
-   * @param {Event} event Progress event.
-   * @return {string} message.
-   * @private
-   */
-  static getDeleteMessage_(event) {
-    event = /** @type {FileOperationProgressEvent} */ (event);
-    if (event.reason === fileOperationUtil.EventRouter.EventType.ERROR) {
-      return str('DELETE_ERROR');
-    } else if (event.entries.length == 1) {
-      const fileName = event.entries[0].name;
-      return strf('DELETE_FILE_NAME', fileName);
-    } else if (event.entries.length > 1) {
-      return strf('DELETE_ITEMS_REMAINING', event.entries.length);
-    } else {
-      return '';
-    }
-  }
-
-  /**
    * Obtains ProgressItemType from OperationType of FileTransferManager.
    * @param {string} operationType OperationType of FileTransferManager.
    * @return {ProgressItemType} corresponding to the specified operation type.
@@ -320,11 +314,11 @@
    */
   static getType_(operationType) {
     switch (operationType) {
-      case 'COPY':
+      case util.FileOperationType.COPY:
         return ProgressItemType.COPY;
-      case 'MOVE':
+      case util.FileOperationType.MOVE:
         return ProgressItemType.MOVE;
-      case 'ZIP':
+      case util.FileOperationType.ZIP:
         return ProgressItemType.ZIP;
       default:
         console.error('Unknown operation type.');
diff --git a/ui/file_manager/file_manager/background/js/file_operation_manager.js b/ui/file_manager/file_manager/background/js/file_operation_manager.js
index 9ee55cbb..bffc6d1b 100644
--- a/ui/file_manager/file_manager/background/js/file_operation_manager.js
+++ b/ui/file_manager/file_manager/background/js/file_operation_manager.js
@@ -113,15 +113,16 @@
    * Returns status information for a running task.
    * @param {fileOperationUtil.Task} task The task we use to retrieve status
    *     from.
-   * @return {Object} Status object with optional volume information.
+   * @return {!fileOperationUtil.Status} Status object with optional volume
+   *     information.
    */
   getTaskStatus(task) {
     const status = task.getStatus();
     // If there's no target directory name, use the volume name for UI display.
-    if (status['targetDirEntryName'] === '' && task.targetDirEntry) {
+    if (status.targetDirEntryName === '' && task.targetDirEntry) {
       const entry = /** {Entry} */ (task.targetDirEntry);
       if (this.volumeManager_) {
-        status['targetDirEntryName'] = this.getVolumeLabel_(entry);
+        status.targetDirEntryName = this.getVolumeLabel_(entry);
       }
     }
     return status;
@@ -405,8 +406,20 @@
    * @param {!Array<!Entry>} entries The entries.
    */
   deleteEntries(entries) {
+    this.deleteOrRestore_(util.FileOperationType.DELETE, entries);
+  }
+
+  /**
+   * Schedule delete or restore.
+   *
+   * @param {!util.FileOperationType} operationType DELETE or RESTORE.
+   * @param {!Array<!Entry|!TrashEntry>} entries The entries.
+   * @private
+   */
+  deleteOrRestore_(operationType, entries) {
     const task =
         /** @type {!fileOperationUtil.DeleteTask} */ (Object.preventExtensions({
+          operationType: operationType,
           entries: entries,
           taskId: this.generateTaskId(),
           entrySize: {},
@@ -447,10 +460,10 @@
   }
 
   /**
-   * Service all pending delete tasks, as well as any that might appear during
-   * the deletion.
+   * Service all pending delete/restore tasks, as well as any that might appear
+   * during the deletion.
    *
-   * Must not be called if there is an in-flight delete task.
+   * Must not be called if there is an in-flight delete/restore task.
    *
    * @private
    */
@@ -472,16 +485,16 @@
   }
 
   /**
-   * Performs the deletion.
+   * Performs the deletion or restore.
    *
-   * @param {!Object} task The delete task (see deleteEntries function).
+   * @param {!Object} task The delete task (see deleteOrRestore_()).
    * @param {function()} callback Callback run on task end.
    * @private
    */
   serviceDeleteTask_(task, callback) {
     const queue = new AsyncUtil.Queue();
 
-    // Delete each entry.
+    // Delete or restore each entry.
     let error = null;
     const deleteOneEntry = inCallback => {
       if (!task.entries.length || task.cancelRequested || error) {
@@ -490,14 +503,34 @@
       }
       this.eventRouter_.sendDeleteEvent(
           fileOperationUtil.EventRouter.EventType.PROGRESS, task);
-      this.trash_
-          .removeFileOrDirectory(
-              assert(this.volumeManager_), task.entries[0],
-              /*permanentlyDelete=*/ false)
-          .then(trashEntry => {
-            if (trashEntry) {
-              task.trashedEntries.push(trashEntry);
-            }
+
+      // Operation will be either delete, or restore.
+      let operation;
+      switch (task.operationType) {
+        case util.FileOperationType.DELETE:
+          operation = this.trash_
+                          .removeFileOrDirectory(
+                              assert(this.volumeManager_), task.entries[0],
+                              /*permanentlyDelete=*/ false)
+                          .then(trashEntry => {
+                            if (trashEntry) {
+                              task.trashedEntries.push(trashEntry);
+                            }
+                          });
+          break;
+
+        case util.FileOperationType.RESTORE:
+          operation =
+              this.trash_.restore(assert(this.volumeManager_), task.entries[0]);
+          break;
+
+        default:
+          operation =
+              Promise.reject('Unkonwn operation type ' + task.operationType);
+      }
+
+      operation
+          .then(() => {
             this.eventRouter_.sendEntryChangedEvent(
                 util.EntryChangedKind.DELETED, task.entries[0]);
             task.processedBytes += task.entrySize[task.entries[0].toURL()];
@@ -505,7 +538,7 @@
             deleteOneEntry(inCallback);
           })
           .catch(inError => {
-            error = inError;
+            error = inError.message;
             inCallback();
           });
     };
@@ -522,30 +555,22 @@
       } else {
         reason = EventType.SUCCESS;
       }
-      this.eventRouter_.sendDeleteEvent(reason, task);
+      this.eventRouter_.sendDeleteEvent(
+          reason, task,
+          new fileOperationUtil.Error(
+              util.FileOperationErrorType.FILESYSTEM_ERROR, error));
       inCallback();
       callback();
     });
   }
 
   /**
-   * Restores files from trash.
+   * Schedules the files to be restored.
    *
-   * @param {Array<!TrashEntry>} entries The trash entries.
+   * @param {!Array<!TrashEntry>} entries The trash entries.
    */
   restoreDeleted(entries) {
-    if (!this.volumeManager_) {
-      volumeManagerFactory.getInstance().then(volumeManager => {
-        this.volumeManager_ = volumeManager;
-        this.restoreDeleted(entries);
-      });
-      return;
-    }
-
-    while (entries.length) {
-      this.trash_.restore(assert(this.volumeManager_), entries.pop())
-          .catch(e => console.error('Error restoring deleted file', e));
-    }
+    this.deleteOrRestore_(util.FileOperationType.RESTORE, entries);
   }
 
   /**
diff --git a/ui/file_manager/file_manager/background/js/file_operation_manager_unittest.js b/ui/file_manager/file_manager/background/js/file_operation_manager_unittest.js
index 36701088..068140d 100644
--- a/ui/file_manager/file_manager/background/js/file_operation_manager_unittest.js
+++ b/ui/file_manager/file_manager/background/js/file_operation_manager_unittest.js
@@ -153,7 +153,11 @@
    * @return {?EntryLocation}
    */
   getLocationInfo(entry) {
-    return null;
+    return /** @type {!EntryLocation} */ ({
+      rootType: 'downloads',
+      volumeInfo:
+          {volumeType: 'downloads', label: 'Downloads', remoteMountPath: ''}
+    });
   }
 }
 
@@ -281,7 +285,9 @@
 function setUp() {
   // Mock LoadTimeData strings.
   window.loadTimeData = {
-    data: {},
+    data: {
+      'FILES_TRASH_ENABLED': true,
+    },
     getBoolean: function(key) {
       return window.loadTimeData.data[key];
     },
@@ -868,19 +874,19 @@
   reportPromise(
       waitForEvents(fileOperationManager).then(events => {
         assertEquals('delete', events[0].type);
+        assertEquals('DELETE', events[0].status.operationType);
         assertEquals('BEGIN', events[0].reason);
-        assertEquals(10, events[0].totalBytes);
-        assertEquals(0, events[0].processedBytes);
+        assertEquals(10, events[0].status.totalBytes);
+        assertEquals(0, events[0].status.processedBytes);
 
         const lastEvent = events[events.length - 1];
         assertEquals('delete', lastEvent.type);
+        assertEquals('DELETE', lastEvent.status.operationType);
         assertEquals('SUCCESS', lastEvent.reason);
-        assertEquals(10, lastEvent.totalBytes);
-        assertEquals(10, lastEvent.processedBytes);
+        assertEquals(10, lastEvent.status.totalBytes);
+        assertEquals(10, lastEvent.status.processedBytes);
 
-        assertFalse(events.some(event => {
-          return event.type === 'copy-progress';
-        }));
+        assertFalse(events.some(e => e.type === 'copy-progress'));
       }),
       callback);
 
@@ -888,6 +894,57 @@
 }
 
 /**
+ * Tests fileOperationManager.restore.
+ * @param {function(boolean)} callback Callback to be passed true on error.
+ */
+function testRestore(callback) {
+  // Prepare entries and their resolver.
+  const fileSystem = createTestFileSystem('testVolume', {
+    '/': DIRECTORY_SIZE,
+    '/test.txt': 10,
+  });
+  window.webkitResolveLocalFileSystemURL = (url, success, failure) => {
+    resolveTestFileSystemURL(fileSystem, url, success, failure);
+  };
+
+  const onDeleted = (e) => {
+    if (e.status.operationType !== 'DELETE' || e.reason !== 'SUCCESS') {
+      return;
+    }
+    fileOperationManager.removeEventListener('delete', onDeleted);
+
+    // Step 2. Once we receive 'DELETE' 'COMPLETED', observe 'RESTORE' events.
+    reportPromise(
+        waitForEvents(fileOperationManager).then(events => {
+          // Step 4. Validate restore events.
+          assertEquals('delete', events[0].type);
+          assertEquals('RESTORE', events[0].status.operationType);
+          assertEquals('BEGIN', events[0].reason);
+          assertEquals(10, events[0].status.totalBytes);
+          assertEquals(0, events[0].status.processedBytes);
+
+          const lastEvent = events[events.length - 1];
+          assertEquals('delete', lastEvent.type);
+          assertEquals('RESTORE', lastEvent.status.operationType);
+          assertEquals('SUCCESS', lastEvent.reason);
+          assertEquals(10, lastEvent.status.totalBytes);
+          assertEquals(10, lastEvent.status.processedBytes);
+
+          assertFalse(events.some(e => e.type === 'copy-progress'));
+        }),
+        callback);
+
+    // Step 3. Restore files.
+    fileOperationManager.restoreDeleted(e.trashedEntries);
+  };
+
+
+  // Step 1. Delete files.
+  fileOperationManager.addEventListener('delete', onDeleted);
+  fileOperationManager.deleteEntries([fileSystem.entries['/test.txt']]);
+}
+
+/**
  * Tests fileOperationManager.zipSelection.
  * @param {function(boolean)} callback Callback to be passed true on error.
  */
diff --git a/ui/file_manager/file_manager/background/js/file_operation_util.js b/ui/file_manager/file_manager/background/js/file_operation_util.js
index 3ce5e64..082e6af 100644
--- a/ui/file_manager/file_manager/background/js/file_operation_util.js
+++ b/ui/file_manager/file_manager/background/js/file_operation_util.js
@@ -665,7 +665,7 @@
   /**
    * Get states of the task.
    * TODO(hirono): Removes this method and sets a task to progress events.
-   * @return {Object} Status object.
+   * @return {!fileOperationUtil.Status} Status object.
    */
   getStatus() {
     const processingEntry = this.sourceEntries[this.processingSourceIndex_];
@@ -1247,6 +1247,22 @@
 
 /**
  * @typedef {{
+ *   operationType: !util.FileOperationType,
+ *   numRemainingItems: number,
+ *   totalBytes: number,
+ *   processedBytes: number,
+ *   processingEntryName: string,
+ *   targetDirEntryName: string,
+ *   currentSpeed: number,
+ *   averageSpeed: number,
+ *   remainingTime: number,
+ * }}
+ */
+fileOperationUtil.Status;
+
+/**
+ * @typedef {{
+ *  operationType: !util.FileOperationType,
  *  entries: Array<Entry>,
  *  taskId: string,
  *  entrySize: Object,
@@ -1294,8 +1310,8 @@
    * FileOperationManager status. If it is an ERROR event, error should be set.
    *
    * @param {fileOperationUtil.EventRouter.EventType} type Event type.
-   * @param {Object} status Current FileOperationManager's status. See also
-   *     FileOperationManager.Task.getStatus().
+   * @param {!fileOperationUtil.Status} status Current FileOperationManager's
+   *     status. See also FileOperationManager.Task.getStatus().
    * @param {string} taskId ID of task related with the event.
    * @param {fileOperationUtil.Error=} opt_error The info for the error. This
    *     should be set iff the reason is "ERROR".
@@ -1371,15 +1387,26 @@
    *
    * @param {fileOperationUtil.EventRouter.EventType} reason Event type.
    * @param {!Object} task Delete task related with the event.
+   * @param {fileOperationUtil.Error=} error
    */
-  sendDeleteEvent(reason, task) {
+  sendDeleteEvent(reason, task, error) {
     const event =
         /** @type {FileOperationProgressEvent} */ (new Event('delete'));
     event.reason = reason;
+    event.error = error;
     event.taskId = task.taskId;
     event.entries = task.entries;
-    event.totalBytes = task.totalBytes;
-    event.processedBytes = task.processedBytes;
+    event.status = {
+      operationType: task.operationType,
+      numRemainingItems: task.entries.length,
+      totalBytes: task.totalBytes,
+      processedBytes: task.processedBytes,
+      processingEntryName: task.entries.length > 0 ? task.entries[0].name : '',
+      targetDirEntryName: '',
+      currentSpeed: 0,
+      averageSpeed: 0,
+      remainingTime: 0,
+    };
     event.trashedEntries = task.trashedEntries;
     this.dispatchEvent(event);
   }
diff --git a/ui/file_manager/file_manager/common/js/util.js b/ui/file_manager/file_manager/common/js/util.js
index a8ad1ba..d1eb26d 100644
--- a/ui/file_manager/file_manager/common/js/util.js
+++ b/ui/file_manager/file_manager/common/js/util.js
@@ -484,7 +484,9 @@
  */
 util.FileOperationType = {
   COPY: 'COPY',
+  DELETE: 'DELETE',
   MOVE: 'MOVE',
+  RESTORE: 'RESTORE',
   ZIP: 'ZIP',
 };
 Object.freeze(util.FileOperationType);
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
index e152ca08..87d11fd2 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
@@ -1211,7 +1211,8 @@
     fileManager.ui.toast.show(message, {
       text: str('UNDO_DELETE_ACTION_LABEL'),
       callback: () => {
-        fileManager.fileOperationManager.restoreDeleted(e.trashedEntries);
+        fileManager.fileOperationManager.restoreDeleted(
+            assert(e.trashedEntries));
       }
     });
   };
@@ -1232,7 +1233,6 @@
     fileManager.fileOperationManager.restoreDeleted(entries.map(e => {
       return /** @type {!TrashEntry} */ (e);
     }));
-    fileManager.directoryModel.rescanSoon(/*refresh=*/ false);
   }
 
   /** @override */
diff --git a/ui/gfx/skbitmap_operations.cc b/ui/gfx/skbitmap_operations.cc
index 0a3fc8b..ed96883 100644
--- a/ui/gfx/skbitmap_operations.cc
+++ b/ui/gfx/skbitmap_operations.cc
@@ -20,9 +20,16 @@
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/size.h"
 
+static bool IsUninitializedBitmap(const SkBitmap& bitmap) {
+  return bitmap.isNull() && bitmap.colorType() == kUnknown_SkColorType &&
+         bitmap.alphaType() == kUnknown_SkAlphaType;
+}
+
 // static
 SkBitmap SkBitmapOperations::CreateInvertedBitmap(const SkBitmap& image) {
-  DCHECK(image.colorType() == kN32_SkColorType);
+  if (IsUninitializedBitmap(image))
+    return image;
+  CHECK_EQ(image.colorType(), kN32_SkColorType);
 
   SkBitmap inverted;
   inverted.allocN32Pixels(image.width(), image.height());
@@ -46,10 +53,10 @@
                                                  const SkBitmap& second,
                                                  double alpha) {
   DCHECK((alpha >= 0) && (alpha <= 1));
-  DCHECK(first.width() == second.width());
-  DCHECK(first.height() == second.height());
-  DCHECK(first.bytesPerPixel() == second.bytesPerPixel());
-  DCHECK(first.colorType() == kN32_SkColorType);
+  CHECK_EQ(first.width(), second.width());
+  CHECK_EQ(first.height(), second.height());
+  CHECK_EQ(first.colorType(), kN32_SkColorType);
+  CHECK_EQ(second.colorType(), kN32_SkColorType);
 
   // Optimize for case where we won't need to blend anything.
   static const double alpha_min = 1.0 / 255;
@@ -92,11 +99,10 @@
 // static
 SkBitmap SkBitmapOperations::CreateMaskedBitmap(const SkBitmap& rgb,
                                                 const SkBitmap& alpha) {
-  DCHECK(rgb.width() == alpha.width());
-  DCHECK(rgb.height() == alpha.height());
-  DCHECK(rgb.bytesPerPixel() == alpha.bytesPerPixel());
-  DCHECK(rgb.colorType() == kN32_SkColorType);
-  DCHECK(alpha.colorType() == kN32_SkColorType);
+  CHECK_EQ(rgb.width(), alpha.width());
+  CHECK_EQ(rgb.height(), alpha.height());
+  CHECK_EQ(rgb.colorType(), kN32_SkColorType);
+  CHECK_EQ(alpha.colorType(), kN32_SkColorType);
 
   SkBitmap masked;
   masked.allocN32Pixels(rgb.width(), rgb.height());
@@ -120,11 +126,8 @@
 SkBitmap SkBitmapOperations::CreateButtonBackground(SkColor color,
                                                     const SkBitmap& image,
                                                     const SkBitmap& mask) {
-  // Despite this assert, it seems like image is actually unpremultiplied.
-  // The math producing dst_row[x] below is a correct SrcOver when
-  // bg_* are premultiplied and img_* are unpremultiplied.
-  DCHECK(image.colorType() == kN32_SkColorType);
-  DCHECK(mask.colorType() == kN32_SkColorType);
+  CHECK_EQ(image.colorType(), kN32_SkColorType);
+  CHECK_EQ(mask.colorType(), kN32_SkColorType);
 
   SkBitmap background;
   background.allocN32Pixels(mask.width(), mask.height());
@@ -476,6 +479,10 @@
 SkBitmap SkBitmapOperations::CreateHSLShiftedBitmap(
     const SkBitmap& bitmap,
     const color_utils::HSL& hsl_shift) {
+  if (IsUninitializedBitmap(bitmap))
+    return bitmap;
+  CHECK_EQ(bitmap.colorType(), kN32_SkColorType);
+
   // Default to NOPs.
   HSLShift::OperationOnH H_op = HSLShift::kOpHNone;
   HSLShift::OperationOnS S_op = HSLShift::kOpSNone;
@@ -520,7 +527,7 @@
 SkBitmap SkBitmapOperations::CreateTiledBitmap(const SkBitmap& source,
                                                int src_x, int src_y,
                                                int dst_w, int dst_h) {
-  DCHECK(source.colorType() == kN32_SkColorType);
+  CHECK_EQ(source.colorType(), kN32_SkColorType);
 
   SkBitmap cropped;
   cropped.allocN32Pixels(dst_w, dst_h);
@@ -563,6 +570,10 @@
 
 // static
 SkBitmap SkBitmapOperations::DownsampleByTwo(const SkBitmap& bitmap) {
+  if (IsUninitializedBitmap(bitmap))
+    return bitmap;
+  CHECK_EQ(bitmap.colorType(), kN32_SkColorType);
+
   // Handle the nop case.
   if ((bitmap.width() <= 1) || (bitmap.height() <= 1))
     return bitmap;
@@ -626,12 +637,12 @@
 
 // static
 SkBitmap SkBitmapOperations::UnPreMultiply(const SkBitmap& bitmap) {
-  if (bitmap.isNull())
+  if (IsUninitializedBitmap(bitmap))
     return bitmap;
+  CHECK_EQ(bitmap.colorType(), kN32_SkColorType);
+
   if (bitmap.alphaType() != kPremul_SkAlphaType)
     return bitmap;
-  // It's expected this code is called with a 32bpp image.
-  CHECK_EQ(kN32_SkColorType, bitmap.colorType());
 
   const SkImageInfo& opaque_info =
       bitmap.info().makeAlphaType(kUnpremul_SkAlphaType);
@@ -652,7 +663,9 @@
 
 // static
 SkBitmap SkBitmapOperations::CreateTransposedBitmap(const SkBitmap& image) {
-  DCHECK(image.colorType() == kN32_SkColorType);
+  if (IsUninitializedBitmap(image))
+    return image;
+  CHECK_EQ(image.colorType(), kN32_SkColorType);
 
   SkBitmap transposed;
   transposed.allocN32Pixels(image.height(), image.width());
@@ -671,7 +684,7 @@
 // static
 SkBitmap SkBitmapOperations::CreateColorMask(const SkBitmap& bitmap,
                                              SkColor c) {
-  DCHECK(bitmap.colorType() == kN32_SkColorType);
+  CHECK_EQ(bitmap.colorType(), kN32_SkColorType);
 
   SkBitmap color_mask;
   color_mask.allocN32Pixels(bitmap.width(), bitmap.height());
@@ -689,7 +702,7 @@
 SkBitmap SkBitmapOperations::CreateDropShadow(
     const SkBitmap& bitmap,
     const gfx::ShadowValues& shadows) {
-  DCHECK(bitmap.colorType() == kN32_SkColorType);
+  CHECK_EQ(bitmap.colorType(), kN32_SkColorType);
 
   // Shadow margin insets are negative values because they grow outside.
   // Negate them here as grow direction is not important and only pixel value
@@ -730,6 +743,9 @@
 // static
 SkBitmap SkBitmapOperations::Rotate(const SkBitmap& source,
                                     RotationAmount rotation) {
+  if (IsUninitializedBitmap(source))
+    return source;
+  CHECK_EQ(source.colorType(), kN32_SkColorType);
   // SkCanvas::drawBitmap() fails silently with unpremultiplied SkBitmap.
   DCHECK_NE(source.info().alphaType(), kUnpremul_SkAlphaType);
 
diff --git a/ui/ozone/platform/wayland/host/shell_surface_wrapper.h b/ui/ozone/platform/wayland/host/shell_surface_wrapper.h
index a109023..ff5ab6c 100644
--- a/ui/ozone/platform/wayland/host/shell_surface_wrapper.h
+++ b/ui/ozone/platform/wayland/host/shell_surface_wrapper.h
@@ -16,6 +16,19 @@
 
 class WaylandConnection;
 
+enum class DecorationMode {
+  // Client-side decoration for a window.
+  // In this case, the client is responsible for drawing decorations
+  // for a window (e.g. caption bar, close button). This is suitable for
+  // windows using custom frame.
+  kClientSide = 1,
+  // Server-side decoration for a window.
+  // In this case, the ash window manager is responsible for drawing
+  // decorations. This is suitable for windows using native frame.
+  // e.g. taskmanager.
+  kServerSide
+};
+
 // Wrapper interface for different wayland shells shell versions.
 class ShellSurfaceWrapper {
  public:
@@ -68,12 +81,10 @@
   // .desktop file and use the icon set there.
   virtual void SetAppId(const std::string& app_id) = 0;
 
-  // If |is_server_side_decoration| is true, sets a server side decoration,
-  // and a client side decoration otherwise.
-  //
-  // This function sends a request to the wayland compositor to update
-  // the decoration mode for a surface associated with this top level window.
-  virtual void SetDecoration(bool is_server_side_decoration) = 0;
+  // In case of kClientSide or kServerSide, this function sends a
+  // request to the wayland compositor to update the decoration mode
+  // for a surface associated with this top level window.
+  virtual void SetDecoration(DecorationMode decoration) = 0;
 };
 
 bool CheckIfWlArrayHasValue(struct wl_array* wl_array, uint32_t value);
diff --git a/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc b/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
index 6d3011d..309fc6c8f 100644
--- a/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
+++ b/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
@@ -66,7 +66,7 @@
 #else
   shell_surface_->SetAppId(wm_class_class_);
 #endif
-  shell_surface_->SetDecoration(use_native_frame_);
+  SetDecorationMode();
   shell_surface_->SetTitle(window_title_);
   SetSizeConstraints();
   TriggerStateChanges();
@@ -248,7 +248,7 @@
     return;
   use_native_frame_ = use_native_frame;
   if (shell_surface_)
-    shell_surface_->SetDecoration(use_native_frame);
+    SetDecorationMode();
 }
 
 bool WaylandToplevelWindow::ShouldUseNativeFrame() const {
@@ -478,4 +478,15 @@
   }
 }
 
+void WaylandToplevelWindow::SetDecorationMode() {
+  DCHECK(shell_surface_);
+  if (use_native_frame_) {
+    // Set server-side decoration for windows using a native frame,
+    // e.g. taskmanager
+    shell_surface_->SetDecoration(DecorationMode::kServerSide);
+  } else {
+    shell_surface_->SetDecoration(DecorationMode::kClientSide);
+  }
+}
+
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/wayland_toplevel_window.h b/ui/ozone/platform/wayland/host/wayland_toplevel_window.h
index ca423d5..a9eff34 100644
--- a/ui/ozone/platform/wayland/host/wayland_toplevel_window.h
+++ b/ui/ozone/platform/wayland/host/wayland_toplevel_window.h
@@ -60,6 +60,8 @@
   PlatformWindowState GetPlatformWindowState() const override;
   void SizeConstraintsChanged() override;
   std::string GetWindowUniqueId() const override;
+  // SetUseNativeFrame and ShouldUseNativeFrame decide on
+  // xdg-decoration mode for a window.
   void SetUseNativeFrame(bool use_native_frame) override;
   bool ShouldUseNativeFrame() const override;
 
@@ -104,6 +106,9 @@
   // is available.
   void InitializeAuraShellSurface();
 
+  // Set decoration mode for a window.
+  void SetDecorationMode();
+
   // Wrappers around shell surface.
   std::unique_ptr<ShellSurfaceWrapper> shell_surface_;
 
@@ -151,6 +156,10 @@
 
   wl::Object<zaura_surface> aura_surface_;
 
+  // When use_native_frame is false, client-side decoration is set,
+  // e.g. lacros-browser.
+  // When use_native_frame is true, server-side decoration is set,
+  // e.g. lacros-taskmanager.
   bool use_native_frame_ = false;
 
   base::WeakPtrFactory<WaylandToplevelWindow> weak_ptr_factory_{this};
diff --git a/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc b/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc
index 0d49545..1957a55 100644
--- a/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc
+++ b/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc
@@ -11,6 +11,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "ui/base/hit_test.h"
 #include "ui/ozone/platform/wayland/common/wayland_util.h"
+#include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h"
 #include "ui/ozone/platform/wayland/host/wayland_connection.h"
 #include "ui/ozone/platform/wayland/host/wayland_window.h"
 
@@ -18,7 +19,9 @@
 
 XDGSurfaceWrapperImpl::XDGSurfaceWrapperImpl(WaylandWindow* wayland_window,
                                              WaylandConnection* connection)
-    : wayland_window_(wayland_window), connection_(connection) {}
+    : wayland_window_(wayland_window),
+      connection_(connection),
+      decoration_mode_(DecorationMode::kClientSide) {}
 
 XDGSurfaceWrapperImpl::~XDGSurfaceWrapperImpl() {}
 
@@ -163,10 +166,8 @@
   }
 }
 
-void XDGSurfaceWrapperImpl::SetDecoration(bool is_server_side_decoration) {
-  SetTopLevelDecorationMode(is_server_side_decoration
-                                ? ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE
-                                : ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE);
+void XDGSurfaceWrapperImpl::SetDecoration(DecorationMode decoration) {
+  SetTopLevelDecorationMode(decoration);
 }
 
 // static
@@ -211,13 +212,13 @@
 }
 
 void XDGSurfaceWrapperImpl::SetTopLevelDecorationMode(
-    zxdg_toplevel_decoration_v1_mode requested_mode) {
+    DecorationMode requested_mode) {
   if (!zxdg_toplevel_decoration_ || requested_mode == decoration_mode_)
     return;
 
   decoration_mode_ = requested_mode;
   zxdg_toplevel_decoration_v1_set_mode(zxdg_toplevel_decoration_.get(),
-                                       requested_mode);
+                                       static_cast<uint32_t>(requested_mode));
 }
 
 // static
@@ -278,8 +279,7 @@
     uint32_t mode) {
   auto* surface = static_cast<XDGSurfaceWrapperImpl*>(data);
   DCHECK(surface);
-  surface->SetTopLevelDecorationMode(
-      static_cast<zxdg_toplevel_decoration_v1_mode>(mode));
+  surface->SetTopLevelDecorationMode(static_cast<DecorationMode>(mode));
 }
 
 bool XDGSurfaceWrapperImpl::InitializeStable(bool with_toplevel) {
@@ -360,6 +360,8 @@
   zxdg_toplevel_v6_add_listener(zxdg_toplevel_v6_.get(),
                                 &zxdg_toplevel_v6_listener, this);
 
+  InitializeXdgDecoration();
+
   wayland_window_->root_surface()->Commit();
   connection_->ScheduleFlush();
   return true;
diff --git a/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h b/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h
index 860301b..6cbb8b68 100644
--- a/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h
+++ b/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h
@@ -48,7 +48,7 @@
   void SetMinSize(int32_t width, int32_t height) override;
   void SetMaxSize(int32_t width, int32_t height) override;
   void SetAppId(const std::string& app_id) override;
-  void SetDecoration(bool is_server_side_decoration) override;
+  void SetDecoration(DecorationMode decoration) override;
 
   // xdg_surface_listener
   static void ConfigureV6(void* data,
@@ -75,8 +75,9 @@
   static void CloseTopLevelV6(void* data,
                               struct zxdg_toplevel_v6* zxdg_toplevel_v6);
 
-  void SetTopLevelDecorationMode(
-      zxdg_toplevel_decoration_v1_mode requested_mode);
+  // Send request to wayland compositor to enable a requested decoration mode.
+  void SetTopLevelDecorationMode(DecorationMode requested_mode);
+
   // zxdg_decoration_listener
   static void ConfigureDecoration(
       void* data,
@@ -109,10 +110,9 @@
 
   bool surface_for_popup_ = false;
 
-  // Keeps track of the decoration mode currently in use if xdg-decoration
-  // protocol extension is available, otherwise CLIENT_SIDE is assumed.
-  enum zxdg_toplevel_decoration_v1_mode decoration_mode_ =
-      ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
+  // On client side, it keeps track of the decoration mode currently in
+  // use if xdg-decoration protocol extension is available.
+  DecorationMode decoration_mode_;
 };
 
 }  // namespace ui
diff --git a/ui/views/controls/button/image_button.cc b/ui/views/controls/button/image_button.cc
index 0762225e..faad061 100644
--- a/ui/views/controls/button/image_button.cc
+++ b/ui/views/controls/button/image_button.cc
@@ -13,6 +13,7 @@
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/image/image_skia_operations.h"
 #include "ui/gfx/scoped_canvas.h"
+#include "ui/views/background.h"
 #include "ui/views/metadata/metadata_impl_macros.h"
 #include "ui/views/painter.h"
 #include "ui/views/widget/widget.h"
@@ -246,6 +247,11 @@
   }
 }
 
+void ToggleImageButton::SetToggledBackground(std::unique_ptr<Background> b) {
+  toggled_background_ = std::move(b);
+  SchedulePaint();
+}
+
 base::string16 ToggleImageButton::GetToggledTooltipText() const {
   return toggled_tooltip_text_;
 }
@@ -290,6 +296,15 @@
   PreferredSizeChanged();
 }
 
+void ToggleImageButton::OnPaintBackground(gfx::Canvas* canvas) {
+  if (toggled_ && toggled_background_) {
+    TRACE_EVENT0("views", "View::OnPaintBackground");
+    toggled_background_->Paint(canvas, this);
+  } else {
+    ImageButton::OnPaintBackground(canvas);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // ToggleImageButton, View overrides:
 
diff --git a/ui/views/controls/button/image_button.h b/ui/views/controls/button/image_button.h
index 6ea3fdf..4584ae2 100644
--- a/ui/views/controls/button/image_button.h
+++ b/ui/views/controls/button/image_button.h
@@ -138,6 +138,11 @@
   // before the button is toggled.
   void SetToggledImage(ButtonState state, const gfx::ImageSkia* image);
 
+  // Like Views::SetBackground(), but to set the background color used for the
+  // "has been toggled" state.
+  void SetToggledBackground(std::unique_ptr<Background> b);
+  Background* toggled_background() { return toggled_background_.get(); }
+
   // Get/Set the tooltip text displayed when the button is toggled.
   base::string16 GetToggledTooltipText() const;
   void SetToggledTooltipText(const base::string16& tooltip);
@@ -153,6 +158,7 @@
   // Overridden from View:
   base::string16 GetTooltipText(const gfx::Point& p) const override;
   void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
+  void OnPaintBackground(gfx::Canvas* canvas) override;
 
  private:
   // The parent class's images_ member is used for the current images,
@@ -163,6 +169,8 @@
   // True if the button is currently toggled.
   bool toggled_ = false;
 
+  std::unique_ptr<Background> toggled_background_;
+
   // The parent class's tooltip_text_ is displayed when not toggled, and
   // this one is shown when toggled.
   base::string16 toggled_tooltip_text_;
diff --git a/weblayer/browser/safe_browsing/url_checker_delegate_impl.cc b/weblayer/browser/safe_browsing/url_checker_delegate_impl.cc
index ecb3fbe..d016279 100644
--- a/weblayer/browser/safe_browsing/url_checker_delegate_impl.cc
+++ b/weblayer/browser/safe_browsing/url_checker_delegate_impl.cc
@@ -45,7 +45,7 @@
 
 void UrlCheckerDelegateImpl::MaybeDestroyPrerenderContents(
     content::WebContents::OnceGetter web_contents_getter) {
-  // Destroy the prefetch with FINAL_STATUS_SAFEBROSWING.
+  // Destroy the prefetch with FINAL_STATUS_SAFE_BROWSING.
   content::GetUIThreadTaskRunner({})->PostTask(
       FROM_HERE, base::BindOnce(&DestroyPrerenderContents,
                                 std::move(web_contents_getter)));