diff --git a/AUTHORS b/AUTHORS
index c9d76de..160949c 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1074,6 +1074,7 @@
 Wesley Lancel <wesleylancel@gmail.com>
 Wei Wang <wei4.wang@intel.com>
 Wesley Wigham <wwigham@gmail.com>
+Will Cohen <wwcohen@gmail.com>
 Will Hirsch <chromium@willhirsch.co.uk>
 Will Shackleton <w.shackleton@gmail.com>
 William Xie <william.xie@intel.com>
diff --git a/DEPS b/DEPS
index 21ea3f45..3c65961 100644
--- a/DEPS
+++ b/DEPS
@@ -206,11 +206,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '3cd384a5b039c4428c05e4a81f974f9dd80c9976',
+  'skia_revision': '1a364c273e289ebd3a318f92c122571875ec5daa',
   # 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': '74cd21ef855b0602e4b70e049794699fe06b4f82',
+  'v8_revision': '35582ccb50705f34b3c89fc4e95ba9a3a10da681',
   # 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.
@@ -329,7 +329,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': 'a584311a6a73a2b8b21703874742128c6d92f549',
+  'dawn_revision': 'af64c73c174ce666d7fe7f11427c14b439b62515',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -368,7 +368,7 @@
   'ukey2_revision': '0275885d8e6038c39b8a8ca55e75d1d4d1727f47',
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'tint_revision': 'd2fa57d26dff88826fd6274ed4b77734186f89e3',
+  'tint_revision': '62bbc6f6c0507b07c8d1057d8da4dc65afed4114',
 
   # TODO(crbug.com/941824): The values below need to be kept in sync
   # between //DEPS and //buildtools/DEPS, so if you're updating one,
@@ -892,7 +892,7 @@
   # Tools used when building Chrome for Chrome OS. This affects both the Simple
   # Chrome workflow, as well as the chromeos-chrome ebuild.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'aba52f78e1bafd1b0e2a55707bedaa56d12e9c24',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '5ae623f592fc43b10ca5a4855223e396c13706fc',
       'condition': 'checkout_chromeos',
   },
 
@@ -1569,7 +1569,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@9e4c794ee0a5c2cf27c67d2185b927229a9ee2e0',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@b6d93e6c4293060b06c4f15d4cbd7f945e73c8d3',
     'condition': 'checkout_src_internal',
   },
 
@@ -1588,7 +1588,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'bvq8h_3qcpwsdxTwUG4X0xotu2aez7gKp0cfE2xFsewC',
+        'version': '8Q4xmmaYrnhc7cohh6-6mYy09ZY7fiz1y0LEgZ-Y0boC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/WATCHLISTS b/WATCHLISTS
index 18a108f..4aa4712 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -2659,8 +2659,7 @@
     'net_base': ['bnc+watch@chromium.org',
                  'juke+watch@chromium.org'],
     'net_http2': ['bnc+watch@chromium.org'],
-    'net_log': ['bnc+watch@chromium.org',
-                'eroman@chromium.org'],
+    'net_log': ['bnc+watch@chromium.org'],
     'net_server': ['ricea+watch@chromium.org'],
     'net_spdy': ['bnc+watch@chromium.org'],
     'net_websockets': ['ricea+watch@chromium.org'],
diff --git a/android_webview/browser/gfx/aw_gl_surface_external_stencil.cc b/android_webview/browser/gfx/aw_gl_surface_external_stencil.cc
index f589a2e2..1abc9733 100644
--- a/android_webview/browser/gfx/aw_gl_surface_external_stencil.cc
+++ b/android_webview/browser/gfx/aw_gl_surface_external_stencil.cc
@@ -82,6 +82,12 @@
       glDisableVertexAttribArray(i);
     }
 
+    // Note that function is not ANGLE only.
+    if (gl::g_current_gl_driver->fn.glVertexAttribDivisorANGLEFn) {
+      glVertexAttribDivisorANGLE(0, 0);
+      glVertexAttribDivisorANGLE(1, 0);
+    }
+
     glEnableVertexAttribArray(0);
     glEnableVertexAttribArray(1);
 
@@ -220,6 +226,8 @@
 
     glActiveTexture(GL_TEXTURE0);
     glBindTexture(GL_TEXTURE_2D, framebuffer_->texture_id());
+    if (gl::g_current_gl_driver->fn.glBindSamplerFn)
+      glBindSampler(0, 0);
 
     // We need to restore viewport as it might have changed by renderer
     glViewport(0, 0, viewport_.width(), viewport_.height());
@@ -230,6 +238,15 @@
     // Restore color mask in case.
     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
 
+    glDisable(GL_CULL_FACE);
+    glDisable(GL_DEPTH_TEST);
+    glDisable(GL_BLEND);
+    glFrontFace(GL_CCW);
+    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+
+    if (gl::g_current_gl_driver->fn.glWindowRectanglesEXTFn)
+      glWindowRectanglesEXT(GL_EXCLUSIVE_EXT, 0, nullptr);
+
     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
   }
 
diff --git a/android_webview/browser/gfx/scoped_app_gl_state_restore.cc b/android_webview/browser/gfx/scoped_app_gl_state_restore.cc
index 358eaad..0e751fa 100644
--- a/android_webview/browser/gfx/scoped_app_gl_state_restore.cc
+++ b/android_webview/browser/gfx/scoped_app_gl_state_restore.cc
@@ -8,11 +8,28 @@
 
 #include "base/lazy_instance.h"
 #include "base/trace_event/trace_event.h"
+#include "components/viz/common/features.h"
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_context.h"
 #include "ui/gl/gl_surface_stub.h"
 #include "ui/gl/init/gl_factory.h"
 
+// We can't include khronos headers because of conflict with gl_bindings.h, but
+// we need this constant for restoring state.
+#ifndef GL_ARM_shader_framebuffer_fetch
+#define GL_ARM_shader_framebuffer_fetch 1
+#define GL_FETCH_PER_SAMPLE_ARM 0x8F65
+#define GL_FRAGMENT_SHADER_FRAMEBUFFER_FETCH_MRT_ARM 0x8F66
+#endif /* GL_ARM_shader_framebuffer_fetch */
+
+#ifndef GL_NV_conservative_raster
+#define GL_NV_conservative_raster 1
+#define GL_CONSERVATIVE_RASTERIZATION_NV 0x9346
+#define GL_SUBPIXEL_PRECISION_BIAS_X_BITS_NV 0x9347
+#define GL_SUBPIXEL_PRECISION_BIAS_Y_BITS_NV 0x9348
+#define GL_MAX_SUBPIXEL_PRECISION_BIAS_BITS_NV 0x9349
+#endif /* GL_NV_conservative_raster */
+
 namespace android_webview {
 
 namespace {
@@ -67,6 +84,10 @@
 GLint g_gl_max_texture_units = 0;
 GLint g_gl_max_vertex_attribs = 0;
 bool g_supports_oes_vertex_array_object = false;
+bool g_supports_arm_shader_framebuffer_fetch = false;
+bool g_supports_nv_concervative_raster = false;
+bool g_supports_disable_multisample = false;
+bool g_use_skia_renderer = false;
 ScopedAppGLStateRestore* g_current_instance = nullptr;
 
 }  // namespace
@@ -132,6 +153,9 @@
   GLboolean enable_polygon_offset_fill_;
   GLboolean enable_sample_alpha_to_coverage_;
   GLboolean enable_sample_coverage_;
+  GLboolean multisample_enabled_;
+  // ARM_shader_framebuffer_fetch
+  GLboolean fetch_per_sample_arm_enabled_;
 
   // Not saved/restored in MODE_DRAW.
   GLboolean blend_enabled_;
@@ -195,6 +219,29 @@
 
   glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &framebuffer_binding_ext_);
 
+  if (!g_globals_initialized) {
+    g_globals_initialized = true;
+
+    glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &g_gl_max_vertex_attribs);
+    glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &g_gl_max_texture_units);
+
+    std::string extensions;
+    const char* extensions_c_str =
+        reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
+    if (extensions_c_str)
+      extensions = extensions_c_str;
+    g_supports_oes_vertex_array_object =
+        extensions.find("GL_OES_vertex_array_object") != std::string::npos;
+    g_supports_arm_shader_framebuffer_fetch =
+        extensions.find("GL_ARM_shader_framebuffer_fetch") != std::string::npos;
+    g_supports_nv_concervative_raster =
+        extensions.find("GL_NV_conservative_raster") != std::string::npos;
+    g_supports_disable_multisample =
+        extensions.find("GL_EXT_multisample_compatibility") !=
+        std::string::npos;
+    g_use_skia_renderer = features::IsUsingSkiaRenderer();
+  }
+
   if (save_restore_) {
     SaveHWUIState();
   }
@@ -211,21 +258,6 @@
 }
 
 void ScopedAppGLStateRestoreImpl::SaveHWUIState() {
-  if (!g_globals_initialized) {
-    g_globals_initialized = true;
-
-    glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &g_gl_max_vertex_attribs);
-    glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &g_gl_max_texture_units);
-
-    std::string extensions;
-    const char* extensions_c_str =
-        reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
-    if (extensions_c_str)
-      extensions = extensions_c_str;
-    g_supports_oes_vertex_array_object =
-        extensions.find("GL_OES_vertex_array_object") != std::string::npos;
-  }
-
   glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &vertex_array_buffer_binding_);
   glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &index_array_buffer_binding_);
 
@@ -312,6 +344,14 @@
     glGetVertexAttribfv(
         i, GL_CURRENT_VERTEX_ATTRIB, vertex_attrib_[i].current_vertex_attrib);
   }
+
+  if (g_use_skia_renderer) {
+    if (g_supports_arm_shader_framebuffer_fetch)
+      glGetBooleanv(GL_FETCH_PER_SAMPLE_ARM, &fetch_per_sample_arm_enabled_);
+
+    if (g_supports_disable_multisample)
+      glGetBooleanv(GL_MULTISAMPLE, &multisample_enabled_);
+  }
 }
 
 ScopedAppGLStateRestoreImpl::~ScopedAppGLStateRestoreImpl() {
@@ -322,6 +362,11 @@
     RestoreHWUIState();
   }
 
+  // We do restore it even with Skia on the other side because it's new
+  // extension that skia on Android P and Q didn't use.
+  if (g_use_skia_renderer && g_supports_nv_concervative_raster)
+    glDisable(GL_CONSERVATIVE_RASTERIZATION_NV);
+
   // Do not leak GLError out of chromium.
   ClearGLErrors(true, "Chromium GLError");
 }
@@ -345,6 +390,15 @@
 
     glVertexAttrib4fv(i, vertex_attrib_[i].current_vertex_attrib);
 
+    // We don't query this values as this code intends to run on older (O and
+    // below) Android versions and HWUI there doesn't use the state, while
+    // SkiaRenderer does, so we just reset it to default value.
+    // Note despite the name function is no ANGLE specific.
+    if (g_use_skia_renderer &&
+        gl::g_current_gl_driver->fn.glVertexAttribDivisorANGLEFn) {
+      glVertexAttribDivisorANGLE(i, 0);
+    }
+
     if (vertex_attrib_[i].enabled) {
       glEnableVertexAttribArray(i);
     } else {
@@ -363,6 +417,10 @@
     glBindTexture(GL_TEXTURE_2D, bindings.texture_2d);
     glBindTexture(GL_TEXTURE_CUBE_MAP, bindings.texture_cube_map);
     glBindTexture(GL_TEXTURE_EXTERNAL_OES, bindings.texture_external_oes);
+
+    // reset glSamplers if supported.
+    if (g_use_skia_renderer && gl::g_current_gl_driver->fn.glBindSamplerFn)
+      glBindSampler(ii, 0);
   }
   glActiveTexture(active_texture_);
 
@@ -434,6 +492,25 @@
   glStencilOpSeparate(GL_BACK, stencil_state_.stencil_back_fail_op,
                       stencil_state_.stencil_back_z_fail_op,
                       stencil_state_.stencil_back_z_pass_op);
+
+  if (g_use_skia_renderer) {
+    // This code is triggered only for older Android version when it didn't use
+    // Skia for compositing. We restore state to default value instead of
+    // querying the value because older HWUI didn't use it.
+    if (gl::g_current_gl_driver->fn.glWindowRectanglesEXTFn)
+      glWindowRectanglesEXT(GL_EXCLUSIVE_EXT, 0, nullptr);
+
+    if (gl::g_current_gl_driver->fn.glCoverageModulationNVFn)
+      glCoverageModulationNV(GL_NONE);
+
+    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+
+    if (g_supports_arm_shader_framebuffer_fetch)
+      GLEnableDisable(GL_FETCH_PER_SAMPLE_ARM, fetch_per_sample_arm_enabled_);
+
+    if (g_supports_disable_multisample)
+      GLEnableDisable(GL_MULTISAMPLE, multisample_enabled_);
+  }
 }
 
 }  // namespace internal
diff --git a/android_webview/expectations/system_webview_bundle.AndroidManifest.expected b/android_webview/expectations/system_webview_bundle.AndroidManifest.expected
index 07e8126..ca00959e 100644
--- a/android_webview/expectations/system_webview_bundle.AndroidManifest.expected
+++ b/android_webview/expectations/system_webview_bundle.AndroidManifest.expected
@@ -58,6 +58,17 @@
         android:targetActivity="org.chromium.android_webview.devui.MainActivity"
         android:visibleToInstantApps="true">
     </activity-alias>  # DIFF-ANCHOR: b7cc06e9
+    <activity-alias  # DIFF-ANCHOR: a4f5e364
+        android:enabled="false"
+        android:exported="true"
+        android:label="WebView DevTools"
+        android:name="org.chromium.android_webview.devui.LauncherActivity"
+        android:targetActivity="org.chromium.android_webview.devui.MainActivity">
+      <intent-filter>  # DIFF-ANCHOR: a5330430
+        <action android:name="android.intent.action.MAIN"/>
+        <category android:name="android.intent.category.LAUNCHER"/>
+      </intent-filter>  # DIFF-ANCHOR: a5330430
+    </activity-alias>  # DIFF-ANCHOR: a4f5e364
     <meta-data android:name="$PACKAGE.WebViewLibrary" android:value="libwebviewchromium.so"/>
     <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version"/>
     <meta-data android:name="org.chromium.content.browser.NUM_PRIVILEGED_SERVICES" android:value="0"/>
diff --git a/android_webview/expectations/trichrome_webview_bundle.AndroidManifest.expected b/android_webview/expectations/trichrome_webview_bundle.AndroidManifest.expected
index f46f3621e..1f6f5660 100644
--- a/android_webview/expectations/trichrome_webview_bundle.AndroidManifest.expected
+++ b/android_webview/expectations/trichrome_webview_bundle.AndroidManifest.expected
@@ -58,6 +58,17 @@
         android:targetActivity="org.chromium.android_webview.devui.MainActivity"
         android:visibleToInstantApps="true">
     </activity-alias>  # DIFF-ANCHOR: b7cc06e9
+    <activity-alias  # DIFF-ANCHOR: a4f5e364
+        android:enabled="false"
+        android:exported="true"
+        android:label="WebView DevTools"
+        android:name="org.chromium.android_webview.devui.LauncherActivity"
+        android:targetActivity="org.chromium.android_webview.devui.MainActivity">
+      <intent-filter>  # DIFF-ANCHOR: a5330430
+        <action android:name="android.intent.action.MAIN"/>
+        <category android:name="android.intent.category.LAUNCHER"/>
+      </intent-filter>  # DIFF-ANCHOR: a5330430
+    </activity-alias>  # DIFF-ANCHOR: a4f5e364
     <meta-data android:name="$PACKAGE.WebViewLibrary" android:value="libmonochrome.so"/>
     <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version"/>
     <meta-data android:name="org.chromium.content.browser.NUM_PRIVILEGED_SERVICES" android:value="0"/>
diff --git a/android_webview/nonembedded/BUILD.gn b/android_webview/nonembedded/BUILD.gn
index 5663848..668b391 100644
--- a/android_webview/nonembedded/BUILD.gn
+++ b/android_webview/nonembedded/BUILD.gn
@@ -161,9 +161,18 @@
   ]
 }
 
+_devui_launcher_icon_android_manifest = "$root_gen_dir/android_webview/system_webview_apk/DeveloperUiLauncherManifest.xml"
+
+jinja_template("devui_launcher_icon_manifest") {
+  input = "java/DeveloperUiLauncherManifest.xml"
+  output = _devui_launcher_icon_android_manifest
+  variables = [ "show_devui_icon=$webview_devui_show_icon" ]
+}
+
 android_resources("devui_launcher_icon_resources") {
   sources = []
-  android_manifest = "java/DeveloperUiLauncherManifest.xml"
+  android_manifest = _devui_launcher_icon_android_manifest
+  android_manifest_dep = ":devui_launcher_icon_manifest"
 }
 
 android_resources("monochrome_devui_launcher_icon_resources") {
diff --git a/android_webview/nonembedded/java/DeveloperUiLauncherManifest.xml b/android_webview/nonembedded/java/DeveloperUiLauncherManifest.xml
index a1457e8..226e331 100644
--- a/android_webview/nonembedded/java/DeveloperUiLauncherManifest.xml
+++ b/android_webview/nonembedded/java/DeveloperUiLauncherManifest.xml
@@ -15,7 +15,8 @@
         <activity-alias android:name="org.chromium.android_webview.devui.LauncherActivity"
                   android:targetActivity="org.chromium.android_webview.devui.MainActivity"
                   android:label="WebView DevTools"
-                  android:exported="true">
+                  android:exported="true"
+                  android:enabled="{{ show_devui_icon|default('true') }}">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
                 <category android:name="android.intent.category.LAUNCHER"/>
diff --git a/android_webview/system_webview_apk_tmpl.gni b/android_webview/system_webview_apk_tmpl.gni
index fa280ae..d419710 100644
--- a/android_webview/system_webview_apk_tmpl.gni
+++ b/android_webview/system_webview_apk_tmpl.gni
@@ -46,6 +46,7 @@
     deps += [
       "//android_webview:locale_pak_assets",
       "//android_webview:pak_file_assets",
+      "//android_webview/nonembedded:devui_launcher_icon_resources",
     ]
 
     if (_exclude_weblayer_java) {
@@ -86,10 +87,6 @@
       alternative_android_sdk_dep = webview_framework_dep
     }
 
-    if (webview_devui_show_icon) {
-      deps += [ "//android_webview/nonembedded:devui_launcher_icon_resources" ]
-    }
-
     _use_trichrome_library =
         defined(use_trichrome_library) && use_trichrome_library
     assert(
diff --git a/ash/clipboard/clipboard_history.cc b/ash/clipboard/clipboard_history.cc
index 74dca83..44fbf6d0 100644
--- a/ash/clipboard/clipboard_history.cc
+++ b/ash/clipboard/clipboard_history.cc
@@ -12,7 +12,7 @@
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "ui/base/clipboard/clipboard_monitor.h"
 #include "ui/base/clipboard/clipboard_non_backed.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 
 namespace ash {
 
diff --git a/ash/clipboard/clipboard_history_controller_impl.cc b/ash/clipboard/clipboard_history_controller_impl.cc
index 9457487..4c38afbb4 100644
--- a/ash/clipboard/clipboard_history_controller_impl.cc
+++ b/ash/clipboard/clipboard_history_controller_impl.cc
@@ -23,7 +23,7 @@
 #include "ui/base/clipboard/clipboard_constants.h"
 #include "ui/base/clipboard/clipboard_data.h"
 #include "ui/base/clipboard/clipboard_non_backed.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 #include "ui/base/ime/input_method.h"
 #include "ui/base/ime/text_input_client.h"
 #include "ui/base/models/image_model.h"
diff --git a/ash/clipboard/clipboard_history_menu_model_adapter.cc b/ash/clipboard/clipboard_history_menu_model_adapter.cc
index 0d72ceb..4c598cd6 100644
--- a/ash/clipboard/clipboard_history_menu_model_adapter.cc
+++ b/ash/clipboard/clipboard_history_menu_model_adapter.cc
@@ -10,8 +10,8 @@
 #include "ash/public/cpp/clipboard_image_model_factory.h"
 #include "base/metrics/histogram_macros.h"
 #include "ui/base/clipboard/clipboard.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
-#include "ui/base/clipboard/data_transfer_policy_controller.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/ui_base_types.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/views/controls/menu/menu_item_view.h"
diff --git a/ash/events/OWNERS b/ash/events/OWNERS
index fd423df3..f38b74cc 100644
--- a/ash/events/OWNERS
+++ b/ash/events/OWNERS
@@ -1,3 +1,2 @@
-per-file spoken_feedback_event_rewriter*=file://ui/accessibility/OWNERS
+per-file accessibility_event_rewriter*=file://ui/accessibility/OWNERS
 per-file select_to_speak_event_handler*=file://ui/accessibility/OWNERS
-per-file switch_access_event_handler*=file://ui/accessibility/OWNERS
diff --git a/ash/login/ui/login_base_bubble_view.cc b/ash/login/ui/login_base_bubble_view.cc
index 5bb96b17..362a18b 100644
--- a/ash/login/ui/login_base_bubble_view.cc
+++ b/ash/login/ui/login_base_bubble_view.cc
@@ -180,10 +180,20 @@
   // calculated by using the root view's coordinates system. kShowAbove and
   // kShowBelow are less complicated, they only use the coordinate system of the
   // the anchor view's parent.
+
+  // In RTL case, we are doing mirroring in `ConvertPointToTarget` when finding
+  // the position of the bubble. However, there's no need to mirror since the
+  // coordinate system is from right to left and the origin is the right upper
+  // corner. `GetMirroredXWithWidthInView` is called to cancel out the mirroring
+  // effect and returning the correct position for the bubble.
   gfx::Point anchor_position = GetAnchorView()->bounds().origin();
+  gfx::Point origin;
   ConvertPointToTarget(GetAnchorView()->parent() /*source*/,
                        GetAnchorView()->GetWidget()->GetRootView() /*target*/,
-                       &anchor_position);
+                       &origin);
+  origin.set_x(parent()->GetMirroredXWithWidthInView(
+      origin.x(), GetAnchorView()->parent()->width()));
+  anchor_position += origin.OffsetFromOrigin();
   auto bounds = GetBoundsAvailableToShowBubble();
   gfx::Size bubble_size(width() + 2 * horizontal_padding_,
                         height() + vertical_padding_);
diff --git a/ash/public/cpp/external_arc/message_center/arc_notification_content_view.cc b/ash/public/cpp/external_arc/message_center/arc_notification_content_view.cc
index 0f3b83c..8518f03e 100644
--- a/ash/public/cpp/external_arc/message_center/arc_notification_content_view.cc
+++ b/ash/public/cpp/external_arc/message_center/arc_notification_content_view.cc
@@ -687,10 +687,11 @@
         item_->GetSnapshot().height(), contents_bounds.x(), contents_bounds.y(),
         contents_bounds.width(), contents_bounds.height(), true /* filter */);
   } else {
-    // Draw a blank background otherwise. The height of the view and surface are
-    // not exactly synced and user may see the blank area out of the surface.
-    // This code prevetns an ugly blank area and show white color instead.
-    // This should be removed after b/35786193 is done.
+    // Draw a white background otherwise. The height of the view/ surface and
+    // animation buffer size are not exactly synced and user may see the blank
+    // area out of the surface.
+    // TODO: This can be removed once both ARC and Chrome notifications have
+    // smooth expansion animations.
     canvas->DrawColor(SK_ColorWHITE);
   }
 }
diff --git a/ash/system/phonehub/task_continuation_view_unittest.cc b/ash/system/phonehub/task_continuation_view_unittest.cc
index 9b30f7ed..5d55c13 100644
--- a/ash/system/phonehub/task_continuation_view_unittest.cc
+++ b/ash/system/phonehub/task_continuation_view_unittest.cc
@@ -110,18 +110,6 @@
   expected_tabs = 2;
   EXPECT_EQ(expected_tabs, task_view()->chips_view_->children().size());
 
-  tabs.push_back(metadata);
-  phone_model()->SetBrowserTabsModel(BrowserTabsModel(true, tabs));
-  // The chips view should contains 3 tab.
-  expected_tabs = 3;
-  EXPECT_EQ(expected_tabs, task_view()->chips_view_->children().size());
-
-  tabs.push_back(metadata);
-  phone_model()->SetBrowserTabsModel(BrowserTabsModel(true, tabs));
-  // The chips view should contains 4 tab.
-  expected_tabs = 4;
-  EXPECT_EQ(expected_tabs, task_view()->chips_view_->children().size());
-
   for (auto* child : task_view()->chips_view_->children()) {
     ContinueBrowsingChip* chip = static_cast<ContinueBrowsingChip*>(child);
     // NewTabWithUrl is expected to call after button pressed simulation.
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 2438dcc..3e44373 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -260,6 +260,9 @@
     "files/scoped_temp_dir.cc",
     "files/scoped_temp_dir.h",
     "format_macros.h",
+    "functional/identity.h",
+    "functional/invoke.h",
+    "functional/not_fn.h",
     "gtest_prod_util.h",
     "guid.cc",
     "guid.h",
@@ -2739,6 +2742,9 @@
     "files/important_file_writer_unittest.cc",
     "files/memory_mapped_file_unittest.cc",
     "files/scoped_temp_dir_unittest.cc",
+    "functional/identity_unittest.cc",
+    "functional/invoke_unittest.cc",
+    "functional/not_fn_unittest.cc",
     "gmock_unittest.cc",
     "guid_unittest.cc",
     "hash/hash_unittest.cc",
diff --git a/base/allocator/partition_allocator/memory_reclaimer_unittest.cc b/base/allocator/partition_allocator/memory_reclaimer_unittest.cc
index 67ab373..43429a43 100644
--- a/base/allocator/partition_allocator/memory_reclaimer_unittest.cc
+++ b/base/allocator/partition_allocator/memory_reclaimer_unittest.cc
@@ -39,7 +39,9 @@
     PartitionAllocGlobalInit(HandleOOM);
     PartitionAllocMemoryReclaimer::Instance()->ResetForTesting();
     allocator_ = std::make_unique<PartitionAllocator>();
-    allocator_->init();
+    allocator_->init({PartitionOptions::Alignment::kRegular,
+                      PartitionOptions::ThreadCache::kDisabled,
+                      PartitionOptions::PCScan::kAlwaysDisabled});
   }
 
   void TearDown() override {
diff --git a/base/allocator/partition_allocator/partition_alloc.h b/base/allocator/partition_allocator/partition_alloc.h
index 80b1b0a..d9ee79155 100644
--- a/base/allocator/partition_allocator/partition_alloc.h
+++ b/base/allocator/partition_allocator/partition_alloc.h
@@ -92,7 +92,7 @@
   PartitionAllocator() = default;
   ~PartitionAllocator();
 
-  void init(PartitionOptions = {});
+  void init(PartitionOptions);
 
   ALWAYS_INLINE PartitionRoot<thread_safe>* root() { return &partition_root_; }
   ALWAYS_INLINE const PartitionRoot<thread_safe>* root() const {
diff --git a/base/allocator/partition_allocator/partition_bucket.cc b/base/allocator/partition_allocator/partition_bucket.cc
index 06738ac..1384885 100644
--- a/base/allocator/partition_allocator/partition_bucket.cc
+++ b/base/allocator/partition_allocator/partition_bucket.cc
@@ -268,7 +268,7 @@
   // Allocate from GigaCage, if enabled. However, the exception to this is when
   // tags aren't allowed, as CheckedPtr assumes that everything inside GigaCage
   // uses tags (specifically, inside the GigaCage's normal bucket pool).
-  if (root->allow_extras && features::IsPartitionAllocGigaCageEnabled()) {
+  if (root->UsesGigaCage()) {
     super_page = AddressPoolManager::GetInstance()->Alloc(
         GetNormalBucketPool(), requested_address, kSuperPageSize);
   } else {
diff --git a/base/allocator/partition_allocator/partition_root.cc b/base/allocator/partition_allocator/partition_root.cc
index b176024..3b6974a 100644
--- a/base/allocator/partition_allocator/partition_root.cc
+++ b/base/allocator/partition_allocator/partition_root.cc
@@ -375,7 +375,8 @@
   scannable = (opts.pcscan != PartitionOptions::PCScan::kAlwaysDisabled);
   // Concurrent freeing in PCScan can only safely work on thread-safe
   // partitions.
-  if (thread_safe && opts.pcscan == PartitionOptions::PCScan::kEnabled)
+  if (thread_safe &&
+      opts.pcscan == PartitionOptions::PCScan::kForcedEnabledForTesting)
     pcscan.emplace(this);
 
   // We mark the sentinel slot span as free to make sure it is skipped by our
diff --git a/base/allocator/partition_allocator/partition_root.h b/base/allocator/partition_allocator/partition_root.h
index 1c64a0a..2b140d3 100644
--- a/base/allocator/partition_allocator/partition_root.h
+++ b/base/allocator/partition_allocator/partition_root.h
@@ -100,12 +100,12 @@
     // PartitionRoot::EnablePCScan().
     kDisabledByDefault,
     // PCScan is always enabled.
-    kEnabled,
+    kForcedEnabledForTesting,
   };
 
-  Alignment alignment = Alignment::kRegular;
-  ThreadCache thread_cache = ThreadCache::kDisabled;
-  PCScan pcscan = PCScan::kAlwaysDisabled;
+  Alignment alignment;
+  ThreadCache thread_cache;
+  PCScan pcscan;
 };
 
 // Never instantiate a PartitionRoot directly, instead use
@@ -286,9 +286,7 @@
   }
 
   void EnablePCScan() {
-    // TODO(bikineev): Make CHECK once PCScan is enabled.
-    if (!scannable || pcscan.has_value())
-      return;
+    PA_CHECK(scannable && !pcscan.has_value());
     pcscan.emplace(this);
   }
 
diff --git a/base/allocator/partition_allocator/pcscan_unittest.cc b/base/allocator/partition_allocator/pcscan_unittest.cc
index 7b0a36ac..5264f8ec 100644
--- a/base/allocator/partition_allocator/pcscan_unittest.cc
+++ b/base/allocator/partition_allocator/pcscan_unittest.cc
@@ -18,7 +18,7 @@
     PartitionAllocGlobalInit([](size_t) { LOG(FATAL) << "Out of memory"; });
     allocator_.init({PartitionOptions::Alignment::kRegular,
                      PartitionOptions::ThreadCache::kDisabled,
-                     PartitionOptions::PCScan::kEnabled});
+                     PartitionOptions::PCScan::kForcedEnabledForTesting});
   }
   ~PCScanTest() override {
     allocator_.root()->PurgeMemory(PartitionPurgeDecommitEmptySlotSpans |
diff --git a/base/functional/README.md b/base/functional/README.md
new file mode 100644
index 0000000..a40d8b2
--- /dev/null
+++ b/base/functional/README.md
@@ -0,0 +1,27 @@
+# base/functional library
+
+[TOC]
+
+## What goes here
+
+This directory contains function objects from future STL versions and closely
+related types.
+
+Things should be moved here that are generally applicable across the code base.
+Don't add things here just because you need them in one place and think others
+may someday want something similar. You can put specialized function objects in
+your component's directory and we can promote them here later if we feel there
+is broad applicability.
+
+### Design and naming
+
+Fundamental [//base principles](../README.md#design-and-naming) apply, i.e.:
+
+Function objects should either come directly from the STL or adhere as closely
+to STL as possible. Functions and behaviors not present in STL should only be
+added when they are related to the specific function objects.
+
+For STL-like function objects our policy is that they should use STL-like naming
+even when it may conflict with the style guide. So functions and class names
+should be lower case with underscores. Non-STL-like classes and functions should
+use Google naming. Be sure to use the base namespace.
diff --git a/base/functional/identity.h b/base/functional/identity.h
new file mode 100644
index 0000000..454f30af
--- /dev/null
+++ b/base/functional/identity.h
@@ -0,0 +1,28 @@
+// 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 BASE_FUNCTIONAL_IDENTITY_H_
+#define BASE_FUNCTIONAL_IDENTITY_H_
+
+#include <utility>
+
+namespace base {
+
+// Implementation of C++20's std::identity.
+//
+// Reference:
+// - https://en.cppreference.com/w/cpp/utility/functional/identity
+// - https://wg21.link/func.identity
+struct identity {
+  template <typename T>
+  constexpr T&& operator()(T&& t) const noexcept {
+    return std::forward<T>(t);
+  }
+
+  using is_transparent = void;
+};
+
+}  // namespace base
+
+#endif  // BASE_FUNCTIONAL_IDENTITY_H_
diff --git a/base/functional/identity_unittest.cc b/base/functional/identity_unittest.cc
new file mode 100644
index 0000000..ade33eb
--- /dev/null
+++ b/base/functional/identity_unittest.cc
@@ -0,0 +1,23 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/functional/identity.h"
+
+#include <vector>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(FunctionalTest, Identity) {
+  static constexpr identity id;
+
+  std::vector<int> v;
+  EXPECT_EQ(&v, &id(v));
+
+  constexpr int arr = {0};
+  static_assert(arr == id(arr), "");
+}
+
+}  // namespace base
diff --git a/base/functional/invoke.h b/base/functional/invoke.h
new file mode 100644
index 0000000..e936450
--- /dev/null
+++ b/base/functional/invoke.h
@@ -0,0 +1,152 @@
+// 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 BASE_FUNCTIONAL_INVOKE_H_
+#define BASE_FUNCTIONAL_INVOKE_H_
+
+#include <type_traits>
+#include <utility>
+
+namespace base {
+
+namespace internal {
+
+// Helper struct and alias to deduce the class type from a member function
+// pointer or member object pointer.
+template <typename DecayedF>
+struct member_pointer_class {};
+
+template <typename ReturnT, typename ClassT>
+struct member_pointer_class<ReturnT ClassT::*> {
+  using type = ClassT;
+};
+
+template <typename DecayedF>
+using member_pointer_class_t = typename member_pointer_class<DecayedF>::type;
+
+// Utility struct to detect specializations of std::reference_wrapper.
+template <typename T>
+struct is_reference_wrapper : std::false_type {};
+
+template <typename T>
+struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {};
+
+// Small helpers used below in internal::invoke to make the SFINAE more concise.
+template <typename F>
+const bool& IsMemFunPtr =
+    std::is_member_function_pointer<std::decay_t<F>>::value;
+
+template <typename F>
+const bool& IsMemObjPtr = std::is_member_object_pointer<std::decay_t<F>>::value;
+
+template <typename F,
+          typename T,
+          typename MemPtrClass = member_pointer_class_t<std::decay_t<F>>>
+const bool& IsMemPtrToBaseOf =
+    std::is_base_of<MemPtrClass, std::decay_t<T>>::value;
+
+template <typename T>
+const bool& IsRefWrapper = is_reference_wrapper<std::decay_t<T>>::value;
+
+template <bool B>
+using EnableIf = std::enable_if_t<B, bool>;
+
+// Invokes a member function pointer on a reference to an object of a suitable
+// type. Covers bullet 1 of the INVOKE definition.
+//
+// Reference: https://wg21.link/func.require#1.1
+template <typename F,
+          typename T1,
+          typename... Args,
+          EnableIf<IsMemFunPtr<F> && IsMemPtrToBaseOf<F, T1>> = true>
+constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) {
+  return (std::forward<T1>(t1).*f)(std::forward<Args>(args)...);
+}
+
+// Invokes a member function pointer on a std::reference_wrapper to an object of
+// a suitable type. Covers bullet 2 of the INVOKE definition.
+//
+// Reference: https://wg21.link/func.require#1.2
+template <typename F,
+          typename T1,
+          typename... Args,
+          EnableIf<IsMemFunPtr<F> && IsRefWrapper<T1>> = true>
+constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) {
+  return (t1.get().*f)(std::forward<Args>(args)...);
+}
+
+// Invokes a member function pointer on a pointer-like type to an object of a
+// suitable type. Covers bullet 3 of the INVOKE definition.
+//
+// Reference: https://wg21.link/func.require#1.3
+template <typename F,
+          typename T1,
+          typename... Args,
+          EnableIf<IsMemFunPtr<F> && !IsMemPtrToBaseOf<F, T1> &&
+                   !IsRefWrapper<T1>> = true>
+constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) {
+  return ((*std::forward<T1>(t1)).*f)(std::forward<Args>(args)...);
+}
+
+// Invokes a member object pointer on a reference to an object of a suitable
+// type. Covers bullet 4 of the INVOKE definition.
+//
+// Reference: https://wg21.link/func.require#1.4
+template <typename F,
+          typename T1,
+          EnableIf<IsMemObjPtr<F> && IsMemPtrToBaseOf<F, T1>> = true>
+constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) {
+  return std::forward<T1>(t1).*f;
+}
+
+// Invokes a member object pointer on a std::reference_wrapper to an object of
+// a suitable type. Covers bullet 5 of the INVOKE definition.
+//
+// Reference: https://wg21.link/func.require#1.5
+template <typename F,
+          typename T1,
+          EnableIf<IsMemObjPtr<F> && IsRefWrapper<T1>> = true>
+constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) {
+  return t1.get().*f;
+}
+
+// Invokes a member object pointer on a pointer-like type to an object of a
+// suitable type. Covers bullet 6 of the INVOKE definition.
+//
+// Reference: https://wg21.link/func.require#1.6
+template <typename F,
+          typename T1,
+          EnableIf<IsMemObjPtr<F> && !IsMemPtrToBaseOf<F, T1> &&
+                   !IsRefWrapper<T1>> = true>
+constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) {
+  return (*std::forward<T1>(t1)).*f;
+}
+
+// Invokes a regular function or function object. Covers bullet 7 of the INVOKE
+// definition.
+//
+// Reference: https://wg21.link/func.require#1.7
+template <typename F, typename... Args>
+constexpr decltype(auto) InvokeImpl(F&& f, Args&&... args) {
+  return std::forward<F>(f)(std::forward<Args>(args)...);
+}
+
+}  // namespace internal
+
+// Implementation of C++17's std::invoke. This is not based on implementation
+// referenced in original std::invoke proposal, but rather a manual
+// implementation, so that it can be constexpr.
+//
+// References:
+// - https://wg21.link/n4169#implementability
+// - https://en.cppreference.com/w/cpp/utility/functional/invoke
+// - https://wg21.link/func.invoke
+template <typename F, typename... Args>
+constexpr decltype(auto) invoke(F&& f, Args&&... args) {
+  return internal::InvokeImpl(std::forward<F>(f), std::forward<Args>(args)...);
+}
+
+}  // namespace base
+
+#endif  // BASE_FUNCTIONAL_INVOKE_H_
diff --git a/base/functional/invoke_unittest.cc b/base/functional/invoke_unittest.cc
new file mode 100644
index 0000000..b1babb96
--- /dev/null
+++ b/base/functional/invoke_unittest.cc
@@ -0,0 +1,34 @@
+// 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/functional/invoke.h"
+
+#include <functional>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(FunctionalTest, Invoke) {
+  struct S {
+    int i;
+    constexpr int add(int x) const { return i + x; }
+  };
+
+  constexpr S s = {1};
+
+  // Note: The tests involving a std::reference_wrapper are not static_asserts,
+  // since std::reference_wrapper is not constexpr prior to C++20.
+  static_assert(base::invoke(&S::add, s, 2) == 3, "");
+  EXPECT_EQ(base::invoke(&S::add, std::ref(s), 2), 3);
+  static_assert(base::invoke(&S::add, &s, 3) == 4, "");
+
+  static_assert(base::invoke(&S::i, s) == 1, "");
+  EXPECT_EQ(base::invoke(&S::i, std::ref(s)), 1);
+  static_assert(base::invoke(&S::i, &s) == 1, "");
+
+  static_assert(base::invoke(std::plus<>(), 1, 2) == 3, "");
+}
+
+}  // namespace base
diff --git a/base/functional/not_fn.h b/base/functional/not_fn.h
new file mode 100644
index 0000000..bd5f34b
--- /dev/null
+++ b/base/functional/not_fn.h
@@ -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.
+
+#ifndef BASE_FUNCTIONAL_NOT_FN_H_
+#define BASE_FUNCTIONAL_NOT_FN_H_
+
+#include <type_traits>
+#include <utility>
+
+#include "base/functional/invoke.h"
+
+namespace base {
+
+namespace internal {
+
+template <typename F>
+struct NotFnImpl {
+  F f;
+
+  template <typename... Args>
+  constexpr decltype(auto) operator()(Args&&... args) & noexcept {
+    return !base::invoke(f, std::forward<Args>(args)...);
+  }
+
+  template <typename... Args>
+  constexpr decltype(auto) operator()(Args&&... args) const& noexcept {
+    return !base::invoke(f, std::forward<Args>(args)...);
+  }
+
+  template <typename... Args>
+  constexpr decltype(auto) operator()(Args&&... args) && noexcept {
+    return !base::invoke(std::move(f), std::forward<Args>(args)...);
+  }
+
+  template <typename... Args>
+  constexpr decltype(auto) operator()(Args&&... args) const&& noexcept {
+    return !base::invoke(std::move(f), std::forward<Args>(args)...);
+  }
+};
+
+}  // namespace internal
+
+// Implementation of C++17's std::not_fn.
+//
+// Reference:
+// - https://en.cppreference.com/w/cpp/utility/functional/not_fn
+// - https://wg21.link/func.not.fn
+template <typename F>
+constexpr internal::NotFnImpl<std::decay_t<F>> not_fn(F&& f) {
+  return {std::forward<F>(f)};
+}
+
+}  // namespace base
+
+#endif  // BASE_FUNCTIONAL_NOT_FN_H_
diff --git a/base/functional/not_fn_unittest.cc b/base/functional/not_fn_unittest.cc
new file mode 100644
index 0000000..6d1c800
--- /dev/null
+++ b/base/functional/not_fn_unittest.cc
@@ -0,0 +1,23 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/functional/not_fn.h"
+
+#include <functional>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(FunctionalTest, NotFn) {
+  constexpr auto not_less = base::not_fn(std::less<>());
+
+  using NotLessT = decltype(not_less);
+  static_assert(static_cast<const NotLessT&>(not_less)(1, 1), "");
+  static_assert(static_cast<NotLessT&>(not_less)(2, 1), "");
+  static_assert(static_cast<const NotLessT&&>(not_less)(2, 2), "");
+  static_assert(!static_cast<NotLessT&&>(not_less)(1, 2), "");
+}
+
+}  // namespace base
diff --git a/base/ranges/algorithm.h b/base/ranges/algorithm.h
index 7dd66bce71..9bdafd8f 100644
--- a/base/ranges/algorithm.h
+++ b/base/ranges/algorithm.h
@@ -11,9 +11,10 @@
 #include <type_traits>
 #include <utility>
 
+#include "base/functional/identity.h"
+#include "base/functional/invoke.h"
 #include "base/ranges/functional.h"
 #include "base/ranges/ranges.h"
-#include "base/stl_util.h"
 #include "base/template_util.h"
 
 namespace base {
diff --git a/base/stl_util.h b/base/stl_util.h
index cfab6e1..024e1e0 100644
--- a/base/stl_util.h
+++ b/base/stl_util.h
@@ -171,157 +171,6 @@
 template <typename T>
 void as_const(const T&& t) = delete;
 
-namespace internal {
-
-// Helper struct and alias to deduce the class type from a member function
-// pointer or member object pointer.
-template <typename DecayedF>
-struct member_pointer_class {};
-
-template <typename ReturnT, typename ClassT>
-struct member_pointer_class<ReturnT ClassT::*> {
-  using type = ClassT;
-};
-
-template <typename DecayedF>
-using member_pointer_class_t = typename member_pointer_class<DecayedF>::type;
-
-// Utility struct to detect specializations of std::reference_wrapper.
-template <typename T>
-struct is_reference_wrapper : std::false_type {};
-
-template <typename T>
-struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {};
-
-// Small helpers used below in internal::invoke to make the SFINAE more concise.
-template <typename F>
-const bool& IsMemFunPtr =
-    std::is_member_function_pointer<std::decay_t<F>>::value;
-
-template <typename F>
-const bool& IsMemObjPtr = std::is_member_object_pointer<std::decay_t<F>>::value;
-
-template <typename F,
-          typename T,
-          typename MemPtrClass = member_pointer_class_t<std::decay_t<F>>>
-const bool& IsMemPtrToBaseOf =
-    std::is_base_of<MemPtrClass, std::decay_t<T>>::value;
-
-template <typename T>
-const bool& IsRefWrapper = is_reference_wrapper<std::decay_t<T>>::value;
-
-template <bool B>
-using EnableIf = std::enable_if_t<B, bool>;
-
-// Invokes a member function pointer on a reference to an object of a suitable
-// type. Covers bullet 1 of the INVOKE definition.
-//
-// Reference: https://wg21.link/func.require#1.1
-template <typename F,
-          typename T1,
-          typename... Args,
-          EnableIf<IsMemFunPtr<F> && IsMemPtrToBaseOf<F, T1>> = true>
-constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) {
-  return (std::forward<T1>(t1).*f)(std::forward<Args>(args)...);
-}
-
-// Invokes a member function pointer on a std::reference_wrapper to an object of
-// a suitable type. Covers bullet 2 of the INVOKE definition.
-//
-// Reference: https://wg21.link/func.require#1.2
-template <typename F,
-          typename T1,
-          typename... Args,
-          EnableIf<IsMemFunPtr<F> && IsRefWrapper<T1>> = true>
-constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) {
-  return (t1.get().*f)(std::forward<Args>(args)...);
-}
-
-// Invokes a member function pointer on a pointer-like type to an object of a
-// suitable type. Covers bullet 3 of the INVOKE definition.
-//
-// Reference: https://wg21.link/func.require#1.3
-template <typename F,
-          typename T1,
-          typename... Args,
-          EnableIf<IsMemFunPtr<F> && !IsMemPtrToBaseOf<F, T1> &&
-                   !IsRefWrapper<T1>> = true>
-constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) {
-  return ((*std::forward<T1>(t1)).*f)(std::forward<Args>(args)...);
-}
-
-// Invokes a member object pointer on a reference to an object of a suitable
-// type. Covers bullet 4 of the INVOKE definition.
-//
-// Reference: https://wg21.link/func.require#1.4
-template <typename F,
-          typename T1,
-          EnableIf<IsMemObjPtr<F> && IsMemPtrToBaseOf<F, T1>> = true>
-constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) {
-  return std::forward<T1>(t1).*f;
-}
-
-// Invokes a member object pointer on a std::reference_wrapper to an object of
-// a suitable type. Covers bullet 5 of the INVOKE definition.
-//
-// Reference: https://wg21.link/func.require#1.5
-template <typename F,
-          typename T1,
-          EnableIf<IsMemObjPtr<F> && IsRefWrapper<T1>> = true>
-constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) {
-  return t1.get().*f;
-}
-
-// Invokes a member object pointer on a pointer-like type to an object of a
-// suitable type. Covers bullet 6 of the INVOKE definition.
-//
-// Reference: https://wg21.link/func.require#1.6
-template <typename F,
-          typename T1,
-          EnableIf<IsMemObjPtr<F> && !IsMemPtrToBaseOf<F, T1> &&
-                   !IsRefWrapper<T1>> = true>
-constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) {
-  return (*std::forward<T1>(t1)).*f;
-}
-
-// Invokes a regular function or function object. Covers bullet 7 of the INVOKE
-// definition.
-//
-// Reference: https://wg21.link/func.require#1.7
-template <typename F, typename... Args>
-constexpr decltype(auto) InvokeImpl(F&& f, Args&&... args) {
-  return std::forward<F>(f)(std::forward<Args>(args)...);
-}
-
-}  // namespace internal
-
-// Implementation of C++17's std::invoke. This is not based on implementation
-// referenced in original std::invoke proposal, but rather a manual
-// implementation, so that it can be constexpr.
-//
-// References:
-// - https://wg21.link/n4169#implementability
-// - https://en.cppreference.com/w/cpp/utility/functional/invoke
-// - https://wg21.link/func.invoke
-template <typename F, typename... Args>
-constexpr decltype(auto) invoke(F&& f, Args&&... args) {
-  return internal::InvokeImpl(std::forward<F>(f), std::forward<Args>(args)...);
-}
-
-// Implementation of C++20's std::identity.
-//
-// Reference:
-// - https://en.cppreference.com/w/cpp/utility/functional/identity
-// - https://wg21.link/func.identity
-struct identity {
-  template <typename T>
-  constexpr T&& operator()(T&& t) const noexcept {
-    return std::forward<T>(t);
-  }
-
-  using is_transparent = void;
-};
-
 // Simplified C++14 implementation of  C++20's std::to_address.
 // Note: This does not consider specializations of pointer_traits<>::to_address,
 // since that member function may only be present in C++20 and later.
diff --git a/base/stl_util_unittest.cc b/base/stl_util_unittest.cc
index 25c923da..55980a51 100644
--- a/base/stl_util_unittest.cc
+++ b/base/stl_util_unittest.cc
@@ -289,37 +289,6 @@
                 "Error: base::as_const() returns an unexpected type");
 }
 
-TEST(STLUtilTest, Invoke) {
-  struct S {
-    int i;
-    constexpr int add(int x) const { return i + x; }
-  };
-
-  constexpr S s = {1};
-
-  // Note: The tests involving a std::reference_wrapper are not static_asserts,
-  // since std::reference_wrapper is not constexpr prior to C++20.
-  static_assert(invoke(&S::add, s, 2) == 3, "");
-  EXPECT_EQ(invoke(&S::add, std::ref(s), 2), 3);
-  static_assert(invoke(&S::add, &s, 3) == 4, "");
-
-  static_assert(invoke(&S::i, s) == 1, "");
-  EXPECT_EQ(invoke(&S::i, std::ref(s)), 1);
-  static_assert(invoke(&S::i, &s) == 1, "");
-
-  static_assert(invoke(std::plus<>(), 1, 2) == 3, "");
-}
-
-TEST(STLUtilTest, Identity) {
-  static constexpr identity id;
-
-  std::vector<int> v;
-  EXPECT_EQ(&v, &id(v));
-
-  constexpr int arr = {0};
-  static_assert(arr == id(arr), "");
-}
-
 TEST(STLUtilTest, GetUnderlyingContainer) {
   {
     std::queue<int> queue({1, 2, 3, 4, 5});
diff --git a/build/android/gyp/aar.py b/build/android/gyp/aar.py
index a6736f6..4065b6d 100755
--- a/build/android/gyp/aar.py
+++ b/build/android/gyp/aar.py
@@ -23,18 +23,7 @@
 import gn_helpers
 
 
-# Regular expression to extract -checkdiscard / -check* lines.
-# Example patterns:
-# -checkdiscard @com.Foo class *
-# -checkdiscard class ** {
-#  ...
-# }
-# Does not support nested comments with "}" in them (oh well).
-_CHECKDISCARD_PATTERN = re.compile(r'^[ \t\r\f\v]*-check[^{\n]*({.*?})?\s*',
-                                   re.DOTALL | re.MULTILINE)
-
 _PROGUARD_TXT = 'proguard.txt'
-_PROGUARD_CHECKS_TXT = 'proguard-checks.txt'
 
 
 def _GetManifestPackage(doc):
@@ -125,33 +114,10 @@
         # have no resources as well. We treat empty R.txt as having no R.txt.
         data['has_r_text_file'] = bool(z.read('R.txt').strip())
 
-    if data['has_proguard_flags']:
-      config = z.read(_PROGUARD_TXT)
-      if _CHECKDISCARD_PATTERN.search(config):
-        data['has_proguard_check_flags'] = True
-
   return data
 
 
-def _SplitProguardConfig(tmp_dir):
-  # Put -checkdiscard (and friends) into a separate proguard config.
-  # https://crbug.com/1093831
-  main_flag_path = os.path.join(tmp_dir, _PROGUARD_TXT)
-  check_flag_path = os.path.join(tmp_dir, _PROGUARD_CHECKS_TXT)
-  with open(main_flag_path) as f:
-    config_data = f.read()
-  with open(main_flag_path, 'w') as f:
-    MSG = ('# Check flag moved to proguard-checks.txt by '
-           '//build/android/gyp/aar.py\n')
-    f.write(_CHECKDISCARD_PATTERN.sub(MSG, config_data))
-  with open(check_flag_path, 'w') as f:
-    f.write('# Check flags extracted by //build/android/gyp/aar.py\n\n')
-    for m in _CHECKDISCARD_PATTERN.finditer(config_data):
-      f.write(m.group(0))
-
-
-def _PerformExtract(aar_file, output_dir, name_allowlist,
-                    has_proguard_check_flags):
+def _PerformExtract(aar_file, output_dir, name_allowlist):
   with build_utils.TempDir() as tmp_dir:
     tmp_dir = os.path.join(tmp_dir, 'staging')
     os.mkdir(tmp_dir)
@@ -161,9 +127,6 @@
     with open(os.path.join(tmp_dir, 'source.info'), 'w') as f:
       f.write('source={}\n'.format(aar_file))
 
-    if has_proguard_check_flags:
-      _SplitProguardConfig(tmp_dir)
-
     shutil.rmtree(output_dir, ignore_errors=True)
     shutil.move(tmp_dir, output_dir)
 
@@ -211,24 +174,22 @@
     if args.assert_info_file:
       cached_info = args.assert_info_file.read()
       if formatted_info != cached_info:
-        raise Exception('android_aar_prebuilt() cached .info file is '
-                        'out-of-date. Run gn gen with '
-                        'update_android_aar_prebuilts=true to update it.')
+        pass
+        # TODO(smaier) - uncomment this as soon as possible.
+        #raise Exception('android_aar_prebuilt() cached .info file is '
+        #                'out-of-date. Run gn gen with '
+        #                'update_android_aar_prebuilts=true to update it.')
 
     with zipfile.ZipFile(args.aar_file) as zf:
       names = zf.namelist()
       if args.ignore_resources:
         names = [n for n in names if not n.startswith('res')]
 
-    has_proguard_check_flags = aar_info.get('has_proguard_check_flags')
     output_paths = [os.path.join(args.output_dir, n) for n in names]
     output_paths.append(os.path.join(args.output_dir, 'source.info'))
-    if has_proguard_check_flags:
-      output_paths.append(os.path.join(args.output_dir, _PROGUARD_CHECKS_TXT))
 
     def on_stale_md5():
-      _PerformExtract(args.aar_file, args.output_dir, set(names),
-                      has_proguard_check_flags)
+      _PerformExtract(args.aar_file, args.output_dir, set(names))
 
     md5_check.CallAndRecordIfStale(on_stale_md5,
                                    input_strings=[aar_info],
diff --git a/build/android/gyp/proguard.py b/build/android/gyp/proguard.py
index 24044a8..0fbc0b5a 100755
--- a/build/android/gyp/proguard.py
+++ b/build/android/gyp/proguard.py
@@ -29,45 +29,6 @@
     (29, 'Q'),
     (30, 'R'),
 ]
-_CHECKDISCARD_RE = re.compile(r'^[ \t\r\f\v]*-checkdiscard[^\n{]*({[\s\S]*?})?',
-                              re.MULTILINE)
-# Ignore remaining directives that start with -check, as they're not supported
-# by R8 anyway.
-_DIRECTIVE_RE = re.compile(r'^\s*-(?<!check)[a-zA-Z].*')
-
-
-def _ValidateAndFilterCheckDiscards(configs):
-  """Check for invalid -checkdiscard rules and filter out -checkdiscards.
-
-  -checkdiscard assertions often don't work for test APKs and are not actually
-  helpful. Additionally, test APKs may pull in dependency proguard configs which
-  makes filtering out these rules difficult in GN. Instead, we enforce that
-  configs that use -checkdiscard do not contain any other rules so that we can
-  filter out the undesired -checkdiscard rule files here.
-
-  Args:
-    configs: List of paths to proguard configuration files.
-
-  Returns:
-    A list of configs with -checkdiscard-containing-configs removed.
-  """
-  valid_configs = []
-  for config_path in configs:
-    with open(config_path) as f:
-      contents = f.read()
-      if _CHECKDISCARD_RE.search(contents):
-        contents = _CHECKDISCARD_RE.sub('', contents)
-        directive_match = _DIRECTIVE_RE.search(contents)
-        if directive_match:
-          raise Exception(
-              'Proguard configs containing -checkdiscards cannot '
-              'contain other directives so that they can be '
-              'disabled in test APKs ({}). Directive "{}" found.'.format(
-                  config_path, directive_match.group()))
-      else:
-        valid_configs.append(config_path)
-
-  return valid_configs
 
 
 def _ParseOptions():
@@ -270,6 +231,15 @@
         tmp_mapping_path,
     ]
 
+    if options.disable_checkdiscard:
+      # Info level priority logs are not printed by default.
+      cmd += [
+          '--map-diagnostics:'
+          'com.android.tools.r8.errors.CheckDiscardDiagnostic',
+          'error',
+          'info',
+      ]
+
     if options.desugar_jdk_libs_json:
       cmd += [
           '--desugared-lib',
@@ -461,8 +431,6 @@
   _VerifyNoEmbeddedConfigs(options.input_paths + libraries)
 
   proguard_configs = options.proguard_configs
-  if options.disable_checkdiscard:
-    proguard_configs = _ValidateAndFilterCheckDiscards(proguard_configs)
 
   # ProGuard configs that are derived from flags.
   dynamic_config_data = _CreateDynamicConfig(options)
diff --git a/build/config/android/config.gni b/build/config/android/config.gni
index bc176d5..4c363465c 100644
--- a/build/config/android/config.gni
+++ b/build/config/android/config.gni
@@ -255,7 +255,7 @@
 
     # Enables Java library desugaring.
     # This will cause an extra classes.dex file to appear in every apk.
-    enable_jdk_library_desugaring = true
+    enable_jdk_library_desugaring = false
   }
 
   # Host stuff -----------------------------------------------------------------
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 869e521..c7315ea 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -4258,10 +4258,6 @@
         if (_scanned_files.has_proguard_flags) {
           outputs += [ "${_output_path}/proguard.txt" ]
         }
-        if (defined(_scanned_files.has_proguard_check_flags) &&
-            _scanned_files.has_proguard_check_flags) {
-          outputs += [ "${_output_path}/proguard-checks.txt" ]
-        }
       }
 
       if (_extract_native_libraries && _scanned_files.has_native_libraries) {
@@ -4418,10 +4414,6 @@
           if (_scanned_files.has_proguard_flags) {
             proguard_configs += [ "$_output_path/proguard.txt" ]
           }
-          if (defined(_scanned_files.has_proguard_check_flags) &&
-              _scanned_files.has_proguard_check_flags) {
-            proguard_configs += [ "$_output_path/proguard-checks.txt" ]
-          }
         }
         public_target_label = invoker.target_name
       }
diff --git a/build/config/ios/asset_catalog.gni b/build/config/ios/asset_catalog.gni
index 6013def..84dd92c 100644
--- a/build/config/ios/asset_catalog.gni
+++ b/build/config/ios/asset_catalog.gni
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/ios/ios_sdk.gni")
+
 # This template declares a bundle_data target that references an asset
 # catalog so that it is compiled to the asset catalog of the generated
 # bundle.
@@ -46,9 +48,9 @@
   assert(defined(invoker.asset_type) && invoker.asset_type != "",
          "asset_type must be defined and not empty for $target_name")
 
-  if (current_toolchain != default_toolchain) {
+  if (is_fat_secondary_toolchain) {
     group(target_name) {
-      public_deps = [ ":$target_name($default_toolchain)" ]
+      public_deps = [ ":$target_name($primary_fat_toolchain_name)" ]
     }
   } else {
     _copy_target_name = target_name + "__copy"
diff --git a/build/config/ios/ios_sdk.gni b/build/config/ios/ios_sdk.gni
index 93808505..09caa60 100644
--- a/build/config/ios/ios_sdk.gni
+++ b/build/config/ios/ios_sdk.gni
@@ -68,6 +68,16 @@
   target_environment = ""
 }
 
+declare_args() {
+  # This variable is set by the toolchain. It is set to true if the toolchain
+  # is a secondary toolchain as part of a "fat" build.
+  is_fat_secondary_toolchain = false
+
+  # This variable is set by the toolchain. It is the name of the primary
+  # toolchain for the fat build (could be current_toolchain).
+  primary_fat_toolchain_name = ""
+}
+
 if (target_environment == "") {
   if (current_cpu == "x86" || current_cpu == "x64") {
     target_environment = "simulator"
@@ -108,7 +118,7 @@
     assert(_additional_target_cpu != target_cpu,
            "target_cpu must not be listed in additional_target_cpus")
 
-    _toolchain = "//build/toolchain/mac:ios_clang_$_additional_target_cpu"
+    _toolchain = "//build/toolchain/mac:ios_clang_${_additional_target_cpu}_fat"
     foreach(_additional_toolchain, additional_toolchains) {
       assert(_toolchain != _additional_toolchain,
              "additional_target_cpus must not contains duplicate values")
diff --git a/build/config/ios/rules.gni b/build/config/ios/rules.gni
index 2076043..f2d97a28 100644
--- a/build/config/ios/rules.gni
+++ b/build/config/ios/rules.gni
@@ -602,6 +602,11 @@
     _output_name = invoker.output_name
   }
 
+  _primary_toolchain = current_toolchain
+  if (is_fat_secondary_toolchain) {
+    _primary_toolchain = primary_fat_toolchain_name
+  }
+
   assert(
       !defined(invoker.bundle_extension),
       "bundle_extension must not be set for ios_app_bundle template for $target_name")
@@ -681,11 +686,10 @@
     visibility = [ ":$_arch_executable_target" ]
   }
 
-  if (current_toolchain == default_toolchain ||
-      target_environment == "simulator") {
+  if (!is_fat_secondary_toolchain || target_environment == "simulator") {
     _generate_entitlements_target = _target_name + "_gen_entitlements"
     _generate_entitlements_output =
-        get_label_info(":$_generate_entitlements_target($default_toolchain)",
+        get_label_info(":$_generate_entitlements_target($_primary_toolchain)",
                        "target_out_dir") + "/$_output_name.xcent"
   }
 
@@ -724,8 +728,8 @@
                              "visibility",
                            ])
 
-    visibility = [ ":$_lipo_executable_target($default_toolchain)" ]
-    if (current_toolchain != default_toolchain) {
+    visibility = [ ":$_lipo_executable_target($_primary_toolchain)" ]
+    if (is_fat_secondary_toolchain) {
       visibility += [ ":$_target_name" ]
     }
 
@@ -740,7 +744,7 @@
     frameworks += [ "UIKit.framework" ]
 
     if (target_environment == "simulator") {
-      deps += [ ":$_generate_entitlements_target($default_toolchain)" ]
+      deps += [ ":$_generate_entitlements_target($_primary_toolchain)" ]
 
       if (!defined(inputs)) {
         inputs = []
@@ -759,7 +763,7 @@
     output_dir = "$target_out_dir/$current_cpu"
   }
 
-  if (current_toolchain != default_toolchain) {
+  if (is_fat_secondary_toolchain) {
     # For fat builds, only the default toolchain will generate an application
     # bundle. For the other toolchains, the template is only used for building
     # the arch-specific binary, thus the default target is just a group().
@@ -802,7 +806,7 @@
       executable_name = _output_name
     }
 
-    if (current_toolchain == default_toolchain) {
+    if (!is_fat_secondary_toolchain) {
       if (!defined(invoker.entitlements_target)) {
         _entitlements_path = "//build/config/ios/entitlements.plist"
         if (defined(invoker.entitlements_path)) {
@@ -942,7 +946,7 @@
     }
   }
 
-  if (current_toolchain != default_toolchain) {
+  if (is_fat_secondary_toolchain) {
     not_needed("*")
   }
 }
@@ -1247,13 +1251,18 @@
   _has_public_headers =
       defined(invoker.public_headers) && invoker.public_headers != []
 
+  _primary_toolchain = current_toolchain
+  if (is_fat_secondary_toolchain) {
+    _primary_toolchain = primary_fat_toolchain_name
+  }
+
   # Public configs are not propagated across toolchain (see crbug.com/675224)
   # so some configs have to be defined for both default_toolchain and all others
   # toolchains when performing a fat build. Use "get_label_info" to construct
   # the path since they need to be relative to the default_toolchain.
 
   _default_toolchain_root_out_dir =
-      get_label_info("$_target_name($default_toolchain)", "root_out_dir")
+      get_label_info("$_target_name($_primary_toolchain)", "root_out_dir")
 
   _arch_shared_library_source = _target_name + "_arch_shared_library_sources"
   _arch_shared_library_target = _target_name + "_arch_shared_library"
@@ -1262,7 +1271,7 @@
 
   if (_has_public_headers) {
     _default_toolchain_target_gen_dir =
-        get_label_info("$_target_name($default_toolchain)", "target_gen_dir")
+        get_label_info("$_target_name($_primary_toolchain)", "target_gen_dir")
 
     _framework_headers_target = _target_name + "_framework_headers"
 
@@ -1313,7 +1322,7 @@
       if (!defined(deps)) {
         deps = []
       }
-      deps += [ ":$_framework_headers_target($default_toolchain)" ]
+      deps += [ ":$_framework_headers_target($_primary_toolchain)" ]
     }
   }
 
@@ -1334,8 +1343,8 @@
                              "visibility",
                            ])
 
-    visibility = [ ":$_lipo_shared_library_target($default_toolchain)" ]
-    if (current_toolchain != default_toolchain) {
+    visibility = [ ":$_lipo_shared_library_target($_primary_toolchain)" ]
+    if (is_fat_secondary_toolchain) {
       visibility += [
         ":${_target_name}",
         ":${_target_name}_signed_bundle",
@@ -1347,7 +1356,7 @@
     }
     deps += [ ":$_arch_shared_library_source" ]
     if (_has_public_headers) {
-      deps += [ ":$_framework_headers_target($default_toolchain)" ]
+      deps += [ ":$_framework_headers_target($_primary_toolchain)" ]
     }
     if (!defined(ldflags)) {
       ldflags = []
@@ -1361,7 +1370,7 @@
     output_dir = "$target_out_dir/$current_cpu"
   }
 
-  if (current_toolchain != default_toolchain) {
+  if (is_fat_secondary_toolchain) {
     # For fat builds, only the default toolchain will generate a framework
     # bundle. For the other toolchains, the template is only used for building
     # the arch-specific binary, thus the default target is just a group().
@@ -1382,7 +1391,7 @@
                                "visibility",
                                "testonly",
                              ])
-      public_deps = [ ":$_link_target_name($default_toolchain)" ]
+      public_deps = [ ":$_link_target_name($_primary_toolchain)" ]
 
       if (_has_public_headers) {
         if (!defined(public_configs)) {
@@ -1398,7 +1407,7 @@
 
     group("$_target_name+bundle") {
       forward_variables_from(invoker, [ "testonly" ])
-      public_deps = [ ":$_target_name+bundle($default_toolchain)" ]
+      public_deps = [ ":$_target_name+bundle($_primary_toolchain)" ]
     }
 
     not_needed(invoker, "*")
@@ -1408,9 +1417,9 @@
 
       _framework_root_dir = "$root_out_dir/$_output_name.framework"
       if (target_environment == "simulator" || target_environment == "device") {
-        _frameworks_content_dir = _framework_root_dir
+        _framework_contents_dir = _framework_root_dir
       } else if (target_environment == "catalyst") {
-        _frameworks_content_dir = "$_framework_root_dir/Versions/A"
+        _framework_contents_dir = "$_framework_root_dir/Versions/A"
       }
 
       _compile_headers_map_target = _target_name + "_compile_headers_map"
@@ -1446,10 +1455,10 @@
       action(_create_module_map_target) {
         visibility = [ ":$_framework_headers_target" ]
         script = "//build/config/ios/write_framework_modulemap.py"
-        outputs = [ "$_frameworks_content_dir/Modules/module.modulemap" ]
+        outputs = [ "$_framework_contents_dir/Modules/module.modulemap" ]
         args = [
           _output_name,
-          rebase_path("$_frameworks_content_dir/Modules", root_build_dir),
+          rebase_path("$_framework_contents_dir/Modules", root_build_dir),
         ]
       }
 
@@ -1462,7 +1471,7 @@
                                ])
         visibility = [ ":$_framework_headers_target" ]
         sources = _public_headers
-        outputs = [ "$_frameworks_content_dir/Headers/{{source_file_part}}" ]
+        outputs = [ "$_framework_contents_dir/Headers/{{source_file_part}}" ]
 
         # Do not use forward_variables_from for "public_deps" as
         # we do not want to forward those dependencies.
@@ -1658,7 +1667,7 @@
   # Silence "assignment had no effect" error for non-default toolchains as
   # following variables are only used in the expansion of the template for the
   # default toolchain.
-  if (current_toolchain != default_toolchain) {
+  if (is_fat_secondary_toolchain) {
     not_needed(invoker, "*")
   }
 
@@ -1673,6 +1682,11 @@
   _arch_loadable_module_target = _target_name + "_arch_loadable_module"
   _lipo_loadable_module_target = _target_name + "_loadable_module"
 
+  _primary_toolchain = current_toolchain
+  if (is_fat_secondary_toolchain) {
+    _primary_toolchain = primary_fat_toolchain_name
+  }
+
   source_set(_arch_loadable_module_source) {
     forward_variables_from(invoker, [ "deps" ])
 
@@ -1682,8 +1696,8 @@
 
   loadable_module(_arch_loadable_module_target) {
     testonly = true
-    visibility = [ ":$_lipo_loadable_module_target($default_toolchain)" ]
-    if (current_toolchain != default_toolchain) {
+    visibility = [ ":$_lipo_loadable_module_target($_primary_toolchain)" ]
+    if (is_fat_secondary_toolchain) {
       visibility += [ ":$_target_name" ]
     }
 
@@ -1696,7 +1710,7 @@
     output_extension = ""
   }
 
-  if (current_toolchain != default_toolchain) {
+  if (is_fat_secondary_toolchain) {
     # For fat builds, only the default toolchain will generate a test bundle.
     # For the other toolchains, the template is only used for building the
     # arch-specific binary, thus the default target is just a group().
@@ -1888,7 +1902,7 @@
     ]
 
     _xctest_bundle = _xctest_target + "_bundle"
-    if (current_toolchain == default_toolchain) {
+    if (!is_fat_secondary_toolchain) {
       if (!defined(bundle_deps)) {
         bundle_deps = []
       }
diff --git a/build/toolchain/mac/BUILD.gn b/build/toolchain/mac/BUILD.gn
index a3eca611..09d922a 100644
--- a/build/toolchain/mac/BUILD.gn
+++ b/build/toolchain/mac/BUILD.gn
@@ -69,6 +69,7 @@
 tool_versions =
     exec_script("get_tool_mtime.py",
                 rebase_path([
+                              "//build/apple/swiftc.py",
                               "//build/config/ios/compile_xcassets.py",
                               "//build/toolchain/mac/filter_libtool.py",
                               "//build/toolchain/mac/linker_driver.py",
@@ -478,8 +479,13 @@
         partial_outputs = [ "$_objects_dir/{{source_name_part}}.o" ]
       }
 
+      _env_vars = "TOOL_VERSION=${tool_versions.swiftc}"
+      if (is_ios && ios_sdk_developer_dir != "") {
+        _env_vars += " DEVELOPER_DIR=$ios_sdk_developer_dir"
+      }
+
       command =
-          "$_tool -module-name {{module_name}} " +
+          "$_env_vars $_tool -module-name {{module_name}} " +
           "-object-dir $_objects_dir " +
           "-module-path {{target_gen_dir}}/{{module_name}}.swiftmodule " +
           "-header-path {{target_gen_dir}}/{{module_name}}.h " +
@@ -603,6 +609,21 @@
 }
 
 if (is_ios) {
+  mac_toolchain("ios_clang_arm64") {
+    toolchain_args = {
+      current_cpu = "arm64"
+      current_os = "ios"
+    }
+  }
+
+  mac_toolchain("ios_clang_arm64_14_0") {
+    toolchain_args = {
+      current_cpu = "arm64"
+      current_os = "ios"
+      ios_deployment_target = "14.0"
+    }
+  }
+
   mac_toolchain("ios_clang_arm") {
     toolchain_args = {
       current_cpu = "arm"
@@ -610,10 +631,27 @@
     }
   }
 
-  mac_toolchain("ios_clang_arm64") {
+  mac_toolchain("ios_clang_arm_fat") {
     toolchain_args = {
-      current_cpu = "arm64"
+      current_cpu = "arm"
       current_os = "ios"
+      is_fat_secondary_toolchain = true
+      primary_fat_toolchain_name = "//build/toolchain/mac:ios_clang_arm64"
+    }
+  }
+
+  mac_toolchain("ios_clang_x64") {
+    toolchain_args = {
+      current_cpu = "x64"
+      current_os = "ios"
+    }
+  }
+
+  mac_toolchain("ios_clang_x64_14_0") {
+    toolchain_args = {
+      current_cpu = "x64"
+      current_os = "ios"
+      ios_deployment_target = "14.0"
     }
   }
 
@@ -624,10 +662,12 @@
     }
   }
 
-  mac_toolchain("ios_clang_x64") {
+  mac_toolchain("ios_clang_x86_fat") {
     toolchain_args = {
-      current_cpu = "x64"
+      current_cpu = "x86"
       current_os = "ios"
+      is_fat_secondary_toolchain = true
+      primary_fat_toolchain_name = "//build/toolchain/mac:ios_clang_x64"
     }
   }
 }
diff --git a/cc/test/fake_tile_manager_client.cc b/cc/test/fake_tile_manager_client.cc
index 75147a59..2f8e1425 100644
--- a/cc/test/fake_tile_manager_client.cc
+++ b/cc/test/fake_tile_manager_client.cc
@@ -43,4 +43,8 @@
   return 0;
 }
 
+bool FakeTileManagerClient::HasPendingTree() {
+  return true;
+}
+
 }  // namespace cc
diff --git a/cc/test/fake_tile_manager_client.h b/cc/test/fake_tile_manager_client.h
index c9c21b7..c636f84c 100644
--- a/cc/test/fake_tile_manager_client.h
+++ b/cc/test/fake_tile_manager_client.h
@@ -36,6 +36,7 @@
                                WhichTree tree) const override;
   int GetMSAASampleCountForRaster(
       const scoped_refptr<DisplayItemList>& display_list) override;
+  bool HasPendingTree() override;
 
  private:
   gfx::ColorSpace color_space_;
diff --git a/cc/tiles/tile_manager.cc b/cc/tiles/tile_manager.cc
index 8089c12..c6c7cd5b 100644
--- a/cc/tiles/tile_manager.cc
+++ b/cc/tiles/tile_manager.cc
@@ -1496,7 +1496,7 @@
   if (signals_.activate_tile_tasks_completed &&
       signals_.activate_gpu_work_completed &&
       !signals_.did_notify_ready_to_activate) {
-    if (IsReadyToActivate()) {
+    if (!client_->HasPendingTree() || IsReadyToActivate()) {
       TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
                    "TileManager::IssueSignals - ready to activate");
       signals_.did_notify_ready_to_activate = true;
diff --git a/cc/tiles/tile_manager.h b/cc/tiles/tile_manager.h
index d29d365..0495ba08 100644
--- a/cc/tiles/tile_manager.h
+++ b/cc/tiles/tile_manager.h
@@ -104,6 +104,9 @@
   virtual int GetMSAASampleCountForRaster(
       const scoped_refptr<DisplayItemList>& display_list) = 0;
 
+  // True if there is a pending tree.
+  virtual bool HasPendingTree() = 0;
+
  protected:
   virtual ~TileManagerClient() {}
 };
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index eca1d1ab..84f938e 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -1851,6 +1851,10 @@
   return RequestedMSAASampleCount();
 }
 
+bool LayerTreeHostImpl::HasPendingTree() {
+  return pending_tree_ != nullptr;
+}
+
 void LayerTreeHostImpl::NotifyReadyToActivate() {
   // The TileManager may call this method while the pending tree is still being
   // painted, as it isn't aware of the ongoing paint. We shouldn't tell the
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index a70807f98b..39d321fbf 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -494,6 +494,8 @@
   int GetMSAASampleCountForRaster(
       const scoped_refptr<DisplayItemList>& display_list) override;
 
+  bool HasPendingTree() override;
+
   // ScrollbarAnimationControllerClient implementation.
   void PostDelayedScrollbarAnimationTask(base::OnceClosure task,
                                          base::TimeDelta delay) override;
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index d3e3007..22709e35 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -1086,6 +1086,7 @@
   "java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinator.java",
   "java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinatorPhone.java",
   "java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinatorTablet.java",
+  "java/src/org/chromium/chrome/browser/omnibox/LocationBarDataProvider.java",
   "java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java",
   "java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java",
   "java/src/org/chromium/chrome/browser/omnibox/LocationBarTablet.java",
@@ -1552,7 +1553,6 @@
   "java/src/org/chromium/chrome/browser/toolbar/ThemeColorProvider.java",
   "java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonInProductHelpController.java",
   "java/src/org/chromium/chrome/browser/toolbar/ToolbarColors.java",
-  "java/src/org/chromium/chrome/browser/toolbar/ToolbarCommonPropertiesModel.java",
   "java/src/org/chromium/chrome/browser/toolbar/ToolbarDataProvider.java",
   "java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java",
   "java/src/org/chromium/chrome/browser/toolbar/ToolbarProgressBar.java",
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/FeedRequestManagerImpl.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/FeedRequestManagerImpl.java
index 856cbe3..dc75e62 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/FeedRequestManagerImpl.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/FeedRequestManagerImpl.java
@@ -302,9 +302,13 @@
     private void logServerCapabilities(Response response, boolean isRefreshRequest) {
         FeedResponse feedResponse = response.getExtension(FeedResponse.feedResponse);
         List<Capability> capabilities = feedResponse.getServerCapabilitiesList();
+        boolean hasNoticeCard =
+                capabilities.contains(Capability.REPORT_FEED_USER_ACTIONS_NOTICE_CARD);
+        RecordHistogram.recordBooleanHistogram(
+                "ContentSuggestions.Feed.NoticeCardFulfilled", hasNoticeCard);
         if (isRefreshRequest) {
-            RecordHistogram.recordBooleanHistogram("ContentSuggestions.Feed.NoticeCardFulfilled",
-                    capabilities.contains(Capability.REPORT_FEED_USER_ACTIONS_NOTICE_CARD));
+            RecordHistogram.recordBooleanHistogram(
+                    "ContentSuggestions.Feed.NoticeCardFulfilled2", hasNoticeCard);
             mMainThreadRunner.execute("Update notice card pref",
                     ()
                             -> updateNoticeCardPref(capabilities.contains(
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/FeedRequestManagerImplTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/FeedRequestManagerImplTest.java
index 11d3c95..73c63aa 100644
--- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/FeedRequestManagerImplTest.java
+++ b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/FeedRequestManagerImplTest.java
@@ -6,6 +6,8 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -245,11 +247,17 @@
     }
 
     @Test
-    public void testTriggerRefresh_setNoticeCardPrefAndRecordHistogram() throws Exception {
+    public void testTriggerRefresh_setNoticeCardPrefAndRecordBothHistograms() throws Exception {
+        MetricsUtils.HistogramDelta obsoleteNoticeCardNotFulfilledDelta =
+                new MetricsUtils.HistogramDelta(
+                        "ContentSuggestions.Feed.NoticeCardFulfilled", 0 /*false*/);
+        MetricsUtils.HistogramDelta obsoleteNoticeCardFulfilledDelta =
+                new MetricsUtils.HistogramDelta(
+                        "ContentSuggestions.Feed.NoticeCardFulfilled", 1 /*true*/);
         MetricsUtils.HistogramDelta noticeCardNotFulfilledDelta = new MetricsUtils.HistogramDelta(
-                "ContentSuggestions.Feed.NoticeCardFulfilled", 0 /*false*/);
+                "ContentSuggestions.Feed.NoticeCardFulfilled2", 0 /*false*/);
         MetricsUtils.HistogramDelta noticeCardFulfilledDelta = new MetricsUtils.HistogramDelta(
-                "ContentSuggestions.Feed.NoticeCardFulfilled", 1 /*true*/);
+                "ContentSuggestions.Feed.NoticeCardFulfilled2", 1 /*true*/);
 
         // Skip the read of the int that determines the length of the encoded proto. This is to
         // avoid having to encode the length which is a feature we don't want to test here.
@@ -283,6 +291,8 @@
         mFakeNetworkClient.addResponse(
                 new HttpResponse(200, Response.getDefaultInstance().toByteArray(), false));
         mRequestManager.triggerRefresh(RequestReason.HOST_REQUESTED, input -> {});
+        assertThat(obsoleteNoticeCardNotFulfilledDelta.getDelta()).isEqualTo(1);
+        assertThat(obsoleteNoticeCardFulfilledDelta.getDelta()).isEqualTo(1);
         assertThat(noticeCardNotFulfilledDelta.getDelta()).isEqualTo(1);
         assertThat(noticeCardFulfilledDelta.getDelta()).isEqualTo(1);
     }
@@ -310,11 +320,18 @@
     }
 
     @Test
-    public void testLoadMore_dontSetNoticeCardPrefAndDontRecordHistogram() throws Exception {
+    public void testLoadMore_dontSetNoticeCardPrefAndOnlyRecordObsoleteHistogram()
+            throws Exception {
+        MetricsUtils.HistogramDelta obsoleteNoticeCardNotFulfilledDelta =
+                new MetricsUtils.HistogramDelta(
+                        "ContentSuggestions.Feed.NoticeCardFulfilled", 0 /*false*/);
+        MetricsUtils.HistogramDelta obsoleteNoticeCardFulfilledDelta =
+                new MetricsUtils.HistogramDelta(
+                        "ContentSuggestions.Feed.NoticeCardFulfilled", 1 /*true*/);
         MetricsUtils.HistogramDelta noticeCardNotFulfilledDelta = new MetricsUtils.HistogramDelta(
-                "ContentSuggestions.Feed.NoticeCardFulfilled", 0 /*false*/);
+                "ContentSuggestions.Feed.NoticeCardFulfilled2", 0 /*false*/);
         MetricsUtils.HistogramDelta noticeCardFulfilledDelta = new MetricsUtils.HistogramDelta(
-                "ContentSuggestions.Feed.NoticeCardFulfilled", 1 /*true*/);
+                "ContentSuggestions.Feed.NoticeCardFulfilled2", 1 /*true*/);
 
         // Skip the read of the int that determines the length of the encoded proto. This is to
         // avoid having to encode the length which is a feature we don't want to test here.
@@ -329,18 +346,36 @@
                 mApplicationInfo, mFakeMainThreadRunner, mFakeBasicLoggingApi,
                 mFakeTooltipSupportedApi);
 
-        mFakeNetworkClient.addResponse(
-                new HttpResponse(200, Response.getDefaultInstance().toByteArray(), false));
+        mFakeThreadUtils.enforceMainThread(false);
+
+        // Trigger a load more with a notice card in the query response.
+        Response response =
+                Response.newBuilder()
+                        .setExtension(FeedResponse.feedResponse,
+                                FeedResponse.newBuilder()
+                                        .addServerCapabilities(
+                                                Capability.REPORT_FEED_USER_ACTIONS_NOTICE_CARD)
+                                        .build())
+                        .build();
+        mFakeNetworkClient.addResponse(new HttpResponse(200, response.toByteArray(), false));
         StreamToken token =
                 StreamToken.newBuilder()
                         .setNextPageToken(ByteString.copyFrom("abc", Charset.defaultCharset()))
                         .build();
-        mFakeThreadUtils.enforceMainThread(false);
         mRequestManager.loadMore(token, ConsistencyToken.getDefaultInstance(), input -> {});
 
-        verify(mPrefService, never()).setBoolean(Pref.LAST_FETCH_HAD_NOTICE_CARD, true);
+        // Trigger a load more without a notice card in the query response.
+        mFakeNetworkClient.addResponse(
+                new HttpResponse(200, Response.getDefaultInstance().toByteArray(), false));
+        mRequestManager.loadMore(token, ConsistencyToken.getDefaultInstance(), input -> {});
+
+        // Verify that only the obsolete histograms were recorded.
         assertThat(noticeCardNotFulfilledDelta.getDelta()).isEqualTo(0);
         assertThat(noticeCardFulfilledDelta.getDelta()).isEqualTo(0);
+        assertThat(obsoleteNoticeCardNotFulfilledDelta.getDelta()).isEqualTo(1);
+        assertThat(obsoleteNoticeCardFulfilledDelta.getDelta()).isEqualTo(1);
+        // Verify that no attempts were made to update the notice card presence pref.
+        verify(mPrefService, never()).setBoolean(eq(Pref.LAST_FETCH_HAD_NOTICE_CARD), anyBoolean());
     }
 
     @Test
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/AppHooks.java b/chrome/android/java/src/org/chromium/chrome/browser/AppHooks.java
index 34e911d..6acb848d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/AppHooks.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/AppHooks.java
@@ -29,6 +29,7 @@
 import org.chromium.chrome.browser.lens.LensController;
 import org.chromium.chrome.browser.locale.LocaleManager;
 import org.chromium.chrome.browser.metrics.VariationsSession;
+import org.chromium.chrome.browser.notifications.chime.ChimeDelegate;
 import org.chromium.chrome.browser.omaha.RequestGenerator;
 import org.chromium.chrome.browser.partnerbookmarks.PartnerBookmark;
 import org.chromium.chrome.browser.partnerbookmarks.PartnerBookmarksProviderIterator;
@@ -358,4 +359,11 @@
     public String getWebApkServerUrl() {
         return "";
     }
+
+    /**
+     * Returns a Chime Delegate if the chime module is defined.
+     */
+    public @Nullable ChimeDelegate getChimeDelegate() {
+        return null;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivitySessionTracker.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivitySessionTracker.java
index e475645..bd5637b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivitySessionTracker.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivitySessionTracker.java
@@ -28,7 +28,6 @@
 import org.chromium.chrome.browser.metrics.UmaUtils;
 import org.chromium.chrome.browser.metrics.VariationsSession;
 import org.chromium.chrome.browser.notifications.NotificationPlatformBridge;
-import org.chromium.chrome.browser.notifications.chime.ChimeSession;
 import org.chromium.chrome.browser.partnercustomizations.PartnerBrowserCustomizations;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.preferences.Pref;
@@ -140,7 +139,9 @@
         updateAcceptLanguages();
         mVariationsSession.start();
         mPowerBroadcastReceiver.onForegroundSessionStart();
-        ChimeSession.start();
+        if (AppHooks.get().getChimeDelegate() != null) {
+            AppHooks.get().getChimeDelegate().startSession();
+        }
 
         // Track the ratio of Chrome startups that are caused by notification clicks.
         // TODO(johnme): Add other reasons (and switch to recordEnumeratedHistogram).
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java b/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java
index dd218e1e..c95fd327 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java
@@ -73,7 +73,8 @@
                 ChromeFeatureList.TAB_TO_GTS_ANIMATION,
                 ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_ICONS,
                 ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_REGROUP,
-                ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_THREE_BUTTON_ACTIONBAR);
+                ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_THREE_BUTTON_ACTIONBAR,
+                ChromeFeatureList.USE_CHIME_ANDROID_SDK);
         // clang-format on
         CachedFeatureFlags.cacheNativeFlags(featuresToCache);
         CachedFeatureFlags.cacheAdditionalNativeFlags();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/digitalgoods/GetDetailsConverter.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/digitalgoods/GetDetailsConverter.java
index 6d346c0d..4365486 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/digitalgoods/GetDetailsConverter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/digitalgoods/GetDetailsConverter.java
@@ -34,13 +34,18 @@
     static final String RESPONSE_GET_DETAILS_RESPONSE_CODE = "getDetails.responseCode";
     static final String RESPONSE_GET_DETAILS_DETAILS_LIST = "getDetails.detailsList";
 
-    static final String ITEM_DETAILS_ID = "itemDetails.id";
-    static final String ITEM_DETAILS_TITLE = "itemDetails.title";
-    static final String ITEM_DETAILS_DESC = "itemDetails.description";
-    static final String ITEM_DETAILS_CURRENCY = "itemDetails.currency";
-    static final String ITEM_DETAILS_VALUE = "itemDetails.value";
-    static final String[] ITEM_DETAILS_ALL_FIELDS = {ITEM_DETAILS_ID, ITEM_DETAILS_TITLE,
-            ITEM_DETAILS_DESC, ITEM_DETAILS_CURRENCY, ITEM_DETAILS_VALUE};
+    static final String KEY_ID = "itemDetails.id";
+    static final String KEY_TITLE = "itemDetails.title";
+    static final String KEY_DESC = "itemDetails.description";
+    static final String KEY_CURRENCY = "itemDetails.currency";
+    static final String KEY_VALUE = "itemDetails.value";
+    static final String[] REQUIRED_FIELDS = {KEY_ID, KEY_TITLE, KEY_DESC, KEY_CURRENCY, KEY_VALUE};
+
+    static final String KEY_SUBS_PERIOD = "itemDetails.subsPeriod";
+    static final String KEY_FREE_TRIAL_PERIOD = "itemDetails.freeTrialPeriod";
+    static final String KEY_INTRO_CURRENCY = "itemDetails.introPriceCurrency";
+    static final String KEY_INTRO_VALUE = "itemDetails.introPriceValue";
+    static final String KEY_INTRO_PERIOD = "itemDetails.introPricePeriod";
 
     private GetDetailsConverter() {}
 
@@ -106,23 +111,39 @@
 
         Bundle item = (Bundle) itemAsParcelable;
 
-        for (String field : ITEM_DETAILS_ALL_FIELDS) {
+        for (String field : REQUIRED_FIELDS) {
             if (item.containsKey(field) && (item.get(field) instanceof String)) continue;
             Log.w(TAG, "Item does not contain field String " + field + ".");
             return null;
         }
 
-        PaymentCurrencyAmount amount = new PaymentCurrencyAmount();
-        amount.currency = item.getString(ITEM_DETAILS_CURRENCY);
-        amount.value = item.getString(ITEM_DETAILS_VALUE);
+        // Mandatory fields.
+        PaymentCurrencyAmount price = new PaymentCurrencyAmount();
+        price.currency = item.getString(KEY_CURRENCY);
+        price.value = item.getString(KEY_VALUE);
 
-        ItemDetails res = new ItemDetails();
-        res.itemId = item.getString(ITEM_DETAILS_ID);
-        res.title = item.getString(ITEM_DETAILS_TITLE);
-        res.description = item.getString(ITEM_DETAILS_DESC);
-        res.price = amount;
+        ItemDetails result = new ItemDetails();
+        result.itemId = item.getString(KEY_ID);
+        result.title = item.getString(KEY_TITLE);
+        result.description = item.getString(KEY_DESC);
+        result.price = price;
 
-        return res;
+        // Optional fields.
+        result.subscriptionPeriod = item.getString(KEY_SUBS_PERIOD);
+        result.freeTrialPeriod = item.getString(KEY_FREE_TRIAL_PERIOD);
+        result.introductoryPricePeriod = item.getString(KEY_INTRO_PERIOD);
+
+        String introPriceCurrency = item.getString(KEY_INTRO_CURRENCY);
+        String introPriceValue = item.getString(KEY_INTRO_VALUE);
+
+        if (introPriceCurrency != null && introPriceValue != null) {
+            PaymentCurrencyAmount introPrice = new PaymentCurrencyAmount();
+            introPrice.currency = introPriceCurrency;
+            introPrice.value = introPriceValue;
+            result.introductoryPrice = introPrice;
+        }
+
+        return result;
     }
 
     public static void returnClientAppUnavailable(GetDetailsResponse callback) {
@@ -138,15 +159,34 @@
      * This would be used by the client app and is here only to help testing.
      */
     @VisibleForTesting
+    public static Bundle createItemDetailsBundle(String id, String title, String desc,
+            String currency, String value, @Nullable String subsPeriod,
+            @Nullable String freeTrialPeriod, @Nullable String introPriceCurrency,
+            @Nullable String introPriceValue, @Nullable String intoPricePeriod) {
+        Bundle bundle = createItemDetailsBundle(id, title, desc, currency, value);
+
+        bundle.putString(KEY_SUBS_PERIOD, subsPeriod);
+        bundle.putString(KEY_FREE_TRIAL_PERIOD, freeTrialPeriod);
+        bundle.putString(KEY_INTRO_CURRENCY, introPriceCurrency);
+        bundle.putString(KEY_INTRO_VALUE, introPriceValue);
+        bundle.putString(KEY_INTRO_PERIOD, intoPricePeriod);
+
+        return bundle;
+    }
+
+    /**
+     * Like the above method, but provides {@code null} for all optional parameters.
+     */
+    @VisibleForTesting
     public static Bundle createItemDetailsBundle(
             String id, String title, String desc, String currency, String value) {
         Bundle bundle = new Bundle();
 
-        bundle.putString(ITEM_DETAILS_ID, id);
-        bundle.putString(ITEM_DETAILS_TITLE, title);
-        bundle.putString(ITEM_DETAILS_DESC, desc);
-        bundle.putString(ITEM_DETAILS_CURRENCY, currency);
-        bundle.putString(ITEM_DETAILS_VALUE, value);
+        bundle.putString(KEY_ID, id);
+        bundle.putString(KEY_TITLE, title);
+        bundle.putString(KEY_DESC, desc);
+        bundle.putString(KEY_CURRENCY, currency);
+        bundle.putString(KEY_VALUE, value);
 
         return bundle;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java
index 90985c0..1106083 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java
@@ -49,6 +49,7 @@
 import org.chromium.chrome.browser.ntp.FakeboxDelegate;
 import org.chromium.chrome.browser.offlinepages.OfflinePageUtils;
 import org.chromium.chrome.browser.omnibox.LocationBar;
+import org.chromium.chrome.browser.omnibox.LocationBarDataProvider;
 import org.chromium.chrome.browser.omnibox.UrlBar;
 import org.chromium.chrome.browser.omnibox.UrlBarCoordinator;
 import org.chromium.chrome.browser.omnibox.UrlBarCoordinator.SelectionState;
@@ -246,12 +247,12 @@
 
     /**
      *
-     * @param toolbarDataProvider {@link ToolbarDataProvider} to be used for accessing Toolbar
+     * @param locationBarDataProvider {@link ToolbarDataProvider} to be used for accessing Toolbar
      *         state.
      * @return The LocationBar implementation for this CustomTabToolbar.
      */
-    public LocationBar createLocationBar(ToolbarDataProvider toolbarDataProvider) {
-        mLocationBar = new CustomTabLocationBar(toolbarDataProvider);
+    public LocationBar createLocationBar(LocationBarDataProvider locationBarDataProvider) {
+        mLocationBar = new CustomTabLocationBar(locationBarDataProvider);
         mUrlCoordinator.setDelegate(mLocationBar);
         mLocationBar.updateVisualsForState();
         return mLocationBar;
@@ -624,21 +625,16 @@
      * Custom tab-specific implementation of the LocationBar interface.
      */
     private class CustomTabLocationBar implements LocationBar, UrlBar.UrlBarDelegate {
-        private ToolbarDataProvider mToolbarDataProvider;
+        private LocationBarDataProvider mLocationBarDataProvider;
 
-        public CustomTabLocationBar(ToolbarDataProvider toolbarDataProvider) {
-            mToolbarDataProvider = toolbarDataProvider;
-        }
-
-        /** Gets the {@link ToolbarDataProvider} to be used for accessing {@link Toolbar} state. */
-        ToolbarDataProvider getToolbarDataProvider() {
-            return mToolbarDataProvider;
+        public CustomTabLocationBar(LocationBarDataProvider locationBarDataProvider) {
+            mLocationBarDataProvider = locationBarDataProvider;
         }
 
         @Override
         public void onNativeLibraryReady() {
             mSecurityButton.setOnClickListener(v -> {
-                Tab currentTab = getToolbarDataProvider().getTab();
+                Tab currentTab = mLocationBarDataProvider.getTab();
                 if (currentTab == null) return;
                 WebContents webContents = currentTab.getWebContents();
                 if (webContents == null) return;
@@ -668,11 +664,6 @@
         }
 
         @Override
-        public boolean shouldCutCopyVerbatim() {
-            return false;
-        }
-
-        @Override
         public void gestureDetected(boolean isLongPress) {}
 
         @Override
@@ -687,17 +678,17 @@
 
         @Override
         public void setTitleToPageTitle() {
-            String title = getToolbarDataProvider().getTitle();
-            if (!getToolbarDataProvider().hasTab() || TextUtils.isEmpty(title)) {
+            String title = mLocationBarDataProvider.getTitle();
+            if (!mLocationBarDataProvider.hasTab() || TextUtils.isEmpty(title)) {
                 mTitleBar.setText("");
                 return;
             }
 
             // It takes some time to parse the title of the webcontent, and before that
-            // ToolbarDataProvider#getTitle always returns the url. We postpone the title animation
-            // until the title is authentic.
+            // LocationBarDataProvider#getTitle always returns the url. We postpone the title
+            // animation until the title is authentic.
             if ((mState == STATE_DOMAIN_AND_TITLE || mState == STATE_TITLE_ONLY)
-                    && !title.equals(getToolbarDataProvider().getCurrentUrl())
+                    && !title.equals(mLocationBarDataProvider.getCurrentUrl())
                     && !title.equals(ContentUrlConstants.ABOUT_BLANK_DISPLAY_URL)) {
                 // Delay the title animation until security icon animation finishes.
                 PostTask.postDelayedTask(
@@ -719,7 +710,9 @@
             String publisherUrl = TrustedCdn.getPublisherUrl(tab);
             String url = publisherUrl != null ? publisherUrl : tab.getUrlString().trim();
             if (mState == STATE_TITLE_ONLY) {
-                if (!TextUtils.isEmpty(getToolbarDataProvider().getTitle())) setTitleToPageTitle();
+                if (!TextUtils.isEmpty(mLocationBarDataProvider.getTitle())) {
+                    setTitleToPageTitle();
+                }
             }
 
             // Don't show anything for Chrome URLs and "about:blank".
@@ -735,7 +728,6 @@
             final int originStart;
             final int originEnd;
             if (publisherUrl != null) {
-                // TODO(bauerb): Move this into the ToolbarDataProvider as well?
                 String plainDisplayText =
                         getContext().getString(R.string.custom_tab_amp_publisher_url,
                                 extractPublisherFromPublisherUrl(publisherUrl));
@@ -749,7 +741,7 @@
                 formattedDisplayText.removeSpan(ORIGIN_SPAN);
                 displayText = formattedDisplayText;
             } else {
-                UrlBarData urlBarData = getToolbarDataProvider().getUrlBarData();
+                UrlBarData urlBarData = mLocationBarDataProvider.getUrlBarData();
                 displayText = urlBarData.displayText.subSequence(
                         urlBarData.originStartIndex, urlBarData.originEndIndex);
                 originStart = 0;
@@ -759,7 +751,7 @@
             // The Lite Status view visibility should be updated on every new URL and only be
             // displayed along with the URL bar.
             final boolean liteStatusIsVisible =
-                    getToolbarDataProvider().isPreview() && mUrlBar.getVisibility() == View.VISIBLE;
+                    mLocationBarDataProvider.isPreview() && mUrlBar.getVisibility() == View.VISIBLE;
             mLiteStatusView.setVisibility(liteStatusIsVisible ? View.VISIBLE : View.GONE);
             mLiteStatusSeparatorView.setVisibility(liteStatusIsVisible ? View.VISIBLE : View.GONE);
 
@@ -804,17 +796,17 @@
         public void updateStatusIcon() {
             if (mState == STATE_TITLE_ONLY) return;
 
-            int securityIconResource = getToolbarDataProvider().getSecurityIconResource(
+            int securityIconResource = mLocationBarDataProvider.getSecurityIconResource(
                     DeviceFormFactor.isNonMultiDisplayContextOnTablet(getContext()));
             if (securityIconResource != 0) {
                 ColorStateList colorStateList = AppCompatResources.getColorStateList(
-                        getContext(), getToolbarDataProvider().getSecurityIconColorStateList());
+                        getContext(), mLocationBarDataProvider.getSecurityIconColorStateList());
                 ApiCompatibilityUtils.setImageTintList(mSecurityButton, colorStateList);
             }
             mAnimDelegate.updateSecurityButton(securityIconResource);
 
             int contentDescriptionId =
-                    getToolbarDataProvider().getSecurityIconContentDescriptionResourceId();
+                    mLocationBarDataProvider.getSecurityIconContentDescriptionResourceId();
             String contentDescription = getContext().getString(contentDescriptionId);
             mSecurityButton.setContentDescription(contentDescription);
 
@@ -841,11 +833,6 @@
         public void destroy() {}
 
         @Override
-        public boolean shouldForceLTR() {
-            return true;
-        }
-
-        @Override
         public void showUrlBarCursorWithoutFocusAnimations() {}
 
         @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinator.java
index d8d61fd7..b0f06d70 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinator.java
@@ -21,7 +21,6 @@
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.share.ShareDelegate;
 import org.chromium.chrome.browser.tabmodel.IncognitoStateProvider;
-import org.chromium.chrome.browser.toolbar.ToolbarDataProvider;
 import org.chromium.chrome.browser.toolbar.top.ToolbarActionModeCallback;
 import org.chromium.chrome.browser.ui.native_page.NativePage;
 import org.chromium.ui.base.WindowAndroid;
@@ -58,8 +57,8 @@
      * @param locationBarLayout Inflated {@link LocationBarPhone} or {@link LocationBarTablet}.
      *         {@code LocationBarCoordinator} takes ownership and will destroy this object.
      * @param profileObservableSupplier The supplier of the active profile.
-     * @param toolbarDataProvider {@link ToolbarDataProvider} to be used for accessing Toolbar
-     *         state.
+     * @param locationBarDataProvider {@link LocationBarDataProvider} to be used for accessing
+     *         Toolbar state.
      * @param actionModeCallback The default callback for text editing action bar to use.
      * @param windowDelegate {@link WindowDelegate} that will provide {@link Window} related info.
      * @param windowAndroid {@link WindowAndroid} that is used by the owning {@link Activity}.
@@ -74,9 +73,9 @@
      */
     public LocationBarCoordinator(View locationBarLayout,
             ObservableSupplier<Profile> profileObservableSupplier,
-            ToolbarDataProvider toolbarDataProvider, ToolbarActionModeCallback actionModeCallback,
-            WindowDelegate windowDelegate, WindowAndroid windowAndroid,
-            ActivityTabProvider activityTabProvider,
+            LocationBarDataProvider locationBarDataProvider,
+            ToolbarActionModeCallback actionModeCallback, WindowDelegate windowDelegate,
+            WindowAndroid windowAndroid, ActivityTabProvider activityTabProvider,
             Supplier<ModalDialogManager> modalDialogManagerSupplier,
             Supplier<ShareDelegate> shareDelegateSupplier,
             IncognitoStateProvider incognitoStateProvider) {
@@ -93,7 +92,7 @@
             throw new IllegalArgumentException(locationBarLayout.getClass().toString());
         }
 
-        mLocationBarLayout.setToolbarDataProvider(toolbarDataProvider);
+        mLocationBarLayout.setLocationBarDataProvider(locationBarDataProvider);
         mLocationBarLayout.setProfileSupplier(profileObservableSupplier);
         mLocationBarLayout.setDefaultTextEditActionModeCallback(actionModeCallback);
         mLocationBarLayout.initializeControls(windowDelegate, windowAndroid, activityTabProvider,
@@ -152,8 +151,8 @@
         mLocationBarLayout.updateLoadingState(updateUrl);
     }
 
-    public ToolbarDataProvider getToolbarDataProvider() {
-        return mLocationBarLayout.getToolbarDataProvider();
+    public LocationBarDataProvider getLocationBarDataProvider() {
+        return mLocationBarLayout.getLocationBarDataProvider();
     }
 
     @Override
@@ -208,16 +207,6 @@
     }
 
     @Override
-    public boolean shouldForceLTR() {
-        return mLocationBarLayout.shouldForceLTR();
-    }
-
-    @Override
-    public boolean shouldCutCopyVerbatim() {
-        return mLocationBarLayout.shouldCutCopyVerbatim();
-    }
-
-    @Override
     public void gestureDetected(boolean isLongPress) {
         mLocationBarLayout.gestureDetected(isLongPress);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarDataProvider.java
new file mode 100644
index 0000000..2af4f69
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarDataProvider.java
@@ -0,0 +1,112 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.omnibox;
+
+import android.content.res.ColorStateList;
+
+import androidx.annotation.ColorRes;
+import androidx.annotation.DrawableRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.StringRes;
+
+import org.chromium.chrome.browser.ntp.NewTabPage;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.components.security_state.ConnectionSecurityLevel;
+
+/**
+ * Interface defining a provider for data needed by the {@link LocationBar}.
+ */
+// TODO(crbug.com/1142887): Refine split between LocationBar properties and sub-component
+// properties, e.g. security state, which is only used by the status icon.
+public interface LocationBarDataProvider {
+    /** Returns The url for the currently active page.*/
+    @NonNull
+    String getCurrentUrl();
+
+    /** Returns The NewTabPage shown for the current tab, if one exists. */
+    @NonNull
+    NewTabPage getNewTabPageForCurrentTab();
+
+    /** Returns whether the currently active page is loading. */
+    default boolean isLoading() {
+        Tab tab = getTab();
+        return tab != null && tab.isLoading();
+    }
+
+    /** Returns whether the current page is in an incognito browser context. */
+    boolean isIncognito();
+
+    /** Returns the currently active tab, if there is one. */
+    @Nullable
+    Tab getTab();
+
+    /** Returns whether the LocationBarDataProvider currently has an active tab. */
+    boolean hasTab();
+
+    /**
+     * Returns whether the LocationBar's embedder is currently being displayed in overview mode and
+     *         showing the
+     *  omnibox.
+     */
+    boolean isInOverviewAndShowingOmnibox();
+
+    /** Returns whether the location bar should show when in overview mode. */
+    boolean shouldShowLocationBarInOverviewMode();
+
+    /** Returns the current {@link Profile}. */
+    Profile getProfile();
+
+    /** Returns the contents of the {@link org.chromium.chrome.browser.omnibox.UrlBar}. */
+    UrlBarData getUrlBarData();
+
+    /** Returns the title of the current page, or the empty string if there is currently no tab. */
+    String getTitle();
+
+    /** Returns the primary color to use for the background.*/
+    int getPrimaryColor();
+
+    /** Returns whether the current primary color is a brand color. */
+    boolean isUsingBrandColor();
+
+    /** Returns whether the page currently shown is an offline page. */
+    boolean isOfflinePage();
+
+    /** Returns whether the page currently shown is a preview. */
+    boolean isPreview();
+
+    /** Returns whether the page currently shown is a paint preview. */
+    default boolean isPaintPreview() {
+        return false;
+    }
+
+    /** Returns the current {@link ConnectionSecurityLevel}. */
+    @ConnectionSecurityLevel
+    int getSecurityLevel();
+
+    /**
+     * Returns the current page classification.
+     * @param isFocusedFromFakebox If the omnibox focus originated from the fakebox.
+     */
+    default int getPageClassification(boolean isFocusedFromFakebox) {
+        return 0;
+    }
+
+    /**
+     * Returns the resource ID of the icon that should be displayed or 0 if no icon should be shown.
+     * @param isTablet Whether or not the display context of the icon is a tablet.
+     */
+    @DrawableRes
+    int getSecurityIconResource(boolean isTablet);
+
+    /** Returns The {@link ColorStateList} to use to tint the security state icon. */
+    @ColorRes
+    int getSecurityIconColorStateList();
+
+    /** Returns the resource ID of the content description for the security icon. */
+    @StringRes
+    int getSecurityIconContentDescriptionResourceId();
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
index 8a9a321..f5e2dafd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
@@ -71,7 +71,6 @@
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.IncognitoStateProvider;
 import org.chromium.chrome.browser.tasks.ReturnToChromeExperimentsUtil;
-import org.chromium.chrome.browser.toolbar.ToolbarDataProvider;
 import org.chromium.chrome.browser.toolbar.top.ToolbarActionModeCallback;
 import org.chromium.chrome.browser.ui.native_page.NativePage;
 import org.chromium.chrome.browser.util.ChromeAccessibilityUtil;
@@ -115,7 +114,7 @@
     protected UrlBarCoordinator mUrlCoordinator;
     protected AutocompleteCoordinator mAutocompleteCoordinator;
 
-    protected ToolbarDataProvider mToolbarDataProvider;
+    protected LocationBarDataProvider mLocationBarDataProvider;
     private final ObserverList<UrlFocusChangeListener> mUrlFocusChangeListeners =
             new ObserverList<>();
 
@@ -410,11 +409,12 @@
         if (!mUrlHasFocus) {
             setUrlToPageUrl();
         } else {
-            String currentUrl = mToolbarDataProvider.getCurrentUrl();
-            if (NativePageFactory.isNativePageUrl(currentUrl, mToolbarDataProvider.isIncognito())) {
+            String currentUrl = mLocationBarDataProvider.getCurrentUrl();
+            if (NativePageFactory.isNativePageUrl(
+                        currentUrl, mLocationBarDataProvider.isIncognito())) {
                 setUrlBarTextEmpty();
             } else {
-                setUrlBarText(mToolbarDataProvider.getUrlBarData(), UrlBar.ScrollType.NO_SCROLL,
+                setUrlBarText(mLocationBarDataProvider.getUrlBarData(), UrlBar.ScrollType.NO_SCROLL,
                         SelectionState.SELECT_ALL);
             }
             setKeyboardVisibility(false, false);
@@ -453,19 +453,19 @@
     /**
      * Sets the toolbar that owns this LocationBar.
      */
-    public void setToolbarDataProvider(ToolbarDataProvider toolbarDataProvider) {
-        mToolbarDataProvider = toolbarDataProvider;
+    public void setLocationBarDataProvider(LocationBarDataProvider locationBarDataProvider) {
+        mLocationBarDataProvider = locationBarDataProvider;
 
         updateButtonVisibility();
 
-        mAutocompleteCoordinator.setToolbarDataProvider(toolbarDataProvider);
-        mStatusCoordinator.setToolbarDataProvider(toolbarDataProvider);
+        mAutocompleteCoordinator.setLocationBarDataProvider(locationBarDataProvider);
+        mStatusCoordinator.setLocationBarDataProvider(locationBarDataProvider);
         mUrlCoordinator.setOnFocusChangedCallback(this::onUrlFocusChange);
     }
 
     @Override
-    public final ToolbarDataProvider getToolbarDataProvider() {
-        return mToolbarDataProvider;
+    public final LocationBarDataProvider getLocationBarDataProvider() {
+        return mLocationBarDataProvider;
     }
 
     /**
@@ -503,10 +503,10 @@
         if (mNativeInitialized
                 && !CommandLine.getInstance().hasSwitch(ChromeSwitches.DISABLE_INSTANT)
                 && PrivacyPreferencesManager.getInstance().shouldPrerender()
-                && mToolbarDataProvider.hasTab()) {
+                && mLocationBarDataProvider.hasTab()) {
             mOmniboxPrerender.prerenderMaybe(userText, getOriginalUrl(),
                     mAutocompleteCoordinator.getCurrentNativeAutocompleteResult(),
-                    mToolbarDataProvider.getProfile(), mToolbarDataProvider.getTab());
+                    mLocationBarDataProvider.getProfile(), mLocationBarDataProvider.getTab());
         }
     }
 
@@ -586,19 +586,6 @@
     }
 
     @Override
-    public boolean shouldForceLTR() {
-        return mToolbarDataProvider.getDisplaySearchTerms() == null;
-    }
-
-    @Override
-    public boolean shouldCutCopyVerbatim() {
-        // When cutting/copying text in the URL bar, it will try to copy some version of the actual
-        // URL to the clipboard, not the currently displayed URL bar contents. We want to avoid this
-        // when displaying search terms.
-        return mToolbarDataProvider.getDisplaySearchTerms() != null;
-    }
-
-    @Override
     public void gestureDetected(boolean isLongPress) {
         recordOmniboxFocusReason(isLongPress ? OmniboxFocusReason.OMNIBOX_LONG_PRESS
                                              : OmniboxFocusReason.OMNIBOX_TAP);
@@ -622,8 +609,8 @@
 
     @Override
     public boolean allowKeyboardLearning() {
-        if (mToolbarDataProvider == null) return false;
-        return !mToolbarDataProvider.isIncognito();
+        if (mLocationBarDataProvider == null) return false;
+        return !mLocationBarDataProvider.isIncognito();
     }
 
     @Override
@@ -669,7 +656,7 @@
     @Override
     public boolean isCurrentPage(NativePage nativePage) {
         assert nativePage != null;
-        return nativePage == mToolbarDataProvider.getNewTabPageForCurrentTab();
+        return nativePage == mLocationBarDataProvider.getNewTabPageForCurrentTab();
     }
 
     @Override
@@ -701,9 +688,9 @@
         // If the location bar is focused, the toolbar background color would be the default color
         // regardless of whether it is branded or not.
         final int defaultPrimaryColor = ChromeColors.getDefaultThemeColor(
-                getResources(), mToolbarDataProvider.isIncognito());
+                getResources(), mLocationBarDataProvider.isIncognito());
         final int primaryColor =
-                mUrlHasFocus ? defaultPrimaryColor : mToolbarDataProvider.getPrimaryColor();
+                mUrlHasFocus ? defaultPrimaryColor : mLocationBarDataProvider.getPrimaryColor();
 
         // This will be called between inflation and initialization. For those calls, using a null
         // ColorStateList should have no visible impact to the user.
@@ -727,11 +714,11 @@
 
         mStatusCoordinator.setUseDarkColors(useDarkColors);
         mStatusCoordinator.setIncognitoBadgeVisibility(
-                mToolbarDataProvider.isIncognito() && !mIsTablet);
+                mLocationBarDataProvider.isIncognito() && !mIsTablet);
 
         if (mAutocompleteCoordinator != null) {
             mAutocompleteCoordinator.updateVisualsForState(
-                    useDarkColors, mToolbarDataProvider.isIncognito());
+                    useDarkColors, mLocationBarDataProvider.isIncognito());
         }
     }
 
@@ -762,9 +749,9 @@
         mMicButton.setImageDrawable(drawable);
 
         final int defaultPrimaryColor = ChromeColors.getDefaultThemeColor(
-                getResources(), mToolbarDataProvider.isIncognito());
+                getResources(), mLocationBarDataProvider.isIncognito());
         final int primaryColor =
-                mUrlHasFocus ? defaultPrimaryColor : mToolbarDataProvider.getPrimaryColor();
+                mUrlHasFocus ? defaultPrimaryColor : mLocationBarDataProvider.getPrimaryColor();
         ColorStateList colorStateList =
                 mAssistantVoiceSearchService.getMicButtonColorStateList(primaryColor, getContext());
         ApiCompatibilityUtils.setImageTintList(mMicButton, colorStateList);
@@ -788,7 +775,7 @@
      * <p>If the current tab is null, the URL text will be cleared.
      */
     public void setUrlToPageUrl() {
-        String currentUrl = mToolbarDataProvider.getCurrentUrl();
+        String currentUrl = mLocationBarDataProvider.getCurrentUrl();
 
         // If the URL is currently focused, do not replace the text they have entered with the URL.
         // Once they stop editing the URL, the current tab's URL will automatically be filled in.
@@ -804,15 +791,12 @@
         }
 
         mOriginalUrl = currentUrl;
-        @ScrollType
-        int scrollType = mToolbarDataProvider.getDisplaySearchTerms() != null
-                ? UrlBar.ScrollType.SCROLL_TO_BEGINNING
-                : UrlBar.ScrollType.SCROLL_TO_TLD;
-        setUrlBarText(mToolbarDataProvider.getUrlBarData(), scrollType, SelectionState.SELECT_ALL);
-        if (!mToolbarDataProvider.hasTab()) return;
+        setUrlBarText(mLocationBarDataProvider.getUrlBarData(), UrlBar.ScrollType.SCROLL_TO_TLD,
+                SelectionState.SELECT_ALL);
+        if (!mLocationBarDataProvider.hasTab()) return;
 
         // Profile may be null if switching to a tab that has not yet been initialized.
-        Profile profile = mToolbarDataProvider.getProfile();
+        Profile profile = mLocationBarDataProvider.getProfile();
         if (profile != null && mOmniboxPrerender != null) mOmniboxPrerender.clear(profile);
     }
 
@@ -846,9 +830,9 @@
         // side is initialized
         assert mNativeInitialized : "Loading URL before native side initialized";
 
-        // TODO(crbug.com/1085812): Should be taking a fulll loaded LoadUrlParams.
-        if (ReturnToChromeExperimentsUtil.willHandleLoadUrlWithPostDataFromStartSurface(
-                    url, transition, postDataType, postData, mToolbarDataProvider.isIncognito())) {
+        // TODO(crbug.com/1085812): Should be taking a full loaded LoadUrlParams.
+        if (ReturnToChromeExperimentsUtil.willHandleLoadUrlWithPostDataFromStartSurface(url,
+                    transition, postDataType, postData, mLocationBarDataProvider.isIncognito())) {
             return;
         }
 
@@ -932,7 +916,7 @@
 
                 mSearchEngine = searchEngine;
                 updateSearchEngineStatusIcon(SearchEngineLogoUtils.shouldShowSearchEngineLogo(
-                                                     mToolbarDataProvider.isIncognito()),
+                                                     mLocationBarDataProvider.isIncognito()),
                         TemplateUrlServiceFactory.get().isDefaultSearchEngineGoogle(),
                         SearchEngineLogoUtils.getSearchLogoUrl());
             }
@@ -941,7 +925,7 @@
 
         // Force an update once to populate initial data.
         updateSearchEngineStatusIcon(SearchEngineLogoUtils.shouldShowSearchEngineLogo(
-                                             mToolbarDataProvider.isIncognito()),
+                                             mLocationBarDataProvider.isIncognito()),
                 TemplateUrlServiceFactory.get().isDefaultSearchEngineGoogle(),
                 SearchEngineLogoUtils.getSearchLogoUrl());
     }
@@ -980,7 +964,7 @@
 
     /** Focuses the current page. */
     private void focusCurrentTab() {
-        if (mToolbarDataProvider.hasTab()) {
+        if (mLocationBarDataProvider.hasTab()) {
             View view = getCurrentTab().getView();
             if (view != null) view.requestFocus();
         }
@@ -1043,7 +1027,7 @@
 
         if (mUrlHasFocus) {
             if (mNativeInitialized) RecordUserAction.record("FocusLocation");
-            UrlBarData urlBarData = mToolbarDataProvider.getUrlBarData();
+            UrlBarData urlBarData = mLocationBarDataProvider.getUrlBarData();
             if (urlBarData.editingText != null) {
                 setUrlBarText(urlBarData, UrlBar.ScrollType.NO_SCROLL, SelectionState.SELECT_ALL);
             }
@@ -1061,7 +1045,7 @@
             mUrlFocusedWithoutAnimations = false;
 
             // Focus change caused by a close-tab may result in an invalid current tab.
-            if (mToolbarDataProvider.hasTab()) {
+            if (mLocationBarDataProvider.hasTab()) {
                 setUrlToPageUrl();
             }
 
@@ -1076,13 +1060,14 @@
             if (imm.isActive(mUrlBar)) imm.hideSoftInputFromWindow(getWindowToken(), 0, null);
         }
 
-        if (mToolbarDataProvider.isUsingBrandColor()) updateVisualsForState();
+        if (mLocationBarDataProvider.isUsingBrandColor()) updateVisualsForState();
 
         mStatusCoordinator.onUrlFocusChange(mUrlHasFocus);
 
         if (!mUrlFocusedWithoutAnimations) handleUrlFocusAnimation(mUrlHasFocus);
 
-        if (mUrlHasFocus && mToolbarDataProvider.hasTab() && !mToolbarDataProvider.isIncognito()) {
+        if (mUrlHasFocus && mLocationBarDataProvider.hasTab()
+                && !mLocationBarDataProvider.isIncognito()) {
             if (mNativeInitialized
                     && TemplateUrlServiceFactory.get().isDefaultSearchEngineGoogle()) {
                 GeolocationHeader.primeLocationForGeoHeader();
@@ -1260,8 +1245,8 @@
     /** @return The current active {@link Tab}. */
     @Nullable
     private Tab getCurrentTab() {
-        if (mToolbarDataProvider == null) return null;
-        return mToolbarDataProvider.getTab();
+        if (mLocationBarDataProvider == null) return null;
+        return mLocationBarDataProvider.getTab();
     }
 
     public void setUnfocusedWidth(int unfocusedWidth) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java
index 58641f03..5bc54a3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java
@@ -65,7 +65,7 @@
 
         // The search engine icon will be the first visible focused view when it's showing.
         shouldShowSearchEngineLogo = SearchEngineLogoUtils.shouldShowSearchEngineLogo(
-                getToolbarDataProvider().isIncognito());
+                getLocationBarDataProvider().isIncognito());
 
         // This branch will be hit if the search engine logo experiment is enabled.
         if (SearchEngineLogoUtils.isSearchEngineLogoEnabled()) {
@@ -180,7 +180,7 @@
     @Override
     public void updateVisualsForState() {
         super.updateVisualsForState();
-        boolean isIncognito = getToolbarDataProvider().isIncognito();
+        boolean isIncognito = getLocationBarDataProvider().isIncognito();
         setShowIconsWhenUrlFocused(SearchEngineLogoUtils.shouldShowSearchEngineLogo(isIncognito));
         updateStatusVisibility();
     }
@@ -264,12 +264,12 @@
 
         // No offset is required if the experiment is disabled.
         if (!SearchEngineLogoUtils.shouldShowSearchEngineLogo(
-                    getToolbarDataProvider().isIncognito())) {
+                    getLocationBarDataProvider().isIncognito())) {
             return 0;
         }
 
         // On non-NTP pages, there will always be an icon when unfocused.
-        if (mToolbarDataProvider.getNewTabPageForCurrentTab() == null) return 0;
+        if (mLocationBarDataProvider.getNewTabPageForCurrentTab() == null) return 0;
 
         // This offset is only required when the focus animation is running.
         if (!hasFocus) return 0;
@@ -299,7 +299,7 @@
 
         // No offset is required if the experiment is disabled.
         if (!SearchEngineLogoUtils.shouldShowSearchEngineLogo(
-                    getToolbarDataProvider().isIncognito())) {
+                    getLocationBarDataProvider().isIncognito())) {
             return 0;
         }
 
@@ -312,7 +312,7 @@
                 urlExpansionPercent * mStatusCoordinator.getEndPaddingPixelSizeOnFocusDelta();
 
         if (!hasFocus && mStatusCoordinator.isSearchEngineStatusIconVisible()
-                && SearchEngineLogoUtils.currentlyOnNTP(mToolbarDataProvider)) {
+                && SearchEngineLogoUtils.currentlyOnNTP(mLocationBarDataProvider)) {
             // When:
             // 1. unfocusing the LocationBar on the NTP.
             // 2. scrolling the fakebox to the LocationBar on the NTP.
@@ -342,12 +342,12 @@
 
     /** Update the status visibility according to the current state held in LocationBar. */
     private void updateStatusVisibility() {
-        boolean incognito = getToolbarDataProvider().isIncognito();
+        boolean incognito = getLocationBarDataProvider().isIncognito();
         if (!SearchEngineLogoUtils.shouldShowSearchEngineLogo(incognito)) {
             return;
         }
 
-        if (SearchEngineLogoUtils.currentlyOnNTP(mToolbarDataProvider)) {
+        if (SearchEngineLogoUtils.currentlyOnNTP(mLocationBarDataProvider)) {
             mStatusCoordinator.setStatusIconShown(hasFocus());
         } else {
             mStatusCoordinator.setStatusIconShown(true);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarTablet.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarTablet.java
index 4b62c4b..687c364 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarTablet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarTablet.java
@@ -150,7 +150,7 @@
             mUrlFocusChangeAnimator = null;
         }
 
-        if (getToolbarDataProvider().getNewTabPageForCurrentTab() == null) {
+        if (getLocationBarDataProvider().getNewTabPageForCurrentTab() == null) {
             finishUrlFocusChange(hasFocus);
             return;
         }
@@ -187,7 +187,7 @@
     public void setUrlFocusChangeFraction(float fraction) {
         super.setUrlFocusChangeFraction(fraction);
 
-        NewTabPage ntp = getToolbarDataProvider().getNewTabPageForCurrentTab();
+        NewTabPage ntp = getLocationBarDataProvider().getNewTabPageForCurrentTab();
         if (ntp != null) ntp.setUrlFocusChangeAnimationPercent(fraction);
     }
 
@@ -494,8 +494,8 @@
     }
 
     private boolean shouldShowSaveOfflineButton() {
-        if (!mNativeInitialized || mToolbarDataProvider == null) return false;
-        Tab tab = mToolbarDataProvider.getTab();
+        if (!mNativeInitialized || mLocationBarDataProvider == null) return false;
+        Tab tab = mLocationBarDataProvider.getTab();
         if (tab == null) return false;
         // The save offline button should not be shown on native pages. Currently, trying to
         // save an offline page in incognito crashes, so don't show it on incognito either.
@@ -503,8 +503,8 @@
     }
 
     private boolean isSaveOfflineButtonEnabled() {
-        if (mToolbarDataProvider == null) return false;
-        return DownloadUtils.isAllowedToDownloadPage(mToolbarDataProvider.getTab());
+        if (mLocationBarDataProvider == null) return false;
+        return DownloadUtils.isAllowedToDownloadPage(mLocationBarDataProvider.getTab());
     }
 
     private boolean shouldShowPageActionButtons() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/SearchEngineLogoUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/SearchEngineLogoUtils.java
index ea05a98..fe19e68 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/SearchEngineLogoUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/SearchEngineLogoUtils.java
@@ -22,7 +22,6 @@
 import org.chromium.chrome.browser.locale.LocaleManager;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
-import org.chromium.chrome.browser.toolbar.ToolbarCommonPropertiesModel;
 import org.chromium.chrome.browser.ui.favicon.FaviconHelper;
 import org.chromium.components.browser_ui.widget.RoundedIconGenerator;
 import org.chromium.components.embedder_support.util.UrlUtilities;
@@ -166,10 +165,9 @@
     }
 
     /** @return Whether the status icon should be hidden when the LocationBar is unfocused. */
-    public static boolean currentlyOnNTP(
-            ToolbarCommonPropertiesModel toolbarCommonPropertiesModel) {
-        return toolbarCommonPropertiesModel != null
-                && UrlUtilities.isNTPUrl(toolbarCommonPropertiesModel.getCurrentUrl());
+    public static boolean currentlyOnNTP(LocationBarDataProvider locationBarDataProvider) {
+        return locationBarDataProvider != null
+                && UrlUtilities.isNTPUrl(locationBarDataProvider.getCurrentUrl());
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java
index 7746c78..bbf963c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java
@@ -170,17 +170,6 @@
         void backKeyPressed();
 
         /**
-         * @return Whether or not we should force LTR text on the URL bar when unfocused.
-         */
-        boolean shouldForceLTR();
-
-        /**
-         * @return Whether or not the copy/cut action should grab the underlying URL or just copy
-         *         whatever's in the URL bar verbatim.
-         */
-        boolean shouldCutCopyVerbatim();
-
-        /**
          * Called to notify that a tap or long press gesture has been detected.
          * @param isLongPress Whether or not is a long press gesture.
          */
@@ -343,7 +332,7 @@
         // normally (to allow users to make non-URL searches and to avoid showing Android's split
         // insertion point when an RTL user enters RTL text). Also render text normally when the
         // text field is empty (because then it displays an instruction that is not a URL).
-        if (mFocused || length() == 0 || !mUrlBarDelegate.shouldForceLTR()) {
+        if (mFocused || length() == 0) {
             setTextDirection(TEXT_DIRECTION_INHERIT);
         } else {
             setTextDirection(TEXT_DIRECTION_LTR);
@@ -597,8 +586,7 @@
             return true;
         }
 
-        if ((id == android.R.id.cut || id == android.R.id.copy)
-                && !mUrlBarDelegate.shouldCutCopyVerbatim()) {
+        if ((id == android.R.id.cut || id == android.R.id.copy)) {
             if (id == android.R.id.cut) {
                 RecordUserAction.record("Omnibox.LongPress.Cut");
             } else {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusCoordinator.java
index 469e717..d0d15e76 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusCoordinator.java
@@ -14,6 +14,7 @@
 import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.offlinepages.OfflinePageUtils;
+import org.chromium.chrome.browser.omnibox.LocationBarDataProvider;
 import org.chromium.chrome.browser.omnibox.UrlBar.UrlTextChangeListener;
 import org.chromium.chrome.browser.omnibox.UrlBarEditingTextStateProvider;
 import org.chromium.chrome.browser.page_info.ChromePageInfoControllerDelegate;
@@ -21,7 +22,6 @@
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabUtils;
 import org.chromium.chrome.browser.tabmodel.IncognitoStateProvider;
-import org.chromium.chrome.browser.toolbar.ToolbarDataProvider;
 import org.chromium.components.page_info.PageInfoController;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.ui.modaldialog.ModalDialogManager;
@@ -39,7 +39,7 @@
     private final PropertyModel mModel;
     private final boolean mIsTablet;
     private Supplier<ModalDialogManager> mModalDialogManagerSupplier;
-    private ToolbarDataProvider mToolbarDataProvider;
+    private LocationBarDataProvider mLocationBarDataProvider;
     private boolean mUrlHasFocus;
 
     /**
@@ -84,12 +84,12 @@
     /**
      * Provides data and state for the toolbar component.
      *
-     * @param toolbarDataProvider The data provider.
+     * @param locationBarDataProvider The data provider.
      */
-    public void setToolbarDataProvider(ToolbarDataProvider toolbarDataProvider) {
-        mToolbarDataProvider = toolbarDataProvider;
-        mMediator.setToolbarCommonPropertiesModel(mToolbarDataProvider);
-        mStatusView.setToolbarCommonPropertiesModel(mToolbarDataProvider);
+    public void setLocationBarDataProvider(LocationBarDataProvider locationBarDataProvider) {
+        mLocationBarDataProvider = locationBarDataProvider;
+        mMediator.setLocationBarDataProvider(mLocationBarDataProvider);
+        mStatusView.setLocationBarDataProvider(mLocationBarDataProvider);
         // Update status immediately after receiving the data provider to avoid initial presence
         // glitch on tablet devices. This glitch would be typically seen upon launch of app, right
         // before the landing page is presented to the user.
@@ -153,10 +153,11 @@
 
     /** Updates the security icon displayed in the LocationBar. */
     public void updateStatusIcon() {
-        mMediator.setSecurityIconResource(mToolbarDataProvider.getSecurityIconResource(mIsTablet));
-        mMediator.setSecurityIconTint(mToolbarDataProvider.getSecurityIconColorStateList());
+        mMediator.setSecurityIconResource(
+                mLocationBarDataProvider.getSecurityIconResource(mIsTablet));
+        mMediator.setSecurityIconTint(mLocationBarDataProvider.getSecurityIconColorStateList());
         mMediator.setSecurityIconDescription(
-                mToolbarDataProvider.getSecurityIconContentDescriptionResourceId());
+                mLocationBarDataProvider.getSecurityIconContentDescriptionResourceId());
 
         // TODO(ender): drop these during final cleanup round.
         updateVerboseStatusVisibility();
@@ -199,24 +200,24 @@
      * omnibox.
      */
     private void updateVerboseStatusVisibility() {
-        // TODO(ender): turn around logic for ToolbarDataProvider to offer
+        // TODO(ender): turn around logic for LocationBarDataProvider to offer
         // notifications rather than polling for these attributes.
-        mMediator.setPageSecurityLevel(mToolbarDataProvider.getSecurityLevel());
-        mMediator.setPageIsOffline(mToolbarDataProvider.isOfflinePage());
-        mMediator.setPageIsPreview(mToolbarDataProvider.isPreview());
-        mMediator.setPageIsPaintPreview(mToolbarDataProvider.isPaintPreview());
+        mMediator.setPageSecurityLevel(mLocationBarDataProvider.getSecurityLevel());
+        mMediator.setPageIsOffline(mLocationBarDataProvider.isOfflinePage());
+        mMediator.setPageIsPreview(mLocationBarDataProvider.isPreview());
+        mMediator.setPageIsPaintPreview(mLocationBarDataProvider.isPaintPreview());
     }
 
     @Override
     public void onClick(View view) {
         if (mUrlHasFocus) return;
 
-        if (!mToolbarDataProvider.hasTab()
-                || mToolbarDataProvider.getTab().getWebContents() == null) {
+        if (!mLocationBarDataProvider.hasTab()
+                || mLocationBarDataProvider.getTab().getWebContents() == null) {
             return;
         }
 
-        Tab tab = mToolbarDataProvider.getTab();
+        Tab tab = mLocationBarDataProvider.getTab();
         WebContents webContents = tab.getWebContents();
         Activity activity = TabUtils.getActivity(tab);
         PageInfoController.show(activity, webContents, null,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusMediator.java
index 92f67ff..1040dba 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusMediator.java
@@ -20,6 +20,7 @@
 import org.chromium.base.annotations.MockedInTests;
 import org.chromium.base.library_loader.LibraryLoader;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.omnibox.LocationBarDataProvider;
 import org.chromium.chrome.browser.omnibox.SearchEngineLogoUtils;
 import org.chromium.chrome.browser.omnibox.UrlBarEditingTextStateProvider;
 import org.chromium.chrome.browser.omnibox.status.StatusProperties.StatusIconResource;
@@ -27,7 +28,6 @@
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tabmodel.IncognitoStateProvider;
 import org.chromium.chrome.browser.toolbar.ToolbarColors;
-import org.chromium.chrome.browser.toolbar.ToolbarCommonPropertiesModel;
 import org.chromium.components.security_state.ConnectionSecurityLevel;
 import org.chromium.content_public.browser.BrowserStartupController;
 import org.chromium.ui.modelutil.PropertyModel;
@@ -62,11 +62,6 @@
         boolean shouldShowSearchLoupeEverywhere(boolean isIncognito) {
             return SearchEngineLogoUtils.shouldShowSearchLoupeEverywhere(isIncognito);
         }
-
-        /** @see {@link SearchEngineLogoUtils#doesUrlMatchDefaultSearchEngine} */
-        boolean doesUrlMatchDefaultSearchEngine(String url) {
-            return SearchEngineLogoUtils.doesUrlMatchDefaultSearchEngine(url);
-        }
     }
 
     private final PropertyModel mModel;
@@ -100,7 +95,7 @@
     private Resources mResources;
     private Context mContext;
 
-    private ToolbarCommonPropertiesModel mToolbarCommonPropertiesModel;
+    private LocationBarDataProvider mLocationBarDataProvider;
     private UrlBarEditingTextStateProvider mUrlBarEditingTextStateProvider;
 
     private String mUrlBarTextWithAutocomplete = "";
@@ -146,9 +141,8 @@
     /**
      * Set the ToolbarDataProvider for this class.
      */
-    void setToolbarCommonPropertiesModel(
-            ToolbarCommonPropertiesModel toolbarCommonPropertiesModel) {
-        mToolbarCommonPropertiesModel = toolbarCommonPropertiesModel;
+    void setLocationBarDataProvider(LocationBarDataProvider toolbarCommonPropertiesModel) {
+        mLocationBarDataProvider = toolbarCommonPropertiesModel;
     }
 
     /**
@@ -307,7 +301,7 @@
         // Note: When mUrlFocusPercent is non-zero, that means we're still in the focused state from
         // scrolling on the NTP.
         if (!urlHasFocus && MathUtils.areFloatsEqual(mUrlFocusPercent, 0f)
-                && SearchEngineLogoUtils.currentlyOnNTP(mToolbarCommonPropertiesModel)) {
+                && SearchEngineLogoUtils.currentlyOnNTP(mLocationBarDataProvider)) {
             setStatusIconShown(false);
         }
     }
@@ -336,7 +330,7 @@
         }
 
         // Only fade the animation on the new tab page.
-        if (SearchEngineLogoUtils.currentlyOnNTP(mToolbarCommonPropertiesModel)) {
+        if (SearchEngineLogoUtils.currentlyOnNTP(mLocationBarDataProvider)) {
             float focusAnimationProgress = percent;
             if (!mUrlHasFocus) {
                 focusAnimationProgress = MathUtils.clamp(
@@ -530,23 +524,12 @@
     boolean maybeUpdateStatusIconForSearchEngineIcon() {
         boolean showIconWhenFocused = mUrlHasFocus && mShowStatusIconWhenUrlFocused;
         boolean showIconWhenScrollingOnNTP =
-                SearchEngineLogoUtils.currentlyOnNTP(mToolbarCommonPropertiesModel)
-                && mUrlFocusPercent > 0 && !mUrlHasFocus
-                && !mToolbarCommonPropertiesModel.isLoading() && mShowStatusIconWhenUrlFocused;
-        // Show the logo unfocused if "Query in the omnibox" is active or we're on the NTP. Current
-        // "Query in the omnibox" behavior makes it active for non-dse searches if you've just
-        // changed your default search engine.The included workaround below
-        // (doesUrlMatchDefaultSearchEngine) can be removed once this is fixed.
-        // TODO(crbug.com/991017): Remove doesUrlMatchDefaultSearchEngine when "Query in the
-        //                         omnibox" properly reacts to dse changes.
-        boolean showUnfocusedSearchResultsPage = !mUrlHasFocus
-                && mToolbarCommonPropertiesModel != null
-                && mToolbarCommonPropertiesModel.getDisplaySearchTerms() != null
-                && mDelegate.doesUrlMatchDefaultSearchEngine(
-                        mToolbarCommonPropertiesModel.getCurrentUrl());
+                SearchEngineLogoUtils.currentlyOnNTP(mLocationBarDataProvider)
+                && mUrlFocusPercent > 0 && !mUrlHasFocus && !mLocationBarDataProvider.isLoading()
+                && mShowStatusIconWhenUrlFocused;
+        // Show the logo unfocused if we're on the NTP.
         if (mDelegate.shouldShowSearchEngineLogo(mIsIncognito) && mIsSearchEngineStateSetup
-                && (showIconWhenFocused || showIconWhenScrollingOnNTP
-                        || showUnfocusedSearchResultsPage)) {
+                && (showIconWhenFocused || showIconWhenScrollingOnNTP)) {
             getStatusIconResourceForSearchEngineIcon(mIsIncognito, (statusIconRes) -> {
                 mModel.set(StatusProperties.STATUS_ICON_RESOURCE, statusIconRes);
             });
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusView.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusView.java
index 23c60f9..24a6f35 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusView.java
@@ -26,8 +26,8 @@
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.omnibox.LocationBarDataProvider;
 import org.chromium.chrome.browser.omnibox.SearchEngineLogoUtils;
-import org.chromium.chrome.browser.toolbar.ToolbarCommonPropertiesModel;
 import org.chromium.components.browser_ui.widget.CompositeTouchDelegate;
 import org.chromium.ui.widget.Toast;
 
@@ -74,7 +74,7 @@
     private boolean mLastTouchDelegateRtlness;
     private Rect mLastTouchDelegateRect;
 
-    private ToolbarCommonPropertiesModel mToolbarCommonPropertiesModel;
+    private LocationBarDataProvider mLocationBarDataProvider;
 
     public StatusView(Context context, AttributeSet attributes) {
         super(context, attributes);
@@ -93,9 +93,8 @@
         configureAccessibilityDescriptions();
     }
 
-    void setToolbarCommonPropertiesModel(
-            ToolbarCommonPropertiesModel toolbarCommonPropertiesModel) {
-        mToolbarCommonPropertiesModel = toolbarCommonPropertiesModel;
+    void setLocationBarDataProvider(LocationBarDataProvider toolbarCommonPropertiesModel) {
+        mLocationBarDataProvider = toolbarCommonPropertiesModel;
     }
 
     /**
@@ -103,9 +102,8 @@
      */
     public void updateSearchEngineStatusIcon(boolean shouldShowSearchEngineLogo,
             boolean isSearchEngineGoogle, String searchEngineUrl) {
-        if (mToolbarCommonPropertiesModel != null
-                && mDelegate.shouldShowSearchEngineLogo(
-                        mToolbarCommonPropertiesModel.isIncognito())) {
+        if (mLocationBarDataProvider != null
+                && mDelegate.shouldShowSearchEngineLogo(mLocationBarDataProvider.isIncognito())) {
             LinearLayout.LayoutParams layoutParams =
                     new LinearLayout.LayoutParams(mIconView.getLayoutParams());
             layoutParams.setMarginEnd(0);
@@ -154,9 +152,8 @@
         // This is to prevent the visibility of the view being changed both implicitly here and
         // explicitly in setStatusIconShown. The visibility should only be set here through code not
         // related to the dse icon.
-        if (mToolbarCommonPropertiesModel != null
-                && mDelegate.shouldShowSearchEngineLogo(
-                        mToolbarCommonPropertiesModel.isIncognito())) {
+        if (mLocationBarDataProvider != null
+                && mDelegate.shouldShowSearchEngineLogo(mLocationBarDataProvider.isIncognito())) {
             return;
         }
 
@@ -315,9 +312,8 @@
         // This is to prevent the visibility of the view being changed both explicitly here and
         // implicitly in animateStatusIcon. The visibility should only be set here through code
         // related to the dse icon.
-        if (mToolbarCommonPropertiesModel != null
-                && !mDelegate.shouldShowSearchEngineLogo(
-                        mToolbarCommonPropertiesModel.isIncognito())) {
+        if (mLocationBarDataProvider != null
+                && !mDelegate.shouldShowSearchEngineLogo(mLocationBarDataProvider.isIncognito())) {
             // Let developers know that they shouldn't use this code-path.
             assert false : "Only DSE icon code should set the status icon visibility manually.";
             return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator.java
index ce7f821..587c117 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator.java
@@ -11,13 +11,13 @@
 import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.browser.ActivityTabProvider;
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
+import org.chromium.chrome.browser.omnibox.LocationBarDataProvider;
 import org.chromium.chrome.browser.omnibox.UrlBar.UrlTextChangeListener;
 import org.chromium.chrome.browser.omnibox.UrlFocusChangeListener;
 import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteController.OnSuggestionsReceivedListener;
 import org.chromium.chrome.browser.omnibox.voice.VoiceRecognitionHandler;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.share.ShareDelegate;
-import org.chromium.chrome.browser.toolbar.ToolbarDataProvider;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
 
@@ -36,9 +36,9 @@
 
     /**
      * Provides data and state for the toolbar component.
-     * @param toolbarDataProvider The data provider.
+     * @param locationBarDataProvider The data provider.
      */
-    void setToolbarDataProvider(ToolbarDataProvider toolbarDataProvider);
+    void setLocationBarDataProvider(LocationBarDataProvider locationBarDataProvider);
 
     /**
      * @param overviewModeBehavior A means of accessing the current OverviewModeState and a way to
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinatorImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinatorImpl.java
index a03f9ca6..6a4d55f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinatorImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinatorImpl.java
@@ -21,6 +21,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ActivityTabProvider;
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
+import org.chromium.chrome.browser.omnibox.LocationBarDataProvider;
 import org.chromium.chrome.browser.omnibox.UrlBarEditingTextStateProvider;
 import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteController.OnSuggestionsReceivedListener;
 import org.chromium.chrome.browser.omnibox.suggestions.SuggestionListViewBinder.SuggestionListViewHolder;
@@ -40,7 +41,6 @@
 import org.chromium.chrome.browser.omnibox.voice.VoiceRecognitionHandler;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.share.ShareDelegate;
-import org.chromium.chrome.browser.toolbar.ToolbarDataProvider;
 import org.chromium.chrome.browser.util.KeyNavigationUtil;
 import org.chromium.components.query_tiles.QueryTile;
 import org.chromium.ui.ViewProvider;
@@ -215,8 +215,8 @@
     }
 
     @Override
-    public void setToolbarDataProvider(ToolbarDataProvider toolbarDataProvider) {
-        mMediator.setToolbarDataProvider(toolbarDataProvider);
+    public void setLocationBarDataProvider(LocationBarDataProvider locationBarDataProvider) {
+        mMediator.setLocationBarDataProvider(locationBarDataProvider);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java
index 1ba47c71..972e3c3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java
@@ -38,6 +38,7 @@
 import org.chromium.chrome.browser.init.AsyncInitializationActivity;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.lifecycle.StartStopWithNativeObserver;
+import org.chromium.chrome.browser.omnibox.LocationBarDataProvider;
 import org.chromium.chrome.browser.omnibox.OmniboxSuggestionType;
 import org.chromium.chrome.browser.omnibox.UrlBarEditingTextStateProvider;
 import org.chromium.chrome.browser.omnibox.styles.OmniboxResourceProvider;
@@ -52,7 +53,6 @@
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelUtils;
 import org.chromium.chrome.browser.tabmodel.TabWindowManager;
-import org.chromium.chrome.browser.toolbar.ToolbarDataProvider;
 import org.chromium.components.embedder_support.util.UrlConstants;
 import org.chromium.components.query_tiles.QueryTile;
 import org.chromium.content_public.browser.WebContents;
@@ -93,7 +93,7 @@
     private final Handler mHandler;
     private AutocompleteResult mAutocompleteResult;
 
-    private ToolbarDataProvider mDataProvider;
+    private LocationBarDataProvider mDataProvider;
     private OverviewModeBehavior mOverviewModeBehavior;
     private OverviewModeBehavior.OverviewModeObserver mOverviewModeObserver;
 
@@ -262,7 +262,7 @@
     /**
      * Sets the data provider for the toolbar.
      */
-    void setToolbarDataProvider(ToolbarDataProvider provider) {
+    void setLocationBarDataProvider(LocationBarDataProvider provider) {
         mDataProvider = provider;
     }
 
@@ -741,7 +741,7 @@
                 mRequestSuggestions = null;
 
                 // There may be no tabs when searching form omnibox in overview mode. In that case,
-                // ToolbarDataProvider.getCurrentUrl() returns NTP url.
+                // LocationBarDataProvider.getCurrentUrl() returns NTP url.
                 if (!mDataProvider.hasTab() && !mDataProvider.isInOverviewAndShowingOmnibox()) {
                     // crbug.com/764749
                     Log.w(TAG, "onTextChangedForAutocomplete: no tab");
@@ -904,13 +904,6 @@
             // (e.g. manually retyping the same search query), and it seems wrong to
             // treat this as a reload.
             transition = PageTransition.RELOAD;
-        } else if (((transition & PageTransition.CORE_MASK) == PageTransition.GENERATED)
-                && TextUtils.equals(
-                        suggestion.getFillIntoEdit(), mDataProvider.getDisplaySearchTerms())) {
-            // When the omnibox is displaying the default search provider search terms,
-            // the user focuses the omnibox, and hits Enter without refining the search
-            // terms, we should classify this transition as a RELOAD.
-            transition = PageTransition.RELOAD;
         } else if (type == OmniboxSuggestionType.URL_WHAT_YOU_TYPED
                 && mUrlBarEditingTextProvider.wasLastEditPaste()) {
             // It's important to use the page transition from the suggestion or we might end
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessor.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessor.java
index 0953fb8e..3e87139 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessor.java
@@ -9,7 +9,6 @@
 
 import androidx.annotation.DrawableRes;
 
-import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
@@ -67,13 +66,6 @@
         return new PropertyModel(SuggestionViewProperties.ALL_KEYS);
     }
 
-    @Override
-    public void recordItemPresented(PropertyModel model) {
-        RecordHistogram.recordEnumeratedHistogram("Omnibox.IconOrFaviconShown",
-                model.get(SuggestionViewProperties.SUGGESTION_ICON_TYPE),
-                SuggestionIcon.TOTAL_COUNT);
-    }
-
     /**
      * Returns suggestion icon to be presented for specified omnibox suggestion.
      *
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/SuggestionViewProperties.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/SuggestionViewProperties.java
index 9133328..a7d807ea 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/SuggestionViewProperties.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/SuggestionViewProperties.java
@@ -23,22 +23,18 @@
 public class SuggestionViewProperties {
     @IntDef({SuggestionIcon.UNSET, SuggestionIcon.BOOKMARK, SuggestionIcon.HISTORY,
             SuggestionIcon.GLOBE, SuggestionIcon.MAGNIFIER, SuggestionIcon.VOICE,
-            SuggestionIcon.CALCULATOR, SuggestionIcon.FAVICON, SuggestionIcon.TRENDS,
-            SuggestionIcon.TOTAL_COUNT})
+            SuggestionIcon.FAVICON, SuggestionIcon.TRENDS, SuggestionIcon.TOTAL_COUNT})
     @Retention(RetentionPolicy.SOURCE)
     public @interface SuggestionIcon {
-        // This enum is used to back UMA histograms, and should therefore be treated as append-only.
-        // See http://cs.chromium.org/SuggestionIconOrFaviconType
         int UNSET = 0;
         int BOOKMARK = 1;
         int HISTORY = 2;
         int GLOBE = 3;
         int MAGNIFIER = 4;
         int VOICE = 5;
-        int CALCULATOR = 6;
-        int FAVICON = 7;
-        int TRENDS = 8;
-        int TOTAL_COUNT = 9;
+        int FAVICON = 6;
+        int TRENDS = 7;
+        int TOTAL_COUNT = 8;
     }
 
     /** The suggestion icon type shown. @see SuggestionIcon. Used for metric collection purposes. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandler.java
index 0a6b063..2f211bd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandler.java
@@ -20,10 +20,10 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.omnibox.LocationBarDataProvider;
 import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteCoordinator;
 import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.browser.toolbar.ToolbarDataProvider;
 import org.chromium.chrome.browser.util.VoiceRecognitionUtil;
 import org.chromium.content_public.browser.NavigationHandle;
 import org.chromium.content_public.browser.RenderFrameHost;
@@ -90,11 +90,11 @@
         void setSearchQuery(final String query);
 
         /**
-         * Grabs a reference to the toolbar data provider from the location bar.
-         * @return The {@link ToolbarDataProvider} currently in use by the
+         * Grabs a reference to the location data provider from the location bar.
+         * @return The {@link LocationBarDataProvider} currently in use by the
          *         {@link LocationBarLayout}.
          */
-        ToolbarDataProvider getToolbarDataProvider();
+        LocationBarDataProvider getLocationBarDataProvider();
 
         /**
          * Grabs a reference to the autocomplete coordinator from the location bar.
@@ -287,8 +287,10 @@
             }
 
             // Since voice was used, we need to let the frame know that there was a user gesture.
-            ToolbarDataProvider toolbarDataProvider = mDelegate.getToolbarDataProvider();
-            Tab currentTab = toolbarDataProvider != null ? toolbarDataProvider.getTab() : null;
+            LocationBarDataProvider locationBarDataProvider =
+                    mDelegate.getLocationBarDataProvider();
+            Tab currentTab =
+                    locationBarDataProvider != null ? locationBarDataProvider.getTab() : null;
             if (currentTab != null) {
                 if (mVoiceSearchWebContentsObserver != null) {
                     mVoiceSearchWebContentsObserver.destroy();
@@ -448,10 +450,10 @@
      * @return Whether or not voice search is enabled.
      */
     public boolean isVoiceSearchEnabled() {
-        ToolbarDataProvider toolbarDataProvider = mDelegate.getToolbarDataProvider();
-        if (toolbarDataProvider == null) return false;
+        LocationBarDataProvider locationBarDataProvider = mDelegate.getLocationBarDataProvider();
+        if (locationBarDataProvider == null) return false;
 
-        boolean isIncognito = toolbarDataProvider.isIncognito();
+        boolean isIncognito = locationBarDataProvider.isIncognito();
         WindowAndroid windowAndroid = mDelegate.getWindowAndroid();
         if (windowAndroid == null || isIncognito) return false;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
index aa8eb84..2892787 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
@@ -164,7 +164,7 @@
         mSearchBox = (SearchActivityLocationBarLayout) mContentView.findViewById(
                 R.id.search_location_bar);
         mSearchBox.setDelegate(this);
-        mSearchBox.setToolbarDataProvider(mSearchBoxDataProvider);
+        mSearchBox.setLocationBarDataProvider(mSearchBoxDataProvider);
         mSearchBox.initializeControls(
                 new WindowDelegate(getWindow()), getWindowAndroid(), null, null, null, null);
         mSearchBox.setProfileSupplier(mProfileSupplier);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchBoxDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchBoxDataProvider.java
index 63026665..7ac43b9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchBoxDataProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchBoxDataProvider.java
@@ -11,14 +11,14 @@
 
 import org.chromium.base.library_loader.LibraryLoader;
 import org.chromium.chrome.browser.ntp.NewTabPage;
+import org.chromium.chrome.browser.omnibox.LocationBarDataProvider;
 import org.chromium.chrome.browser.omnibox.UrlBarData;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.browser.toolbar.ToolbarDataProvider;
 import org.chromium.components.browser_ui.styles.ChromeColors;
 import org.chromium.components.security_state.ConnectionSecurityLevel;
 
-class SearchBoxDataProvider implements ToolbarDataProvider {
+class SearchBoxDataProvider implements LocationBarDataProvider {
     private final @ColorInt int mPrimaryColor;
     private Tab mTab;
 
@@ -95,6 +95,11 @@
     }
 
     @Override
+    public boolean isLoading() {
+        return false;
+    }
+
+    @Override
     public String getCurrentUrl() {
         return SearchWidgetProvider.getDefaultSearchEngineUrl();
     }
@@ -123,4 +128,9 @@
     public @ColorRes int getSecurityIconColorStateList() {
         return 0;
     }
+
+    @Override
+    public int getSecurityIconContentDescriptionResourceId() {
+        return 0;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
index 9ce05a9a..d9b0cf3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
@@ -13,6 +13,7 @@
 import androidx.annotation.ColorRes;
 import androidx.annotation.DrawableRes;
 import androidx.annotation.Nullable;
+import androidx.annotation.StringRes;
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.annotations.CalledByNative;
@@ -24,6 +25,7 @@
 import org.chromium.chrome.browser.ntp.NewTabPage;
 import org.chromium.chrome.browser.offlinepages.OfflinePageUtils;
 import org.chromium.chrome.browser.omnibox.ChromeAutocompleteSchemeClassifier;
+import org.chromium.chrome.browser.omnibox.LocationBarDataProvider;
 import org.chromium.chrome.browser.omnibox.SearchEngineLogoUtils;
 import org.chromium.chrome.browser.omnibox.UrlBarData;
 import org.chromium.chrome.browser.paint_preview.TabbedPaintPreview;
@@ -49,7 +51,7 @@
 /**
  * Provides a way of accessing toolbar data and state.
  */
-public class LocationBarModel implements ToolbarDataProvider, ToolbarCommonPropertiesModel {
+public class LocationBarModel implements ToolbarDataProvider, LocationBarDataProvider {
     private final Context mContext;
 
     private Tab mTab;
@@ -372,6 +374,12 @@
                 getSecurityLevel(), !isTablet, isOfflinePage(), isPreview(), isPaintPreview());
     }
 
+    @Override
+    @StringRes
+    public int getSecurityIconContentDescriptionResourceId() {
+        return SecurityStatusIcon.getSecurityIconContentDescriptionResourceId(getSecurityLevel());
+    }
+
     @VisibleForTesting
     @ConnectionSecurityLevel
     int getSecurityLevel(Tab tab, boolean isOfflinePage, @Nullable String publisherUrl) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarCommonPropertiesModel.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarCommonPropertiesModel.java
deleted file mode 100644
index 1134f02..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarCommonPropertiesModel.java
+++ /dev/null
@@ -1,46 +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.
-
-package org.chromium.chrome.browser.toolbar;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import org.chromium.chrome.browser.ntp.NewTabPage;
-
-/**
- * Defines an interface that provides common properties to toolbar and omnibox classes.
- */
-public interface ToolbarCommonPropertiesModel {
-    /**
-     * @return The current url for the current tab. Returns empty string when there is no tab.
-     */
-    @NonNull
-    String getCurrentUrl();
-
-    /**
-     * @return The NewTabPage shown for the current Tab or null if one is not being shown.
-     */
-    NewTabPage getNewTabPageForCurrentTab();
-
-    /**
-     * @return Whether the toolbar is currently being displayed for incognito.
-     */
-    boolean isIncognito();
-
-    /** @return Whether the current {@link Tab} is loading. */
-    boolean isLoading();
-
-    /**
-     * If the current tab state is eligible for displaying the search query terms instead of the
-     * URL, this extracts the query terms from the current URL.
-     *
-     * @return The search terms. Returns null if the tab is ineligible to display the search terms
-     *         instead of the URL.
-     */
-    @Nullable
-    default String getDisplaySearchTerms() {
-        return null;
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarDataProvider.java
index f374078d..19fb462 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarDataProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarDataProvider.java
@@ -4,61 +4,37 @@
 
 package org.chromium.chrome.browser.toolbar;
 
-import android.content.res.ColorStateList;
-
-import androidx.annotation.ColorRes;
-import androidx.annotation.DrawableRes;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.annotation.StringRes;
-
 import org.chromium.chrome.browser.ntp.NewTabPage;
 import org.chromium.chrome.browser.omnibox.UrlBarData;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.components.omnibox.SecurityStatusIcon;
-import org.chromium.components.security_state.ConnectionSecurityLevel;
 
 /**
  * Defines the data that is exposed to properly render the Toolbar.
  */
-// TODO(crbug.com/865801): Refine split between common/generally toolbar properties and
-//                         sub-component properties.
-public interface ToolbarDataProvider extends ToolbarCommonPropertiesModel {
+public interface ToolbarDataProvider {
     /**
      * @return The tab that contains the information currently displayed in the toolbar.
      */
     @Nullable
     Tab getTab();
 
-    @Override
-    default boolean isLoading() {
-        Tab tab = getTab();
-        return tab != null && tab.isLoading();
-    }
-
-    /**
-     * @return Whether ToolbarDataProvider currently has a tab related to it.
-     */
-    boolean hasTab();
-
     /**
      * @return The current url for the current tab. Returns empty string when there is no tab.
      */
     @NonNull
-    @Override
     String getCurrentUrl();
 
     /**
      * @return The NewTabPage shown for the current Tab or null if one is not being shown.
      */
-    @Override
     NewTabPage getNewTabPageForCurrentTab();
 
     /**
      * @return Whether the toolbar is currently being displayed for incognito.
      */
-    @Override
     boolean isIncognito();
 
     /**
@@ -83,11 +59,6 @@
     UrlBarData getUrlBarData();
 
     /**
-     * @return The title of the current tab, or the empty string if there is currently no tab.
-     */
-    String getTitle();
-
-    /**
      * @return The primary color to use for the background drawable.
      */
     int getPrimaryColor();
@@ -96,55 +67,4 @@
      * @return Whether the current primary color is a brand color.
      */
     boolean isUsingBrandColor();
-
-    /**
-     * @return Whether the page currently shown is an offline page.
-     */
-    boolean isOfflinePage();
-
-    /**
-     * @return Whether the page currently shown is a preview.
-     */
-    boolean isPreview();
-
-    /**
-     * @return Whether the page currently shown is a paint preview.
-     */
-    default boolean isPaintPreview() {
-        return false;
-    }
-
-    /**
-     * @return The current {@link ConnectionSecurityLevel}.
-     */
-    @ConnectionSecurityLevel
-    int getSecurityLevel();
-
-    /**
-     * @param isFocusedFromFakebox If the omnibox focus originated from the fakebox.
-     * @return The current page classification.
-     */
-    default int getPageClassification(boolean isFocusedFromFakebox) {
-        return 0;
-    }
-
-    /**
-     * @return The resource ID of the icon that should be displayed or 0 if no icon should be shown.
-     */
-    @DrawableRes
-    int getSecurityIconResource(boolean isTablet);
-
-    /**
-     * @return The resource ID of the content description for the security icon.
-     */
-    @StringRes
-    default int getSecurityIconContentDescriptionResourceId() {
-        return SecurityStatusIcon.getSecurityIconContentDescriptionResourceId(getSecurityLevel());
-    }
-
-    /**
-     * @return The {@link ColorStateList} to use to tint the security state icon.
-     */
-    @ColorRes
-    int getSecurityIconColorStateList();
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
index 1212619..9602b02 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
@@ -19,7 +19,6 @@
 import android.widget.ProgressBar;
 
 import androidx.annotation.CallSuper;
-import androidx.annotation.ColorRes;
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
@@ -51,7 +50,6 @@
 import org.chromium.chrome.browser.toolbar.menu_button.MenuButtonCoordinator;
 import org.chromium.chrome.browser.toolbar.top.TopToolbarCoordinator.UrlExpansionObserver;
 import org.chromium.chrome.browser.ui.appmenu.AppMenuButtonHelper;
-import org.chromium.components.security_state.ConnectionSecurityLevel;
 import org.chromium.ui.UiUtils;
 import org.chromium.ui.base.ViewUtils;
 
@@ -258,11 +256,6 @@
             }
 
             @Override
-            public boolean hasTab() {
-                return false;
-            }
-
-            @Override
             public String getCurrentUrl() {
                 return "";
             }
@@ -273,11 +266,6 @@
             }
 
             @Override
-            public String getTitle() {
-                return "";
-            }
-
-            @Override
             public NewTabPage getNewTabPageForCurrentTab() {
                 return null;
             }
@@ -291,31 +279,6 @@
             public boolean isUsingBrandColor() {
                 return false;
             }
-
-            @Override
-            public boolean isOfflinePage() {
-                return false;
-            }
-
-            @Override
-            public boolean isPreview() {
-                return false;
-            }
-
-            @Override
-            public int getSecurityLevel() {
-                return ConnectionSecurityLevel.NONE;
-            }
-
-            @Override
-            public int getSecurityIconResource(boolean isTablet) {
-                return 0;
-            }
-
-            @Override
-            public @ColorRes int getSecurityIconColorStateList() {
-                return 0;
-            }
         };
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java
index 59613bf..90f2c0cc 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java
@@ -133,7 +133,7 @@
         mTestLocationBarModel.setTab(tab, tab.isIncognito());
 
         TestThreadUtils.runOnUiThreadBlocking(
-                () -> getLocationBar().setToolbarDataProvider(mTestLocationBarModel));
+                () -> getLocationBar().setLocationBarDataProvider(mTestLocationBarModel));
     }
 
     private void setUrlToPageUrl(LocationBarLayout locationBar) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusMediatorUnitTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusMediatorUnitTest.java
index 6ef73cdcf5..f48a0e4 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusMediatorUnitTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusMediatorUnitTest.java
@@ -39,8 +39,8 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.ntp.NewTabPage;
+import org.chromium.chrome.browser.omnibox.LocationBarDataProvider;
 import org.chromium.chrome.browser.omnibox.UrlBarEditingTextStateProvider;
-import org.chromium.chrome.browser.toolbar.ToolbarCommonPropertiesModel;
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
 import org.chromium.components.embedder_support.util.UrlConstants;
@@ -63,7 +63,7 @@
     @Mock
     NewTabPage mNewTabPage;
     @Mock
-    ToolbarCommonPropertiesModel mToolbarCommonPropertiesModel;
+    LocationBarDataProvider mLocationBarDataProvider;
     @Mock
     UrlBarEditingTextStateProvider mUrlBarEditingTextStateProvider;
     @Mock
@@ -95,7 +95,7 @@
             mMediator = new StatusMediator(mModel, mResources, mContext,
                     mUrlBarEditingTextStateProvider,
                     /* isTablet */ false, mMockForceModelViewReconciliationRunnable);
-            mMediator.setToolbarCommonPropertiesModel(mToolbarCommonPropertiesModel);
+            mMediator.setLocationBarDataProvider(mLocationBarDataProvider);
             mMediator.setDelegateForTesting(mDelegate);
         });
         mBitmap = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888);
@@ -124,8 +124,8 @@
     @UiThreadTest
     public void searchEngineLogo_showGoogleLogo_hideAfterAnimationFinished() {
         setupSearchEngineLogoForTesting(true, false, false);
-        doReturn(mNewTabPage).when(mToolbarCommonPropertiesModel).getNewTabPageForCurrentTab();
-        doReturn("chrome://newtab").when(mToolbarCommonPropertiesModel).getCurrentUrl();
+        doReturn(mNewTabPage).when(mLocationBarDataProvider).getNewTabPageForCurrentTab();
+        doReturn("chrome://newtab").when(mLocationBarDataProvider).getCurrentUrl();
 
         mMediator.updateSearchEngineStatusIcon(true, true, TEST_SEARCH_URL);
         mMediator.setUrlHasFocus(false);
@@ -169,9 +169,9 @@
     @UiThreadTest
     public void searchEngineLogo_showGoogleLogo_whenScrolled() {
         setupSearchEngineLogoForTesting(true, false, false);
-        doReturn(false).when(mToolbarCommonPropertiesModel).isLoading();
-        doReturn(UrlConstants.NTP_URL).when(mToolbarCommonPropertiesModel).getCurrentUrl();
-        doReturn(mNewTabPage).when(mToolbarCommonPropertiesModel).getNewTabPageForCurrentTab();
+        doReturn(false).when(mLocationBarDataProvider).isLoading();
+        doReturn(UrlConstants.NTP_URL).when(mLocationBarDataProvider).getCurrentUrl();
+        doReturn(mNewTabPage).when(mLocationBarDataProvider).getNewTabPageForCurrentTab();
 
         mMediator.setUrlHasFocus(false);
         mMediator.setShowIconsWhenUrlFocused(true);
@@ -346,7 +346,7 @@
     @UiThreadTest
     public void searchEngineLogo_incognitoNoIcon() {
         setupSearchEngineLogoForTesting(true, true, false);
-        doReturn(true).when(mToolbarCommonPropertiesModel).isIncognito();
+        doReturn(true).when(mLocationBarDataProvider).isIncognito();
 
         mMediator.setUrlHasFocus(false);
         mMediator.setShowIconsWhenUrlFocused(true);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusViewRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusViewRenderTest.java
index d569ccc9..a7b118e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusViewRenderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusViewRenderTest.java
@@ -71,8 +71,7 @@
                                   .inflate(org.chromium.chrome.R.layout.location_status, view, true)
                                   .findViewById(org.chromium.chrome.R.id.location_bar_status);
             mStatusView.setCompositeTouchDelegate(new CompositeTouchDelegate(view));
-            mStatusView.setToolbarCommonPropertiesModel(
-                    new LocationBarModel(mStatusView.getContext()));
+            mStatusView.setLocationBarDataProvider(new LocationBarModel(mStatusView.getContext()));
             mStatusModel = new PropertyModel.Builder(StatusProperties.ALL_KEYS).build();
             PropertyModelChangeProcessor.create(mStatusModel, mStatusView, new StatusViewBinder());
         });
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusViewTest.java
index 675c2833..20eb9d2e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusViewTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusViewTest.java
@@ -75,8 +75,8 @@
                                   .findViewById(R.id.location_bar_status);
             mStatusView.setDelegateForTesting(mStatusViewDelegate);
             mStatusView.setCompositeTouchDelegate(new CompositeTouchDelegate(view));
-            mStatusView.setToolbarCommonPropertiesModel(
-                    new LocationBarModel(mStatusView.getContext()));
+
+            mStatusView.setLocationBarDataProvider(new LocationBarModel(mStatusView.getContext()));
             mStatusModel = new PropertyModel.Builder(StatusProperties.ALL_KEYS).build();
             mStatusMCP = PropertyModelChangeProcessor.create(
                     mStatusModel, mStatusView, new StatusViewBinder());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java
index d1fff696..d334795 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java
@@ -42,11 +42,11 @@
 import org.chromium.base.test.UiThreadTest;
 import org.chromium.base.test.util.Batch;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.omnibox.LocationBarDataProvider;
 import org.chromium.chrome.browser.omnibox.OmniboxSuggestionType;
 import org.chromium.chrome.browser.omnibox.UrlBarEditingTextStateProvider;
 import org.chromium.chrome.browser.omnibox.suggestions.header.HeaderProcessor;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.toolbar.ToolbarDataProvider;
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
 import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
@@ -86,7 +86,7 @@
     AutocompleteController mAutocompleteController;
 
     @Mock
-    ToolbarDataProvider mToolbarDataProvider;
+    LocationBarDataProvider mLocationBarDataProvider;
 
     @Mock
     Handler mHandler;
@@ -108,7 +108,7 @@
         mMediator = new AutocompleteMediator(ContextUtils.getApplicationContext(),
                 mAutocompleteDelegate, mTextStateProvider, mAutocompleteController, mListModel,
                 mHandler);
-        mMediator.setToolbarDataProvider(mToolbarDataProvider);
+        mMediator.setLocationBarDataProvider(mLocationBarDataProvider);
         mMediator.getDropdownItemViewInfoListBuilderForTest().registerSuggestionProcessor(
                 mMockProcessor);
         mMediator.getDropdownItemViewInfoListBuilderForTest().setHeaderProcessorForTest(
@@ -340,11 +340,11 @@
         String url = "http://www.example.com";
         String title = "Title";
         int pageClassification = 2;
-        when(mToolbarDataProvider.getProfile()).thenReturn(profile);
-        when(mToolbarDataProvider.getCurrentUrl()).thenReturn(url);
-        when(mToolbarDataProvider.getTitle()).thenReturn(title);
-        when(mToolbarDataProvider.hasTab()).thenReturn(true);
-        when(mToolbarDataProvider.getPageClassification(false)).thenReturn(pageClassification);
+        when(mLocationBarDataProvider.getProfile()).thenReturn(profile);
+        when(mLocationBarDataProvider.getCurrentUrl()).thenReturn(url);
+        when(mLocationBarDataProvider.getTitle()).thenReturn(title);
+        when(mLocationBarDataProvider.hasTab()).thenReturn(true);
+        when(mLocationBarDataProvider.getPageClassification(false)).thenReturn(pageClassification);
 
         when(mTextStateProvider.getTextWithAutocomplete()).thenReturn("");
 
@@ -362,10 +362,10 @@
         Profile profile = Mockito.mock(Profile.class);
         String url = "http://www.example.com";
         int pageClassification = 2;
-        when(mToolbarDataProvider.getProfile()).thenReturn(profile);
-        when(mToolbarDataProvider.getCurrentUrl()).thenReturn(url);
-        when(mToolbarDataProvider.hasTab()).thenReturn(true);
-        when(mToolbarDataProvider.getPageClassification(false)).thenReturn(pageClassification);
+        when(mLocationBarDataProvider.getProfile()).thenReturn(profile);
+        when(mLocationBarDataProvider.getCurrentUrl()).thenReturn(url);
+        when(mLocationBarDataProvider.hasTab()).thenReturn(true);
+        when(mLocationBarDataProvider.getPageClassification(false)).thenReturn(pageClassification);
 
         when(mTextStateProvider.shouldAutocomplete()).thenReturn(true);
         when(mTextStateProvider.getSelectionStart()).thenReturn(4);
@@ -385,10 +385,10 @@
         Profile profile = Mockito.mock(Profile.class);
         String url = "http://www.example.com";
         int pageClassification = 2;
-        when(mToolbarDataProvider.getProfile()).thenReturn(profile);
-        when(mToolbarDataProvider.getCurrentUrl()).thenReturn(url);
-        when(mToolbarDataProvider.hasTab()).thenReturn(true);
-        when(mToolbarDataProvider.getPageClassification(false)).thenReturn(pageClassification);
+        when(mLocationBarDataProvider.getProfile()).thenReturn(profile);
+        when(mLocationBarDataProvider.getCurrentUrl()).thenReturn(url);
+        when(mLocationBarDataProvider.hasTab()).thenReturn(true);
+        when(mLocationBarDataProvider.getPageClassification(false)).thenReturn(pageClassification);
 
         when(mTextStateProvider.shouldAutocomplete()).thenReturn(true);
         when(mTextStateProvider.getSelectionStart()).thenReturn(4);
@@ -474,11 +474,11 @@
         String url = "http://www.example.com";
         String title = "Title";
         int pageClassification = 2;
-        when(mToolbarDataProvider.getProfile()).thenReturn(profile);
-        when(mToolbarDataProvider.getCurrentUrl()).thenReturn(url);
-        when(mToolbarDataProvider.getTitle()).thenReturn(title);
-        when(mToolbarDataProvider.hasTab()).thenReturn(true);
-        when(mToolbarDataProvider.getPageClassification(false)).thenReturn(pageClassification);
+        when(mLocationBarDataProvider.getProfile()).thenReturn(profile);
+        when(mLocationBarDataProvider.getCurrentUrl()).thenReturn(url);
+        when(mLocationBarDataProvider.getTitle()).thenReturn(title);
+        when(mLocationBarDataProvider.hasTab()).thenReturn(true);
+        when(mLocationBarDataProvider.getPageClassification(false)).thenReturn(pageClassification);
 
         when(mTextStateProvider.getTextWithAutocomplete()).thenReturn(url);
 
@@ -500,11 +500,11 @@
         String url = "http://www.example.com";
         String title = "Title";
         int pageClassification = 2;
-        when(mToolbarDataProvider.getProfile()).thenReturn(profile);
-        when(mToolbarDataProvider.getCurrentUrl()).thenReturn(url);
-        when(mToolbarDataProvider.getTitle()).thenReturn(title);
-        when(mToolbarDataProvider.hasTab()).thenReturn(true);
-        when(mToolbarDataProvider.getPageClassification(false)).thenReturn(pageClassification);
+        when(mLocationBarDataProvider.getProfile()).thenReturn(profile);
+        when(mLocationBarDataProvider.getCurrentUrl()).thenReturn(url);
+        when(mLocationBarDataProvider.getTitle()).thenReturn(title);
+        when(mLocationBarDataProvider.hasTab()).thenReturn(true);
+        when(mLocationBarDataProvider.getPageClassification(false)).thenReturn(pageClassification);
 
         when(mTextStateProvider.getTextWithAutocomplete()).thenReturn("");
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandlerTest.java
index 5a8ba75..6936bf8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandlerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandlerTest.java
@@ -34,6 +34,7 @@
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.ntp.NewTabPage;
+import org.chromium.chrome.browser.omnibox.LocationBarDataProvider;
 import org.chromium.chrome.browser.omnibox.UrlBarData;
 import org.chromium.chrome.browser.omnibox.UrlBarEditingTextStateProvider;
 import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteController.OnSuggestionsReceivedListener;
@@ -192,7 +193,7 @@
     /**
      * Test implementation of {@link ToolbarDataProvider}.
      */
-    private class TestDataProvider implements ToolbarDataProvider {
+    private class TestDataProvider implements LocationBarDataProvider {
         private boolean mIncognito;
 
         public void setIncognito(boolean incognito) {
@@ -283,6 +284,11 @@
         public @ColorRes int getSecurityIconColorStateList() {
             return 0;
         }
+
+        @Override
+        public int getSecurityIconContentDescriptionResourceId() {
+            return 0;
+        }
     }
 
     /**
@@ -331,7 +337,7 @@
         public void setSearchQuery(final String query) {}
 
         @Override
-        public ToolbarDataProvider getToolbarDataProvider() {
+        public LocationBarDataProvider getLocationBarDataProvider() {
             return mDataProvider;
         }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreviewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreviewTest.java
index 4678427..b934f07 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreviewTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreviewTest.java
@@ -10,7 +10,6 @@
 import android.support.test.InstrumentationRegistry;
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiObjectNotFoundException;
-import android.support.test.uiautomator.UiSelector;
 import android.view.ViewGroup;
 
 import androidx.test.filters.MediumTest;
@@ -27,7 +26,6 @@
 
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CallbackHelper;
-import org.chromium.base.test.util.DisabledTest;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.paint_preview.services.PaintPreviewTabService;
 import org.chromium.chrome.browser.tab.Tab;
@@ -176,7 +174,6 @@
     /**
      * Tests that the paint preview is removed when certain conditions are met.
      */
-    @DisabledTest(message = "crbug.com/1143219")
     @Test
     @MediumTest
     public void testRemoveOnActionbarClick() throws ExecutionException, UiObjectNotFoundException {
@@ -195,7 +192,8 @@
         int centerY = uiDevice.getDisplayHeight() / 2;
         uiDevice.swipe(centerX, centerY, centerX, centerY, 400);
         assertSnackbarVisibility(snackbarManager, true);
-        uiDevice.findObject(new UiSelector().text("Reload")).click();
+        TestThreadUtils.runOnUiThreadBlocking(()->
+                snackbarManager.getCurrentSnackbarForTesting().getController().onAction(null));
         assertAttachedAndShown(tabbedPaintPreview, false, false);
         Assert.assertEquals(
                 "Dismiss callback should have been called.", 1, dismissCallback.getCallCount());
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/digitalgoods/DigitalGoodsConverterTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/digitalgoods/DigitalGoodsConverterTest.java
index 36cf884..bdbfcc5 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/digitalgoods/DigitalGoodsConverterTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/digitalgoods/DigitalGoodsConverterTest.java
@@ -6,6 +6,7 @@
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
 
 import static org.chromium.chrome.browser.browserservices.digitalgoods.AcknowledgeConverter.PARAM_ACKNOWLEDGE_MAKE_AVAILABLE_AGAIN;
 import static org.chromium.chrome.browser.browserservices.digitalgoods.AcknowledgeConverter.PARAM_ACKNOWLEDGE_PURCHASE_TOKEN;
@@ -23,6 +24,7 @@
 import android.os.Bundle;
 import android.os.Parcelable;
 
+import androidx.annotation.Nullable;
 import androidx.browser.trusted.TrustedWebActivityCallback;
 
 import org.junit.Test;
@@ -68,6 +70,24 @@
 
         ItemDetails item = GetDetailsConverter.convertItemDetails(bundle);
         assertItemDetails(item, id, title, desc, currency, value);
+        assertSubsItemDetails(item, null, null, null, null, null);
+    }
+
+    @Test
+    public void convertItemDetails_subscriptions() {
+        String subsPeriod = "2 weeks";
+        String freeTrialPeriod = "1 week";
+        String introPriceCurrency = "GBP";
+        String introPriceValue = "3.0";
+        String introPricePeriod = "1 month";
+
+        Bundle bundle = GetDetailsConverter.createItemDetailsBundle("id", "Title", "desc", "GBP",
+                "10.0", subsPeriod, freeTrialPeriod, introPriceCurrency, introPriceValue,
+                introPricePeriod);
+
+        ItemDetails item = GetDetailsConverter.convertItemDetails(bundle);
+        assertSubsItemDetails(item, subsPeriod, freeTrialPeriod, introPriceCurrency,
+                introPriceValue, introPricePeriod);
     }
 
     /**
@@ -93,7 +113,9 @@
         int responseCode = 0;
         Parcelable[] items = {
                 GetDetailsConverter.createItemDetailsBundle("1", "t1", "d1", "c1", "v1"),
-                GetDetailsConverter.createItemDetailsBundle("2", "t2", "d2", "c2", "v2")};
+                GetDetailsConverter.createItemDetailsBundle(
+                        "2", "t2", "d2", "c2", "v2", "sp2", "ftp2", "ipc2", "ipv2", "ipp2")};
+
         args.putInt(RESPONSE_GET_DETAILS_RESPONSE_CODE, responseCode);
         args.putParcelableArray(RESPONSE_GET_DETAILS_DETAILS_LIST, items);
 
@@ -101,7 +123,9 @@
 
         assertEquals(responseCode, state.responseCode);
         assertItemDetails(state.itemDetails[0], "1", "t1", "d1", "c1", "v1");
+        assertSubsItemDetails(state.itemDetails[0], null, null, null, null, null);
         assertItemDetails(state.itemDetails[1], "2", "t2", "d2", "c2", "v2");
+        assertSubsItemDetails(state.itemDetails[1], "sp2", "ftp2", "ipc2", "ipv2", "ipp2");
     }
 
     private static void assertItemDetails(ItemDetails item, String id, String title, String desc,
@@ -113,6 +137,20 @@
         assertEquals(value, item.price.value);
     }
 
+    private static void assertSubsItemDetails(ItemDetails item, @Nullable String subsPeriod,
+            @Nullable String freeTrialPeriod, @Nullable String introPriceCurrency,
+            @Nullable String introPriceValue, @Nullable String intoPricePeriod) {
+        assertEquals(subsPeriod, item.subscriptionPeriod);
+        assertEquals(freeTrialPeriod, item.freeTrialPeriod);
+        if (introPriceCurrency == null || introPriceValue == null) {
+            assertNull(item.introductoryPrice);
+        } else {
+            assertEquals(introPriceCurrency, item.introductoryPrice.currency);
+            assertEquals(introPriceValue, item.introductoryPrice.value);
+        }
+        assertEquals(intoPricePeriod, item.introductoryPricePeriod);
+    }
+
     @Test
     public void convertAcknowledgeParams() {
         String token = "abcdef";
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index 69087df2..6310573 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-88.0.4305.0_rc-r1-merged.afdo.bz2
+chromeos-chrome-amd64-88.0.4306.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index a600186..f7faa836 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -4388,6 +4388,9 @@
           <message name="IDS_EXTENSIONS_UNPIN_FROM_TOOLBAR" desc="The text for the menu item to unpin an extension from the toolbar (sentence case).">
             Unpin
           </message>
+          <message name="IDS_EXTENSIONS_PINNED_BY_ADMIN" desc="The text indicating that an extension has been 'pinned' to the toolbar by the controlling administrator (sentence case).">
+            Pinned by your administrator
+          </message>
           <message name="IDS_MANAGE_EXTENSION" desc="The 'Manage extensions' text in the context menu for when right-clicking on extension icons (sentence case).">
             Manage extensions
           </message>
@@ -4438,6 +4441,9 @@
           <message name="IDS_EXTENSIONS_UNPIN_FROM_TOOLBAR" desc="The text for the menu item to unpin an extension from the toolbar (title case).">
             Unpin
           </message>
+          <message name="IDS_EXTENSIONS_PINNED_BY_ADMIN" desc="The text indicating that an extension has been 'pinned' to the toolbar by the controlling administrator (title case).">
+            Pinned by your Administrator
+          </message>
           <message name="IDS_MANAGE_EXTENSION" desc="The 'Manage Extensions' text in the context menu for when right-clicking on extension icons (title case).">
             Manage Extensions
           </message>
diff --git a/chrome/app/generated_resources_grd/IDS_EXTENSIONS_PINNED_BY_ADMIN.png.sha1 b/chrome/app/generated_resources_grd/IDS_EXTENSIONS_PINNED_BY_ADMIN.png.sha1
new file mode 100644
index 0000000..be8bb8f
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_EXTENSIONS_PINNED_BY_ADMIN.png.sha1
@@ -0,0 +1 @@
+26e11b03fa48619005b5ab7c14bd7e01bb71faad
\ No newline at end of file
diff --git a/chrome/app/printing_strings.grdp b/chrome/app/printing_strings.grdp
index 717fa595..c394512 100644
--- a/chrome/app/printing_strings.grdp
+++ b/chrome/app/printing_strings.grdp
@@ -7,6 +7,10 @@
     </message>
   </if>
 
+  <message name="IDS_UTILITY_PROCESS_PRINT_BACKEND_SERVICE_NAME" desc="The name of the utility process used for backend interactions with printer drivers.">
+    Print Backend Service
+  </message>
+
   <message name="IDS_PRINT_INVALID_PRINTER_SETTINGS" desc="Message to display when selected printer is not reachable or its settings are invalid.">
     The selected printer is not available or not installed correctly. Check your printer or try selecting another printer.
   </message>
diff --git a/chrome/app/printing_strings_grdp/IDS_UTILITY_PROCESS_PRINT_BACKEND_SERVICE_NAME.png.sha1 b/chrome/app/printing_strings_grdp/IDS_UTILITY_PROCESS_PRINT_BACKEND_SERVICE_NAME.png.sha1
new file mode 100644
index 0000000..f3ad3d4
--- /dev/null
+++ b/chrome/app/printing_strings_grdp/IDS_UTILITY_PROCESS_PRINT_BACKEND_SERVICE_NAME.png.sha1
@@ -0,0 +1 @@
+3ea9a2aba49c7709003d7298f2aa3e5edc5422ce
\ No newline at end of file
diff --git a/chrome/app/shared_settings_strings.grdp b/chrome/app/shared_settings_strings.grdp
index a37785c..810da3f3 100644
--- a/chrome/app/shared_settings_strings.grdp
+++ b/chrome/app/shared_settings_strings.grdp
@@ -276,6 +276,9 @@
   <message name="IDS_SETTINGS_BOOKMARKS_CHECKBOX_LABEL" desc="Label for the checkbox which enables or disables syncing bookmarks between multiple browser instances.">
     Bookmarks
   </message>
+  <message name="IDS_SETTINGS_READING_LIST_CHECKBOX_LABEL" desc="Label for the checkbox which enables or disables syncing reading list between multiple browser instances.">
+    Reading List
+  </message>
   <message name="IDS_SETTINGS_ENCRYPTION_OPTIONS" desc="Title for the section which includes options for encrypting sync settings.">
     Encryption options
   </message>
diff --git a/chrome/app/shared_settings_strings_grdp/IDS_SETTINGS_READING_LIST_CHECKBOX_LABEL.png.sha1 b/chrome/app/shared_settings_strings_grdp/IDS_SETTINGS_READING_LIST_CHECKBOX_LABEL.png.sha1
new file mode 100644
index 0000000..91460b9
--- /dev/null
+++ b/chrome/app/shared_settings_strings_grdp/IDS_SETTINGS_READING_LIST_CHECKBOX_LABEL.png.sha1
@@ -0,0 +1 @@
+d82a9aba092da44ee87f4da5c3e60788ca8ce0d1
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 90e8e3f..f9d33ab 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1926,8 +1926,7 @@
     "//chrome/browser/safe_browsing",
     "//chrome/browser/safe_browsing:advanced_protection",
     "//chrome/browser/safe_browsing:url_lookup_service_factory",
-    "//chrome/browser/search/recipe_tasks:mojo_bindings",
-    "//chrome/browser/search/shopping_tasks:mojo_bindings",
+    "//chrome/browser/search/task_module:mojo_bindings",
     "//chrome/browser/sharing:buildflags",
     "//chrome/browser/sharing/proto",
     "//chrome/browser/storage_access_api:permissions",
@@ -2314,6 +2313,8 @@
       "//chromeos/components/camera_app_ui:mojo_bindings",
       "//chromeos/components/chromebox_for_meetings/buildflags",
       "//chromeos/components/connectivity_diagnostics",
+      "//chromeos/components/diagnostics_ui",
+      "//chromeos/components/diagnostics_ui/mojom",
       "//chromeos/components/help_app_ui",
       "//chromeos/components/help_app_ui:mojo_bindings",
       "//chromeos/components/local_search_service",
@@ -3753,12 +3754,6 @@
       "search/promos/promo_service_factory.cc",
       "search/promos/promo_service_factory.h",
       "search/promos/promo_service_observer.h",
-      "search/recipe_tasks/recipe_tasks_handler.cc",
-      "search/recipe_tasks/recipe_tasks_handler.h",
-      "search/recipe_tasks/recipe_tasks_service.cc",
-      "search/recipe_tasks/recipe_tasks_service.h",
-      "search/recipe_tasks/recipe_tasks_service_factory.cc",
-      "search/recipe_tasks/recipe_tasks_service_factory.h",
       "search/search_engine_base_url_tracker.cc",
       "search/search_engine_base_url_tracker.h",
       "search/search_suggest/search_suggest_data.cc",
@@ -3771,12 +3766,12 @@
       "search/search_suggest/search_suggest_service_factory.cc",
       "search/search_suggest/search_suggest_service_factory.h",
       "search/search_suggest/search_suggest_service_observer.h",
-      "search/shopping_tasks/shopping_tasks_handler.cc",
-      "search/shopping_tasks/shopping_tasks_handler.h",
-      "search/shopping_tasks/shopping_tasks_service.cc",
-      "search/shopping_tasks/shopping_tasks_service.h",
-      "search/shopping_tasks/shopping_tasks_service_factory.cc",
-      "search/shopping_tasks/shopping_tasks_service_factory.h",
+      "search/task_module/task_module_handler.cc",
+      "search/task_module/task_module_handler.h",
+      "search/task_module/task_module_service.cc",
+      "search/task_module/task_module_service.h",
+      "search/task_module/task_module_service_factory.cc",
+      "search/task_module/task_module_service_factory.h",
       "send_tab_to_self/desktop_notification_handler.cc",
       "send_tab_to_self/desktop_notification_handler.h",
       "send_tab_to_self/send_tab_to_self_desktop_util.cc",
@@ -5252,6 +5247,13 @@
     if (is_linux || is_chromeos) {
       sources += [ "printing/printer_manager_dialog_linux.cc" ]
     }
+    if (is_win || is_mac || is_linux || is_chromeos) {
+      sources += [
+        "printing/print_backend_service.cc",
+        "printing/print_backend_service.h",
+      ]
+      deps += [ "//chrome/services/printing/public/mojom" ]
+    }
     if (is_win || enable_print_preview) {
       deps += [ "//chrome/services/printing/public/mojom" ]
     }
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 3306a65..944d5b901 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3761,12 +3761,6 @@
      SINGLE_VALUE_TYPE(chromeos::switches::kEnableTouchCalibrationSetting)},
 #endif  // defined(OS_CHROMEOS)
 #if defined(OS_CHROMEOS)
-    {"android-files-in-files-app",
-     flag_descriptions::kShowAndroidFilesInFilesAppName,
-     flag_descriptions::kShowAndroidFilesInFilesAppDescription, kOsCrOS,
-     ENABLE_DISABLE_VALUE_TYPE(
-         chromeos::switches::kShowAndroidFilesInFilesApp,
-         chromeos::switches::kHideAndroidFilesInFilesApp)},
     {"camera-system-web-app", flag_descriptions::kCameraSystemWebAppName,
      flag_descriptions::kCameraSystemWebAppDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(chromeos::features::kCameraSystemWebApp)},
@@ -6811,17 +6805,9 @@
   }
 
 #if defined(OS_ANDROID)
-  if (!strcmp("password-change-in-settings", entry.internal_name)) {
-    return !base::FeatureList::IsEnabled(features::kTeamfoodFlags);
-  }
-
   if (!strcmp("password-change-support", entry.internal_name)) {
     return !base::FeatureList::IsEnabled(features::kTeamfoodFlags);
   }
-
-  if (!strcmp("password-scripts-fetching", entry.internal_name)) {
-    return !base::FeatureList::IsEnabled(features::kTeamfoodFlags);
-  }
 #endif  // OS_ANDROID
 
   if (flags::IsFlagExpired(storage, entry.internal_name))
diff --git a/chrome/browser/about_flags_unittest.cc b/chrome/browser/about_flags_unittest.cc
index c760888..c8acbc28 100644
--- a/chrome/browser/about_flags_unittest.cc
+++ b/chrome/browser/about_flags_unittest.cc
@@ -151,14 +151,7 @@
   }
 };
 
-// http://crbug.com/1141271
-#if defined(OS_LINUX)
-#define MAYBE_CheckHistograms DISABLED_CheckHistograms
-#else
-#define MAYBE_CheckHistograms CheckHistograms
-#endif
-
-TEST_F(AboutFlagsHistogramTest, MAYBE_CheckHistograms) {
+TEST_F(AboutFlagsHistogramTest, CheckHistograms) {
   base::Optional<base::HistogramEnumEntryMap> login_custom_flags =
       base::ReadEnumFromEnumsXml("LoginCustomFlags");
   ASSERT_TRUE(login_custom_flags)
diff --git a/chrome/browser/accessibility/accessibility_extension_api.cc b/chrome/browser/accessibility/accessibility_extension_api.cc
index 03a6f6f..1bc4383 100644
--- a/chrome/browser/accessibility/accessibility_extension_api.cc
+++ b/chrome/browser/accessibility/accessibility_extension_api.cc
@@ -560,4 +560,24 @@
   return RespondNow(NoArguments());
 }
 
+ExtensionFunction::ResponseAction
+AccessibilityPrivateIsFeatureEnabledFunction::Run() {
+  std::unique_ptr<accessibility_private::IsFeatureEnabled::Params> params =
+      accessibility_private::IsFeatureEnabled::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params);
+  accessibility_private::AccessibilityFeature params_feature = params->feature;
+  bool enabled;
+  switch (params_feature) {
+    case accessibility_private::AccessibilityFeature::
+        ACCESSIBILITY_FEATURE_SELECTTOSPEAKNAVIGATIONCONTROL:
+      enabled = ::features::IsSelectToSpeakNavigationControlEnabled();
+      break;
+    case accessibility_private::AccessibilityFeature::
+        ACCESSIBILITY_FEATURE_NONE:
+      return RespondNow(Error("Unrecognized feature"));
+  }
+
+  return RespondNow(OneArgument(base::Value(enabled)));
+}
+
 #endif  // defined (OS_CHROMEOS)
diff --git a/chrome/browser/accessibility/accessibility_extension_api.h b/chrome/browser/accessibility/accessibility_extension_api.h
index 118d90bf..95c8730 100644
--- a/chrome/browser/accessibility/accessibility_extension_api.h
+++ b/chrome/browser/accessibility/accessibility_extension_api.h
@@ -198,6 +198,14 @@
   DECLARE_EXTENSION_FUNCTION("accessibilityPrivate.performAcceleratorAction",
                              ACCESSIBILITY_PRIVATE_PERFORMACCELERATORACTION)
 };
+
+// API function that determines if an accessibility feature is enabled.
+class AccessibilityPrivateIsFeatureEnabledFunction : public ExtensionFunction {
+  ~AccessibilityPrivateIsFeatureEnabledFunction() override {}
+  ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("accessibilityPrivate.isFeatureEnabled",
+                             ACCESSIBILITY_PRIVATE_ISFEATUREENABLED)
+};
 #endif  // defined (OS_CHROMEOS)
 
 #endif  // CHROME_BROWSER_ACCESSIBILITY_ACCESSIBILITY_EXTENSION_API_H_
diff --git a/chrome/browser/accessibility/accessibility_extension_api_browsertest.cc b/chrome/browser/accessibility/accessibility_extension_api_browsertest.cc
index 4819bd6..34bdbc1c1 100644
--- a/chrome/browser/accessibility/accessibility_extension_api_browsertest.cc
+++ b/chrome/browser/accessibility/accessibility_extension_api_browsertest.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/common/webui_url_constants.h"
 #include "content/public/test/browser_test.h"
+#include "ui/accessibility/accessibility_features.h"
 #include "ui/base/ui_base_features.h"
 
 namespace extensions {
@@ -85,4 +86,29 @@
   EXPECT_EQ(nullptr, settings_browser);
 }
 
+IN_PROC_BROWSER_TEST_F(AccessibilityPrivateApiTest,
+                       IsFeatureEnabled_FeatureDisabled) {
+  ASSERT_TRUE(RunExtensionSubtest("accessibility_private/",
+                                  "is_feature_enabled_feature_disabled.html"))
+      << message_;
+}
+
+class AccessibilityPrivateApiFeatureEnabledTest : public ExtensionApiTest {
+ public:
+  void SetUp() override {
+    scoped_feature_list_.InitAndEnableFeature(
+        ::features::kSelectToSpeakNavigationControl);
+    ExtensionApiTest::SetUp();
+  }
+
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(AccessibilityPrivateApiFeatureEnabledTest,
+                       IsFeatureEnabled_FeatureEnabled) {
+  ASSERT_TRUE(RunExtensionSubtest("accessibility_private/",
+                                  "is_feature_enabled_feature_enabled.html"))
+      << message_;
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/android/autofill_assistant/client_android.cc b/chrome/browser/android/autofill_assistant/client_android.cc
index e2b48c9b..eade900 100644
--- a/chrome/browser/android/autofill_assistant/client_android.cc
+++ b/chrome/browser/android/autofill_assistant/client_android.cc
@@ -560,7 +560,8 @@
 
   controller_ = std::make_unique<Controller>(
       web_contents_, /* client= */ this, base::DefaultTickClock::GetInstance(),
-      RuntimeManagerImpl::GetForWebContents(web_contents_), std::move(service));
+      RuntimeManagerImpl::GetForWebContents(web_contents_)->GetWeakPtr(),
+      std::move(service));
   controller_->SetStatusMessage(status_message);
 }
 
diff --git a/chrome/browser/android/autofill_assistant/client_android.h b/chrome/browser/android/autofill_assistant/client_android.h
index a44d892..a337e97 100644
--- a/chrome/browser/android/autofill_assistant/client_android.h
+++ b/chrome/browser/android/autofill_assistant/client_android.h
@@ -123,6 +123,7 @@
   friend class content::WebContentsUserData<ClientAndroid>;
 
   explicit ClientAndroid(content::WebContents* web_contents);
+
   void CreateController(std::unique_ptr<Service> service);
   void DestroyController();
   void AttachUI(
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm
index 046544d..b1d66e3f 100644
--- a/chrome/browser/app_controller_mac.mm
+++ b/chrome/browser/app_controller_mac.mm
@@ -881,7 +881,7 @@
         // downloads page if the user chooses to wait.
         Browser* browser = chrome::FindBrowserWithProfile(profiles[i]);
         if (!browser) {
-          browser = new Browser(Browser::CreateParams(profiles[i], true));
+          browser = Browser::Create(Browser::CreateParams(profiles[i], true));
           browser->window()->Show();
         }
         DCHECK(browser);
@@ -1398,7 +1398,7 @@
   Browser* browser = chrome::FindLastActiveWithProfile(profile);
   // if no browser window exists then create one with no tabs to be filled in
   if (!browser) {
-    browser = new Browser(
+    browser = Browser::Create(
         Browser::CreateParams([self safeLastProfileForNewWindows], true));
     browser->window()->Show();
   }
diff --git a/chrome/browser/apps/app_service/extension_apps_base.cc b/chrome/browser/apps/app_service/extension_apps_base.cc
index fd27288e..db36325 100644
--- a/chrome/browser/apps/app_service/extension_apps_base.cc
+++ b/chrome/browser/apps/app_service/extension_apps_base.cc
@@ -715,7 +715,7 @@
                  *extension)) {
     Browser* browser = chrome::FindTabbedBrowser(profile_, false);
     if (!browser) {
-      browser = new Browser(Browser::CreateParams(profile_, true));
+      browser = Browser::Create(Browser::CreateParams(profile_, true));
     }
 
     chrome::ShowExtensions(browser, extension->id());
diff --git a/chrome/browser/apps/app_service/launch_utils.cc b/chrome/browser/apps/app_service/launch_utils.cc
index faee62c..44ab798 100644
--- a/chrome/browser/apps/app_service/launch_utils.cc
+++ b/chrome/browser/apps/app_service/launch_utils.cc
@@ -112,7 +112,7 @@
 
 Browser* CreateBrowserWithNewTabPage(Profile* profile) {
   Browser::CreateParams create_params(profile, /*user_gesture=*/false);
-  Browser* browser = new Browser(create_params);
+  Browser* browser = Browser::Create(create_params);
 
   NavigateParams params(browser, GURL(chrome::kChromeUINewTabURL),
                         ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
diff --git a/chrome/browser/apps/app_shim/app_shim_manager_mac.cc b/chrome/browser/apps/app_shim/app_shim_manager_mac.cc
index dbc3508d..dfc6db1 100644
--- a/chrome/browser/apps/app_shim/app_shim_manager_mac.cc
+++ b/chrome/browser/apps/app_shim/app_shim_manager_mac.cc
@@ -753,8 +753,8 @@
     profile = profile_manager_->GetLastUsedProfile();
   if (!profile)
     return;
-  Browser* browser =
-      new Browser(Browser::CreateParams(Browser::TYPE_NORMAL, profile, true));
+  Browser* browser = Browser::Create(
+      Browser::CreateParams(Browser::TYPE_NORMAL, profile, true));
   browser->window()->Show();
   NavigateParams params(browser, url, ui::PAGE_TRANSITION_AUTO_BOOKMARK);
   params.tabstrip_add_types = TabStripModel::ADD_ACTIVE;
diff --git a/chrome/browser/captive_portal/captive_portal_browsertest.cc b/chrome/browser/captive_portal/captive_portal_browsertest.cc
index d76e03c..47c173df 100644
--- a/chrome/browser/captive_portal/captive_portal_browsertest.cc
+++ b/chrome/browser/captive_portal/captive_portal_browsertest.cc
@@ -2661,7 +2661,7 @@
 // Disabled:  http://crbug.com/134357
 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, DISABLED_TwoWindows) {
   Browser* browser2 =
-      new Browser(Browser::CreateParams(browser()->profile(), true));
+      Browser::Create(Browser::CreateParams(browser()->profile(), true));
   // Navigate the new browser window so it'll be shown and we can pick the
   // active window.
   ui_test_utils::NavigateToURL(browser2, GURL(url::kAboutBlankURL));
diff --git a/chrome/browser/chrome_browser_interface_binders.cc b/chrome/browser/chrome_browser_interface_binders.cc
index 7014682c..0f269dc6 100644
--- a/chrome/browser/chrome_browser_interface_binders.cc
+++ b/chrome/browser/chrome_browser_interface_binders.cc
@@ -111,8 +111,7 @@
 #include "chrome/browser/payments/payment_request_factory.h"
 #include "chrome/browser/promo_browser_command/promo_browser_command.mojom.h"
 #include "chrome/browser/search/ntp_features.h"
-#include "chrome/browser/search/recipe_tasks/recipe_tasks.mojom.h"
-#include "chrome/browser/search/shopping_tasks/shopping_tasks.mojom.h"
+#include "chrome/browser/search/task_module/task_module.mojom.h"
 #include "chrome/browser/speech/speech_recognition_client_browser_interface.h"
 #include "chrome/browser/speech/speech_recognition_client_browser_interface_factory.h"
 #include "chrome/browser/speech/speech_recognition_service.h"
@@ -175,6 +174,8 @@
 #include "chrome/browser/ui/webui/settings/chromeos/search/user_action_recorder.mojom.h"
 #include "chromeos/components/camera_app_ui/camera_app_helper.mojom.h"
 #include "chromeos/components/camera_app_ui/camera_app_ui.h"
+#include "chromeos/components/diagnostics_ui/diagnostics_ui.h"
+#include "chromeos/components/diagnostics_ui/mojom/system_data_provider.mojom.h"
 #include "chromeos/components/help_app_ui/help_app_ui.h"
 #include "chromeos/components/help_app_ui/help_app_ui.mojom.h"
 #include "chromeos/components/local_search_service/mojom/local_search_service_proxy.mojom.h"
@@ -648,14 +649,10 @@
   RegisterWebUIControllerInterfaceBinder<media_feeds::mojom::MediaFeedsStore,
                                          MediaFeedsUI>(map);
 
-  if (base::FeatureList::IsEnabled(ntp_features::kNtpRecipeTasksModule)) {
+  if (base::FeatureList::IsEnabled(ntp_features::kNtpRecipeTasksModule) ||
+      base::FeatureList::IsEnabled(ntp_features::kNtpShoppingTasksModule)) {
     RegisterWebUIControllerInterfaceBinder<
-        recipe_tasks::mojom::RecipeTasksHandler, NewTabPageUI>(map);
-  }
-
-  if (base::FeatureList::IsEnabled(ntp_features::kNtpShoppingTasksModule)) {
-    RegisterWebUIControllerInterfaceBinder<
-        shopping_tasks::mojom::ShoppingTasksHandler, NewTabPageUI>(map);
+        task_module::mojom::TaskModuleHandler, NewTabPageUI>(map);
   }
 
   if (base::FeatureList::IsEnabled(reading_list::switches::kReadLater)) {
@@ -747,6 +744,10 @@
       chromeos::network_diagnostics::mojom::NetworkDiagnosticsRoutines,
       chromeos::NetworkUI>(map);
 
+  RegisterWebUIControllerInterfaceBinder<
+      chromeos::diagnostics::mojom::SystemDataProvider,
+      chromeos::DiagnosticsUI>(map);
+
   RegisterWebUIControllerInterfaceBinder<chromeos::scanning::mojom::ScanService,
                                          chromeos::ScanningUI>(map);
 #endif  // defined(OS_CHROMEOS)
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index a48eb9e..92c19ce 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -2503,6 +2503,8 @@
     "printing/print_management/printing_manager_factory.h",
     "printing/print_server.cc",
     "printing/print_server.h",
+    "printing/print_servers_policy_provider.cc",
+    "printing/print_servers_policy_provider.h",
     "printing/print_servers_provider.cc",
     "printing/print_servers_provider.h",
     "printing/print_servers_provider_factory.cc",
@@ -2526,8 +2528,6 @@
     "printing/server_printers_fetcher.h",
     "printing/server_printers_provider.cc",
     "printing/server_printers_provider.h",
-    "printing/server_printers_provider_factory.cc",
-    "printing/server_printers_provider_factory.h",
     "printing/specifics_translation.cc",
     "printing/specifics_translation.h",
     "printing/synced_printers_manager.cc",
diff --git a/chrome/browser/chromeos/file_manager/volume_manager.cc b/chrome/browser/chromeos/file_manager/volume_manager.cc
index 77b357b..afb4f7c 100644
--- a/chrome/browser/chromeos/file_manager/volume_manager.cc
+++ b/chrome/browser/chromeos/file_manager/volume_manager.cc
@@ -88,13 +88,6 @@
                                           path);
 }
 
-// Returns true if the "Play files" root should be shown based on the current
-// flag settings (chrome://flags/#android-files-in-files-app).
-bool IsShowAndroidFilesEnabled() {
-  return !base::CommandLine::ForCurrentProcess()->HasSwitch(
-      chromeos::switches::kHideAndroidFilesInFilesApp);
-}
-
 // Registers a mount point for Android files to ExternalMountPoints.
 bool RegisterAndroidFilesMountPoint() {
   storage::ExternalMountPoints* const mount_points =
@@ -596,8 +589,7 @@
   if (base::FeatureList::IsEnabled(arc::kMediaViewFeature) &&
       arc::IsArcAllowedForProfile(profile_)) {
     // Registers a mount point for Android files only when the flag is enabled.
-    if (IsShowAndroidFilesEnabled())
-      RegisterAndroidFilesMountPoint();
+    RegisterAndroidFilesMountPoint();
 
     arc::ArcSessionManager::Get()->AddObserver(this);
     OnArcPlayStoreEnabledChanged(
@@ -1151,11 +1143,9 @@
                  Volume::CreateForMediaView(arc::kVideosRootDocumentId));
     DoMountEvent(chromeos::MOUNT_ERROR_NONE,
                  Volume::CreateForMediaView(arc::kAudioRootDocumentId));
-    if (IsShowAndroidFilesEnabled()) {
-      DoMountEvent(chromeos::MOUNT_ERROR_NONE,
-                   Volume::CreateForAndroidFiles(
-                       base::FilePath(util::kAndroidFilesPath)));
-    }
+    DoMountEvent(
+        chromeos::MOUNT_ERROR_NONE,
+        Volume::CreateForAndroidFiles(base::FilePath(util::kAndroidFilesPath)));
   } else {
     DoUnmountEvent(chromeos::MOUNT_ERROR_NONE,
                    *Volume::CreateForMediaView(arc::kImagesRootDocumentId));
@@ -1163,11 +1153,9 @@
                    *Volume::CreateForMediaView(arc::kVideosRootDocumentId));
     DoUnmountEvent(chromeos::MOUNT_ERROR_NONE,
                    *Volume::CreateForMediaView(arc::kAudioRootDocumentId));
-    if (IsShowAndroidFilesEnabled()) {
-      DoUnmountEvent(chromeos::MOUNT_ERROR_NONE,
-                     *Volume::CreateForAndroidFiles(
-                         base::FilePath(util::kAndroidFilesPath)));
-    }
+    DoUnmountEvent(chromeos::MOUNT_ERROR_NONE,
+                   *Volume::CreateForAndroidFiles(
+                       base::FilePath(util::kAndroidFilesPath)));
   }
 
   documents_provider_root_manager_->SetEnabled(enabled);
diff --git a/chrome/browser/chromeos/phonehub/browser_tabs_metadata_fetcher_impl_unittest.cc b/chrome/browser/chromeos/phonehub/browser_tabs_metadata_fetcher_impl_unittest.cc
index 27f346b1..a108707 100644
--- a/chrome/browser/chromeos/phonehub/browser_tabs_metadata_fetcher_impl_unittest.cc
+++ b/chrome/browser/chromeos/phonehub/browser_tabs_metadata_fetcher_impl_unittest.cc
@@ -208,19 +208,15 @@
 
   ExpectFaviconUrlFetchAttempt(kUrlD);
   ExpectFaviconUrlFetchAttempt(kUrlC);
-  ExpectFaviconUrlFetchAttempt(kUrlB);
-  ExpectFaviconUrlFetchAttempt(kUrlA);
 
   AttemptFetch();
   EXPECT_FALSE(actual_browser_tabs_metadata());
 
-  // 5 callbacks called accounting for the additional missed one for tab A.
-  InvokeNextFaviconCallbacks(/*num_successful_fetches=*/5);
+  // 3 callbacks called accounting for the additional missed one for tab A.
+  InvokeNextFaviconCallbacks(/*num_successful_fetches=*/3);
   CheckIsExpectedMetadata(std::vector<BrowserTabMetadata>({
       BrowserTabMetadata(kUrlD, kTitleD, kTimeD, GetDummyImage()),
       BrowserTabMetadata(kUrlC, kTitleC, kTimeC, GetDummyImage()),
-      BrowserTabMetadata(kUrlB, kTitleB, kTimeB, GetDummyImage()),
-      BrowserTabMetadata(kUrlA, kTitleA, kTimeA, GetDummyImage()),
   }));
 }
 
@@ -282,21 +278,17 @@
   AddTab(synced_session_window.get(), kTitleC, kUrlC, kTimeC);
   AddWindow(std::move(synced_session_window));
 
-  ExpectFaviconUrlFetchAttempt(kUrlB);
-  ExpectFaviconUrlFetchAttempt(kUrlC);
   ExpectFaviconUrlFetchAttempt(kUrlD);
   ExpectFaviconUrlFetchAttempt(kUrlE);
 
   AttemptFetch();
-  InvokeNextFaviconCallbacks(/*num_successful_fetches=*/4);
+  InvokeNextFaviconCallbacks(/*num_successful_fetches=*/2);
 
   // Tab A is not present because it has the oldest timestamp, and the maximum
   // number of BrowserTabMetadata has been met.
   CheckIsExpectedMetadata(std::vector<BrowserTabMetadata>({
       BrowserTabMetadata(kUrlE, kTitleE, kTimeE, GetDummyImage()),
       BrowserTabMetadata(kUrlD, kTitleD, kTimeD, GetDummyImage()),
-      BrowserTabMetadata(kUrlC, kTitleC, kTimeC, GetDummyImage()),
-      BrowserTabMetadata(kUrlB, kTitleB, kTimeB, GetDummyImage()),
   }));
 }
 
@@ -325,18 +317,14 @@
   AddTab(synced_session_window_two.get(), kTitleC, kUrlC, kTimeC);
   AddWindow(std::move(synced_session_window_two));
 
-  ExpectFaviconUrlFetchAttempt(kUrlB);
-  ExpectFaviconUrlFetchAttempt(kUrlC);
   ExpectFaviconUrlFetchAttempt(kUrlD);
   ExpectFaviconUrlFetchAttempt(kUrlE);
 
   AttemptFetch();
-  InvokeNextFaviconCallbacks(/*num_successful_fetches=*/4);
+  InvokeNextFaviconCallbacks(/*num_successful_fetches=*/2);
   CheckIsExpectedMetadata(std::vector<BrowserTabMetadata>({
       BrowserTabMetadata(kUrlE, kTitleE, kTimeE, GetDummyImage()),
       BrowserTabMetadata(kUrlD, kTitleD, kTimeD, GetDummyImage()),
-      BrowserTabMetadata(kUrlC, kTitleC, kTimeC, GetDummyImage()),
-      BrowserTabMetadata(kUrlB, kTitleB, kTimeB, GetDummyImage()),
   }));
 }
 
diff --git a/chrome/browser/chromeos/policy/dlp/data_transfer_dlp_controller.cc b/chrome/browser/chromeos/policy/dlp/data_transfer_dlp_controller.cc
index 5c154d8..d6582f3 100644
--- a/chrome/browser/chromeos/policy/dlp/data_transfer_dlp_controller.cc
+++ b/chrome/browser/chromeos/policy/dlp/data_transfer_dlp_controller.cc
@@ -19,7 +19,7 @@
 #include "chrome/grit/generated_resources.h"
 #include "components/strings/grit/components_strings.h"
 #include "ui/base/clipboard/clipboard.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "url/gurl.h"
 
diff --git a/chrome/browser/chromeos/policy/dlp/data_transfer_dlp_controller.h b/chrome/browser/chromeos/policy/dlp/data_transfer_dlp_controller.h
index 75ce454b..4acd17e7 100644
--- a/chrome/browser/chromeos/policy/dlp/data_transfer_dlp_controller.h
+++ b/chrome/browser/chromeos/policy/dlp/data_transfer_dlp_controller.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_CHROMEOS_POLICY_DLP_DATA_TRANSFER_DLP_CONTROLLER_H_
 
 #include "base/strings/string16.h"
-#include "ui/base/clipboard/data_transfer_policy_controller.h"
+#include "ui/base/data_transfer_policy/data_transfer_policy_controller.h"
 
 namespace ui {
 class DataTransferEndpoint;
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_content_manager_browsertest.cc b/chrome/browser/chromeos/policy/dlp/dlp_content_manager_browsertest.cc
index 1d2c958..4c18c2a34 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_content_manager_browsertest.cc
+++ b/chrome/browser/chromeos/policy/dlp/dlp_content_manager_browsertest.cc
@@ -97,7 +97,7 @@
 
   // Open second browser window.
   Browser* browser2 =
-      new Browser(Browser::CreateParams(browser()->profile(), true));
+      Browser::Create(Browser::CreateParams(browser()->profile(), true));
   chrome::NewTab(browser2);
   ui_test_utils::NavigateToURL(browser2, GURL("https://google.com"));
 
@@ -140,7 +140,7 @@
 
   // Open second browser window.
   Browser* browser2 =
-      new Browser(Browser::CreateParams(browser()->profile(), true));
+      Browser::Create(Browser::CreateParams(browser()->profile(), true));
   chrome::NewTab(browser2);
   ui_test_utils::NavigateToURL(browser2, GURL("https://google.com"));
 
@@ -183,7 +183,7 @@
 
   // Open second browser window.
   Browser* browser2 =
-      new Browser(Browser::CreateParams(browser()->profile(), true));
+      Browser::Create(Browser::CreateParams(browser()->profile(), true));
   chrome::NewTab(browser2);
   ui_test_utils::NavigateToURL(browser2, GURL("https://google.com"));
 
diff --git a/chrome/browser/chromeos/printing/cups_printers_manager.cc b/chrome/browser/chromeos/printing/cups_printers_manager.cc
index 92dd089..85c6428 100644
--- a/chrome/browser/chromeos/printing/cups_printers_manager.cc
+++ b/chrome/browser/chromeos/printing/cups_printers_manager.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/chromeos/printing/enterprise_printers_provider.h"
 #include "chrome/browser/chromeos/printing/ppd_provider_factory.h"
 #include "chrome/browser/chromeos/printing/ppd_resolution_tracker.h"
+#include "chrome/browser/chromeos/printing/print_servers_policy_provider.h"
 #include "chrome/browser/chromeos/printing/print_servers_provider.h"
 #include "chrome/browser/chromeos/printing/printer_configurer.h"
 #include "chrome/browser/chromeos/printing/printer_event_tracker.h"
@@ -27,7 +28,6 @@
 #include "chrome/browser/chromeos/printing/printer_info.h"
 #include "chrome/browser/chromeos/printing/printers_map.h"
 #include "chrome/browser/chromeos/printing/server_printers_provider.h"
-#include "chrome/browser/chromeos/printing/server_printers_provider_factory.h"
 #include "chrome/browser/chromeos/printing/synced_printers_manager.h"
 #include "chrome/browser/chromeos/printing/synced_printers_manager_factory.h"
 #include "chrome/browser/chromeos/printing/usb_printer_detector.h"
@@ -77,7 +77,8 @@
       std::unique_ptr<PrinterConfigurer> printer_configurer,
       std::unique_ptr<UsbPrinterNotificationController>
           usb_notification_controller,
-      ServerPrintersProvider* server_printers_provider,
+      std::unique_ptr<PrintServersPolicyProvider> print_servers_provider,
+      std::unique_ptr<ServerPrintersProvider> server_printers_provider,
       std::unique_ptr<EnterprisePrintersProvider> enterprise_printers_provider,
       PrinterEventTracker* event_tracker,
       PrefService* pref_service)
@@ -90,7 +91,8 @@
         auto_usb_printer_configurer_(std::move(printer_configurer),
                                      this,
                                      usb_notification_controller_.get()),
-        server_printers_provider_(server_printers_provider),
+        print_servers_provider_(std::move(print_servers_provider)),
+        server_printers_provider_(std::move(server_printers_provider)),
         enterprise_printers_provider_(std::move(enterprise_printers_provider)),
         enterprise_printers_provider_observer_(this),
         event_tracker_(event_tracker) {
@@ -125,6 +127,9 @@
                             weak_ptr_factory_.GetWeakPtr(), kZeroconfDetector));
     OnPrintersFound(kZeroconfDetector, zeroconf_detector_->GetPrinters());
 
+    print_servers_provider_->SetListener(
+        base::BindRepeating(&CupsPrintersManagerImpl::OnPrintServersUpdated,
+                            weak_ptr_factory_.GetWeakPtr()));
     server_printers_provider_->RegisterPrintersFoundCallback(
         base::BindRepeating(&CupsPrintersManagerImpl::OnPrintersUpdated,
                             weak_ptr_factory_.GetWeakPtr()));
@@ -463,6 +468,68 @@
     }
   }
 
+  void OnPrintServersUpdated(bool is_complete,
+                             std::map<GURL, PrintServer> print_servers,
+                             ServerPrintersFetchingMode fetching_mode) {
+    fetching_mode_ = fetching_mode;
+    if (!is_complete) {
+      return;
+    }
+
+    print_servers_ = std::map<std::string, PrintServer>();
+    for (const auto& server_pair : print_servers) {
+      const PrintServer& server = server_pair.second;
+      print_servers_.value().emplace(server.GetId(), server);
+    }
+
+    if (fetching_mode_ == ServerPrintersFetchingMode::kSingleServerOnly) {
+      // If the previously selected print server is unavailable, set to the
+      // first print server in the list, or set to none if there are no print
+      // servers.
+      auto& servers = print_servers_.value();
+      if (!selected_print_server_id_.has_value() ||
+          !ChoosePrintServer(selected_print_server_id_)) {
+        auto first_id =
+            servers.empty()
+                ? base::nullopt
+                : base::make_optional(servers.begin()->second.GetId());
+        ChoosePrintServer(first_id);
+      }
+    } else {
+      selected_print_server_id_ = base::nullopt;
+      server_printers_provider_->OnServersChanged(true, print_servers);
+    }
+  }
+
+  // Public API function.
+  bool ChoosePrintServer(
+      const base::Optional<std::string>& selected_print_server_id) override {
+    if (fetching_mode_ != ServerPrintersFetchingMode::kSingleServerOnly ||
+        !print_servers_.has_value()) {
+      return false;
+    }
+
+    std::map<GURL, PrintServer> selected_print_servers;
+    if (selected_print_server_id.has_value()) {
+      auto iter = print_servers_.value().find(selected_print_server_id.value());
+      if (iter != print_servers_.value().end()) {
+        const PrintServer& server = iter->second;
+        selected_print_servers.emplace(server.GetUrl(), server);
+      } else {
+        // A selected value was given that is not available
+        return false;
+      }
+    }
+    selected_print_server_id_ = selected_print_server_id;
+    server_printers_provider_->OnServersChanged(true, selected_print_servers);
+    return true;
+  }
+
+  // Public API function.
+  ServerPrintersFetchingMode GetServerPrintersFetchingMode() const override {
+    return fetching_mode_;
+  }
+
  private:
   base::Optional<Printer> GetEnterprisePrinter(const std::string& id) const {
     return printers_.Get(PrinterClass::kEnterprise, id);
@@ -729,8 +796,16 @@
 
   AutomaticUsbPrinterConfigurer auto_usb_printer_configurer_;
 
-  // Not owned.
-  ServerPrintersProvider* server_printers_provider_;
+  std::unique_ptr<PrintServersPolicyProvider> print_servers_provider_;
+
+  // The print server ID that is the current selection, if any.
+  base::Optional<std::string> selected_print_server_id_;
+
+  ServerPrintersFetchingMode fetching_mode_;
+
+  base::Optional<std::map<std::string, PrintServer>> print_servers_;
+
+  std::unique_ptr<ServerPrintersProvider> server_printers_provider_;
 
   std::unique_ptr<EnterprisePrintersProvider> enterprise_printers_provider_;
   ScopedObserver<EnterprisePrintersProvider,
@@ -781,8 +856,8 @@
       UsbPrinterDetector::Create(), ZeroconfPrinterDetector::Create(),
       CreatePpdProvider(profile), PrinterConfigurer::Create(profile),
       UsbPrinterNotificationController::Create(profile),
-      ServerPrintersProviderFactory::GetInstance()->GetForBrowserContext(
-          profile),
+      PrintServersPolicyProvider::Create(profile),
+      ServerPrintersProvider::Create(),
       EnterprisePrintersProvider::Create(CrosSettings::Get(), profile),
       PrinterEventTrackerFactory::GetInstance()->GetForBrowserContext(profile),
       profile->GetPrefs());
@@ -797,7 +872,8 @@
     std::unique_ptr<PrinterConfigurer> printer_configurer,
     std::unique_ptr<UsbPrinterNotificationController>
         usb_notification_controller,
-    ServerPrintersProvider* server_printers_provider,
+    std::unique_ptr<ServerPrintersProvider> server_printers_provider,
+    std::unique_ptr<PrintServersPolicyProvider> print_servers_provider,
     std::unique_ptr<EnterprisePrintersProvider> enterprise_printers_provider,
     PrinterEventTracker* event_tracker,
     PrefService* pref_service) {
@@ -805,8 +881,8 @@
       synced_printers_manager, std::move(usb_detector),
       std::move(zeroconf_detector), std::move(ppd_provider),
       std::move(printer_configurer), std::move(usb_notification_controller),
-      server_printers_provider, std::move(enterprise_printers_provider),
-      event_tracker, pref_service);
+      std::move(print_servers_provider), std::move(server_printers_provider),
+      std::move(enterprise_printers_provider), event_tracker, pref_service);
 }
 
 // static
diff --git a/chrome/browser/chromeos/printing/cups_printers_manager.h b/chrome/browser/chromeos/printing/cups_printers_manager.h
index 91793fc..9831525 100644
--- a/chrome/browser/chromeos/printing/cups_printers_manager.h
+++ b/chrome/browser/chromeos/printing/cups_printers_manager.h
@@ -10,6 +10,7 @@
 
 #include "base/callback_forward.h"
 #include "base/memory/ref_counted.h"
+#include "chrome/browser/chromeos/printing/print_servers_policy_provider.h"
 #include "chrome/browser/chromeos/printing/printer_installation_manager.h"
 #include "chromeos/printing/printer_configuration.h"
 #include "chromeos/printing/uri.h"
@@ -72,7 +73,8 @@
       std::unique_ptr<PrinterConfigurer> printer_configurer,
       std::unique_ptr<UsbPrinterNotificationController>
           usb_notification_controller,
-      ServerPrintersProvider* server_printers_provider,
+      std::unique_ptr<ServerPrintersProvider> server_printers_provider,
+      std::unique_ptr<PrintServersPolicyProvider> print_servers_provider,
       std::unique_ptr<EnterprisePrintersProvider> enterprise_printers_provider,
       PrinterEventTracker* event_tracker,
       PrefService* pref_service);
@@ -129,6 +131,14 @@
   // Records the total number of detected network printers and the
   // number of detected network printers that have not been saved.
   virtual void RecordNearbyNetworkPrinterCounts() const = 0;
+
+  // Selects a print server from all the available print servers. Returns true on
+  // successfully selecting the requested print server.
+  virtual bool ChoosePrintServer(
+      const base::Optional<std::string>& selected_print_server_id) = 0;
+
+  // Returns the current fetching mode strategy for print servers.
+  virtual ServerPrintersFetchingMode GetServerPrintersFetchingMode() const = 0;
 };
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/printing/cups_printers_manager_factory.cc b/chrome/browser/chromeos/printing/cups_printers_manager_factory.cc
index e93b8f0..fab4caa 100644
--- a/chrome/browser/chromeos/printing/cups_printers_manager_factory.cc
+++ b/chrome/browser/chromeos/printing/cups_printers_manager_factory.cc
@@ -7,7 +7,6 @@
 #include "base/memory/singleton.h"
 #include "chrome/browser/chromeos/printing/cups_printers_manager.h"
 #include "chrome/browser/chromeos/printing/cups_printers_manager_proxy.h"
-#include "chrome/browser/chromeos/printing/server_printers_provider_factory.h"
 #include "chrome/browser/chromeos/printing/synced_printers_manager_factory.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/incognito_helpers.h"
@@ -33,7 +32,6 @@
           "CupsPrintersManagerFactory",
           BrowserContextDependencyManager::GetInstance()),
       proxy_(CupsPrintersManagerProxy::Create()) {
-  DependsOn(chromeos::ServerPrintersProviderFactory::GetInstance());
   DependsOn(chromeos::SyncedPrintersManagerFactory::GetInstance());
 }
 
diff --git a/chrome/browser/chromeos/printing/cups_printers_manager_unittest.cc b/chrome/browser/chromeos/printing/cups_printers_manager_unittest.cc
index c760309..c498279 100644
--- a/chrome/browser/chromeos/printing/cups_printers_manager_unittest.cc
+++ b/chrome/browser/chromeos/printing/cups_printers_manager_unittest.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/chromeos/printing/cups_printers_manager.h"
 
 #include <algorithm>
+#include <map>
 #include <memory>
 #include <string>
 #include <unordered_set>
@@ -28,8 +29,11 @@
 #include "chrome/browser/chromeos/printing/usb_printer_detector.h"
 #include "chrome/browser/chromeos/printing/usb_printer_notification_controller.h"
 #include "chrome/common/pref_names.h"
+#include "chrome/test/base/testing_browser_process.h"
 #include "components/prefs/pref_service.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
+#include "content/public/test/browser_task_environment.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace chromeos {
@@ -333,10 +337,55 @@
 
   void RegisterPrintersFoundCallback(OnPrintersUpdateCallback cb) override {}
 
+  void OnServersChanged(bool servers_are_complete,
+                        const std::map<GURL, PrintServer>& servers) override {
+    std::vector<chromeos::PrintServer> print_servers;
+    for (auto& server_pair : servers) {
+      print_servers.push_back(server_pair.second);
+    }
+    print_servers_ = print_servers;
+  }
+
   std::vector<PrinterDetector::DetectedPrinter> GetPrinters() override {
     std::vector<PrinterDetector::DetectedPrinter> printers;
     return printers;
   }
+
+  std::vector<chromeos::PrintServer> GetPrintServers() {
+    return print_servers_;
+  }
+
+ private:
+  std::vector<chromeos::PrintServer> print_servers_;
+};
+
+class FakePrintServersProvider : public PrintServersProvider {
+ public:
+  FakePrintServersProvider() = default;
+  ~FakePrintServersProvider() override = default;
+
+  void AddObserver(Observer* observer) override { observer_ = observer; }
+  void RemoveObserver(Observer* observer) override {}
+  void SetData(std::unique_ptr<std::string> data) override {}
+  void SetAllowlistPref(PrefService* prefs,
+                        const std::string& allowlist_pref) override {}
+  void ClearData() override {}
+
+  base::Optional<std::vector<PrintServer>> GetPrintServers() override {
+    return print_servers_;
+  }
+
+  void SetPrintServers(base::Optional<std::vector<PrintServer>> print_servers) {
+    print_servers_ = print_servers;
+    if (observer_) {
+      observer_->OnServersChanged(print_servers.has_value(),
+                                  print_servers.value());
+    }
+  }
+
+ private:
+  base::Optional<std::vector<PrintServer>> print_servers_;
+  PrintServersProvider::Observer* observer_;
 };
 
 class CupsPrintersManagerTest : public testing::Test,
@@ -349,6 +398,9 @@
     zeroconf_detector_ = zeroconf_detector.get();
     auto usb_detector = std::make_unique<FakePrinterDetector>();
     usb_detector_ = usb_detector.get();
+    auto server_printers_provider =
+        std::make_unique<FakeServerPrintersProvider>();
+    server_printers_provider_ = server_printers_provider.get();
     auto printer_configurer = std::make_unique<TestPrinterConfigurer>();
     printer_configurer_ = printer_configurer.get();
     auto usb_notif_controller =
@@ -357,6 +409,10 @@
     auto enterprise_printers_provider =
         std::make_unique<FakeEnterprisePrintersProvider>();
     enterprise_printers_provider_ = enterprise_printers_provider.get();
+    auto print_servers_policy_provider =
+        PrintServersPolicyProvider::CreateForTesting(
+            user_policy_print_servers_provider_.AsWeakPtr(),
+            device_policy_print_servers_provider_.AsWeakPtr());
 
     // Register the pref |UserPrintersAllowed|
     CupsPrintersManager::RegisterProfilePrefs(pref_service_.registry());
@@ -365,8 +421,10 @@
         &synced_printers_manager_, std::move(usb_detector),
         std::move(zeroconf_detector), ppd_provider_,
         std::move(printer_configurer), std::move(usb_notif_controller),
-        &server_printers_provider_, std::move(enterprise_printers_provider),
-        &event_tracker_, &pref_service_);
+        std::move(server_printers_provider),
+        std::move(print_servers_policy_provider),
+        std::move(enterprise_printers_provider), &event_tracker_,
+        &pref_service_);
     manager_->AddObserver(this);
   }
 
@@ -393,8 +451,17 @@
     pref_service_.SetManagedPref(name, std::move(value_ptr));
   }
 
+  static chromeos::PrintServer CreatePrintServer(std::string id,
+                                                 std::string server_url,
+                                                 std::string name) {
+    GURL url(server_url);
+    chromeos::PrintServer print_server(id, url, name);
+    return print_server;
+  }
+
  protected:
-  base::test::TaskEnvironment task_environment_;
+  // Everything from PrintServersProvider must be called on Chrome_UIThread
+  content::BrowserTaskEnvironment task_environment_;
 
   // Captured printer lists from observer callbacks.
   base::flat_map<PrinterClass, std::vector<Printer>> observed_printers_;
@@ -402,11 +469,13 @@
   // Backend fakes driving the CupsPrintersManager.
   FakeSyncedPrintersManager synced_printers_manager_;
   FakeEnterprisePrintersProvider* enterprise_printers_provider_;  // Not owned.
-  FakePrinterDetector* usb_detector_;          // Not owned.
-  FakePrinterDetector* zeroconf_detector_;     // Not owned.
-  TestPrinterConfigurer* printer_configurer_;  // Not owned.
-  FakeUsbPrinterNotificationController* usb_notif_controller_;  // Not owned.
-  FakeServerPrintersProvider server_printers_provider_;
+  FakePrinterDetector* usb_detector_;                             // Not owned.
+  FakePrinterDetector* zeroconf_detector_;                        // Not owned.
+  TestPrinterConfigurer* printer_configurer_;                     // Not owned.
+  FakeUsbPrinterNotificationController* usb_notif_controller_;    // Not owned.
+  FakeServerPrintersProvider* server_printers_provider_;
+  FakePrintServersProvider user_policy_print_servers_provider_;
+  FakePrintServersProvider device_policy_print_servers_provider_;
   scoped_refptr<FakePpdProvider> ppd_provider_;
 
   // This is unused, it's just here for memory ownership.
@@ -932,5 +1001,54 @@
                                      2, 1);
 }
 
+TEST_F(CupsPrintersManagerTest, GetServerPrinters_StandardMode) {
+  EXPECT_TRUE(server_printers_provider_->GetPrinters().empty());
+
+  std::vector<chromeos::PrintServer> user_print_servers;
+  auto user_print_server =
+      CreatePrintServer("1", "http://192.168.1.5/user-printer", "LexaPrint");
+  user_print_servers.push_back(user_print_server);
+  user_policy_print_servers_provider_.SetPrintServers(user_print_servers);
+  std::vector<chromeos::PrintServer> device_print_servers;
+  auto device_print_server = CreatePrintServer(
+      "2", "http://192.168.1.5/device-printer", "Color Laser");
+  device_print_servers.push_back(device_print_server);
+  device_policy_print_servers_provider_.SetPrintServers(device_print_servers);
+
+  EXPECT_THAT(
+      server_printers_provider_->GetPrintServers(),
+      testing::UnorderedElementsAre(user_print_server, device_print_server));
+}
+
+TEST_F(CupsPrintersManagerTest, GetServerPrinters_SingleServerOnly) {
+  EXPECT_TRUE(server_printers_provider_->GetPrinters().empty());
+
+  auto selected_print_server =
+      CreatePrintServer("user-1", "http://user-print-1", "User LexaPrint - 1");
+
+  std::vector<chromeos::PrintServer> user_print_servers;
+  for (int i = 1; i <= 10; ++i) {
+    auto id = std::to_string(i);
+    auto print_server = CreatePrintServer(
+        "user-" + id, "http://user-print-" + id, "User LexaPrint - " + id);
+    user_print_servers.push_back(print_server);
+  }
+  user_policy_print_servers_provider_.SetPrintServers(user_print_servers);
+  std::vector<chromeos::PrintServer> device_print_servers;
+  for (int i = 1; i <= 7; ++i) {
+    auto id = std::to_string(i);
+    auto print_server =
+        CreatePrintServer("device-" + id, "http://device-print-" + id,
+                          "Device LexaPrint - " + id);
+    device_print_servers.push_back(print_server);
+  }
+  device_policy_print_servers_provider_.SetPrintServers(device_print_servers);
+
+  manager_->ChoosePrintServer(selected_print_server.GetId());
+
+  EXPECT_THAT(server_printers_provider_->GetPrintServers(),
+              testing::UnorderedElementsAre(selected_print_server));
+}
+
 }  // namespace
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/printing/print_servers_policy_provider.cc b/chrome/browser/chromeos/printing/print_servers_policy_provider.cc
new file mode 100644
index 0000000..d68f2e6
--- /dev/null
+++ b/chrome/browser/chromeos/printing/print_servers_policy_provider.cc
@@ -0,0 +1,93 @@
+// 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/chromeos/printing/print_servers_policy_provider.h"
+
+#include "base/bind.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/printing/print_servers_provider.h"
+#include "chrome/browser/chromeos/printing/print_servers_provider_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/pref_names.h"
+
+namespace chromeos {
+
+namespace {
+
+constexpr int kMaxRecords = 16;
+
+}  // namespace
+
+PrintServersPolicyProvider::PrintServersPolicyProvider(
+    base::WeakPtr<PrintServersProvider> user_policy_provider,
+    base::WeakPtr<PrintServersProvider> device_policy_provider)
+    : user_policy_provider_(user_policy_provider),
+      device_policy_provider_(device_policy_provider) {
+  user_policy_provider_->AddObserver(this);
+  device_policy_provider_->AddObserver(this);
+}
+
+PrintServersPolicyProvider::~PrintServersPolicyProvider() = default;
+
+// static
+std::unique_ptr<PrintServersPolicyProvider> PrintServersPolicyProvider::Create(
+    Profile* profile) {
+  base::WeakPtr<PrintServersProvider> user_policy_provider =
+      PrintServersProviderFactory::Get()->GetForProfile(profile);
+  user_policy_provider->SetAllowlistPref(profile->GetPrefs(),
+                                         prefs::kExternalPrintServersAllowlist);
+  base::WeakPtr<PrintServersProvider> device_policy_provider =
+      PrintServersProviderFactory::Get()->GetForDevice();
+  device_policy_provider->SetAllowlistPref(
+      g_browser_process->local_state(),
+      prefs::kDeviceExternalPrintServersAllowlist);
+  return std::make_unique<PrintServersPolicyProvider>(user_policy_provider,
+                                                      device_policy_provider);
+}
+
+// static
+std::unique_ptr<PrintServersPolicyProvider>
+PrintServersPolicyProvider::CreateForTesting(
+    base::WeakPtr<PrintServersProvider> user_policy_provider,
+    base::WeakPtr<PrintServersProvider> device_policy_provider) {
+  return std::make_unique<PrintServersPolicyProvider>(user_policy_provider,
+                                                      device_policy_provider);
+}
+
+void PrintServersPolicyProvider::SetListener(
+    const OnPrintServersChanged& callback) {
+  callback_ = std::make_unique<OnPrintServersChanged>(callback);
+}
+
+void PrintServersPolicyProvider::OnServersChanged(
+    bool unused_complete,
+    const std::vector<PrintServer>& unused_servers) {
+  if (callback_) {
+    std::map<GURL, PrintServer> all_servers;
+    auto device_servers = device_policy_provider_->GetPrintServers();
+    if (device_servers.has_value()) {
+      for (const auto& server : device_servers.value()) {
+        all_servers.emplace(server.GetUrl(), server);
+      }
+    }
+    auto user_servers = user_policy_provider_->GetPrintServers();
+    if (user_servers.has_value()) {
+      for (const auto& server : user_servers.value()) {
+        all_servers.emplace(server.GetUrl(), server);
+      }
+    }
+    bool is_complete = user_servers.has_value() || device_servers.has_value();
+    ServerPrintersFetchingMode fetching_mode = GetFetchingMode(all_servers);
+    callback_->Run(is_complete, all_servers, fetching_mode);
+  }
+}
+
+ServerPrintersFetchingMode PrintServersPolicyProvider::GetFetchingMode(
+    const std::map<GURL, PrintServer>& all_servers) {
+  return all_servers.size() <= kMaxRecords
+             ? ServerPrintersFetchingMode::kStandard
+             : ServerPrintersFetchingMode::kSingleServerOnly;
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/printing/print_servers_policy_provider.h b/chrome/browser/chromeos/printing/print_servers_policy_provider.h
new file mode 100644
index 0000000..a305a44
--- /dev/null
+++ b/chrome/browser/chromeos/printing/print_servers_policy_provider.h
@@ -0,0 +1,71 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#ifndef CHROME_BROWSER_CHROMEOS_PRINTING_PRINT_SERVERS_POLICY_PROVIDER_H_
+#define CHROME_BROWSER_CHROMEOS_PRINTING_PRINT_SERVERS_POLICY_PROVIDER_H_
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "base/callback_forward.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/chromeos/printing/print_server.h"
+#include "chrome/browser/chromeos/printing/print_servers_provider.h"
+#include "components/keyed_service/core/keyed_service.h"
+
+class Profile;
+
+namespace chromeos {
+
+enum ServerPrintersFetchingMode {
+  kStandard,
+  kSingleServerOnly,
+};
+
+// This class observes values provided by the DeviceExternalPrintServers and
+// ExternalPrintServers policies and calculates resultant list of available
+// print servers. This list is propagated to the provided callback.
+class PrintServersPolicyProvider : public KeyedService,
+                                   public PrintServersProvider::Observer {
+ public:
+  PrintServersPolicyProvider(
+      base::WeakPtr<PrintServersProvider> user_policy_provider,
+      base::WeakPtr<PrintServersProvider> device_policy_provider);
+
+  ~PrintServersPolicyProvider() override;
+
+  using OnPrintServersChanged = typename base::RepeatingCallback<
+      void(bool, std::map<GURL, PrintServer>, ServerPrintersFetchingMode)>;
+
+  static std::unique_ptr<PrintServersPolicyProvider> Create(Profile* profile);
+
+  static std::unique_ptr<PrintServersPolicyProvider> CreateForTesting(
+      base::WeakPtr<PrintServersProvider> user_policy_provider,
+      base::WeakPtr<PrintServersProvider> device_policy_provider);
+
+  // Set the callback when print servers has been updated via policy.
+  void SetListener(const OnPrintServersChanged& callback);
+
+  // PrintServersProvider::Observer
+  void OnServersChanged(
+      bool unused_complete,
+      const std::vector<PrintServer>& unused_servers) override;
+
+ private:
+  ServerPrintersFetchingMode GetFetchingMode(
+      const std::map<GURL, PrintServer>& all_servers);
+
+  base::WeakPtr<PrintServersProvider> user_policy_provider_;
+  base::WeakPtr<PrintServersProvider> device_policy_provider_;
+
+  std::map<GURL, PrintServer> all_servers_;
+
+  std::unique_ptr<OnPrintServersChanged> callback_;
+
+  base::WeakPtrFactory<PrintServersPolicyProvider> weak_ptr_factory_{this};
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_PRINTING_PRINT_SERVERS_POLICY_PROVIDER_H_
diff --git a/chrome/browser/chromeos/printing/print_servers_provider.cc b/chrome/browser/chromeos/printing/print_servers_provider.cc
index 0a1bd72..e4e3ae8 100644
--- a/chrome/browser/chromeos/printing/print_servers_provider.cc
+++ b/chrome/browser/chromeos/printing/print_servers_provider.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <vector>
 
+#include "base/bind.h"
 #include "base/json/json_reader.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
@@ -30,8 +31,6 @@
 
 namespace {
 
-constexpr int kMaxRecords = 16;
-
 struct TaskResults {
   int task_id;
   std::vector<PrintServer> servers;
@@ -155,6 +154,7 @@
     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   }
 
+  // This method sets the allowlist to calculate resultant list of servers.
   void SetAllowlistPref(PrefService* prefs,
                         const std::string& allowlist_pref) override {
     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -173,6 +173,17 @@
     UpdateAllowlist();
   }
 
+  void NotifyObservers(bool servers_are_complete,
+                       const std::vector<PrintServer>& servers) {
+    for (auto& observer : observers_) {
+      observer.OnServersChanged(servers_are_complete, servers);
+    }
+  }
+
+  base::Optional<std::vector<PrintServer>> GetPrintServers() override {
+    return IsCompleted() ? base::make_optional(result_servers_) : base::nullopt;
+  }
+
   void AddObserver(PrintServersProvider::Observer* observer) override {
     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
     observers_.AddObserver(observer);
@@ -193,8 +204,7 @@
     result_servers_.clear();
     if (!(previously_completed && previously_empty)) {
       // Notify observers.
-      for (auto& observer : observers_)
-        observer.OnServersChanged(true, result_servers_);
+      NotifyObservers(true, result_servers_);
     }
   }
 
@@ -208,8 +218,7 @@
                        weak_ptr_factory_.GetWeakPtr()));
     if (previously_completed) {
       // Notify observers.
-      for (auto& observer : observers_)
-        observer.OnServersChanged(false, result_servers_);
+      NotifyObservers(false, result_servers_);
     }
   }
 
@@ -247,8 +256,7 @@
     const bool has_changes = CalculateResultantList();
     if (has_changes) {
       const bool is_completed = IsCompleted();
-      for (auto& observer : observers_)
-        observer.OnServersChanged(is_completed, result_servers_);
+      NotifyObservers(is_completed, result_servers_);
     }
   }
 
@@ -265,13 +273,6 @@
     } else {
       for (auto& print_server : servers_) {
         if (allowlist_.value().count(print_server.GetId())) {
-          if (new_servers.size() == kMaxRecords) {
-            LOG(WARNING) << "The list of resultant print servers read from "
-                         << "policies is too long. Only the first "
-                         << kMaxRecords << " print servers will be taken into "
-                         << "account";
-            break;
-          }
           new_servers.push_back(print_server);
         }
       }
@@ -302,8 +303,7 @@
     const bool has_changes = CalculateResultantList();
     // Notify observers if something changed.
     if (is_complete || has_changes) {
-      for (auto& observer : observers_)
-        observer.OnServersChanged(is_complete, result_servers_);
+      NotifyObservers(is_complete, result_servers_);
     }
   }
 
@@ -325,6 +325,8 @@
   PrefChangeRegistrar pref_change_registrar_;
   std::string allowlist_pref_;
 
+  std::unique_ptr<base::RepeatingCallback<void()>> policy_callback_;
+
   base::ObserverList<PrintServersProvider::Observer>::Unchecked observers_;
   base::WeakPtrFactory<PrintServersProviderImpl> weak_ptr_factory_{this};
 
diff --git a/chrome/browser/chromeos/printing/print_servers_provider.h b/chrome/browser/chromeos/printing/print_servers_provider.h
index 6ef3a76..063620f 100644
--- a/chrome/browser/chromeos/printing/print_servers_provider.h
+++ b/chrome/browser/chromeos/printing/print_servers_provider.h
@@ -9,6 +9,7 @@
 #include <set>
 #include <vector>
 
+#include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/chromeos/printing/print_server.h"
@@ -62,6 +63,10 @@
   // Clears the content of the policy.
   virtual void ClearData() = 0;
 
+  // Returns the list of all print servers given from the data provided in
+  // SetData(...) and limited by the allowlist.
+  virtual base::Optional<std::vector<PrintServer>> GetPrintServers() = 0;
+
  protected:
   PrintServersProvider() = default;
 
diff --git a/chrome/browser/chromeos/printing/printing_stubs.cc b/chrome/browser/chromeos/printing/printing_stubs.cc
index dc37ef86..c18d06a 100644
--- a/chrome/browser/chromeos/printing/printing_stubs.cc
+++ b/chrome/browser/chromeos/printing/printing_stubs.cc
@@ -20,4 +20,14 @@
   return {};
 }
 
+bool StubCupsPrintersManager::ChoosePrintServer(
+    const base::Optional<std::string>& selected_print_server_id) {
+  return true;
+}
+
+ServerPrintersFetchingMode StubCupsPrintersManager::GetServerPrintersFetchingMode()
+    const {
+  return ServerPrintersFetchingMode::kStandard;
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/printing/printing_stubs.h b/chrome/browser/chromeos/printing/printing_stubs.h
index c4ec1944..ece42e5 100644
--- a/chrome/browser/chromeos/printing/printing_stubs.h
+++ b/chrome/browser/chromeos/printing/printing_stubs.h
@@ -8,6 +8,7 @@
 #include <string>
 #include <vector>
 
+#include "base/optional.h"
 #include "chrome/browser/chromeos/printing/cups_printers_manager.h"
 #include "chrome/browser/chromeos/printing/printer_configurer.h"
 #include "chromeos/printing/ppd_provider.h"
@@ -32,6 +33,9 @@
   void FetchPrinterStatus(const std::string& printer_id,
                           PrinterStatusCallback cb) override {}
   void RecordNearbyNetworkPrinterCounts() const override {}
+  bool ChoosePrintServer(
+      const base::Optional<std::string>& selected_print_server_id) override;
+  ServerPrintersFetchingMode GetServerPrintersFetchingMode() const override;
 };
 
 class StubPrinterConfigurer : public PrinterConfigurer {
diff --git a/chrome/browser/chromeos/printing/server_printers_provider.cc b/chrome/browser/chromeos/printing/server_printers_provider.cc
index a4a0e61..2a534c57 100644
--- a/chrome/browser/chromeos/printing/server_printers_provider.cc
+++ b/chrome/browser/chromeos/printing/server_printers_provider.cc
@@ -16,8 +16,6 @@
 #include "base/sequenced_task_runner.h"
 #include "base/stl_util.h"
 #include "base/task/post_task.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/chromeos/printing/print_server.h"
 #include "chrome/browser/chromeos/printing/print_servers_provider.h"
 #include "chrome/browser/chromeos/printing/print_servers_provider_factory.h"
 #include "chrome/browser/chromeos/printing/server_printers_fetcher.h"
@@ -40,68 +38,12 @@
   std::vector<PrinterDetector::DetectedPrinter> printers;  // queried printers
 };
 
-class PrintServersPolicyProvider : public PrintServersProvider::Observer {
- public:
-  PrintServersPolicyProvider(base::WeakPtr<PrintServersProvider> provider,
-                             PrefService* prefs,
-                             const std::string& pref_name)
-      : provider_(provider) {
-    provider_->SetAllowlistPref(prefs, pref_name);
-    provider->AddObserver(this);
-  }
-
-  ~PrintServersPolicyProvider() override {
-    if (provider_) {
-      provider_->RemoveObserver(this);
-    }
-  }
-
-  base::Optional<std::vector<PrintServer>>& GetPrinterServers() {
-    return servers_;
-  }
-
-  void SetListener(const base::RepeatingCallback<void()>& callback) {
-    callback_ = std::make_unique<base::RepeatingCallback<void()>>(callback);
-    callback_->Run();
-  }
-
-  // PrintServersProvider::Observer implementation.
-  void OnServersChanged(bool servers_are_complete,
-                        const std::vector<PrintServer>& servers) override {
-    servers_ =
-        servers_are_complete ? base::make_optional(servers) : base::nullopt;
-    if (callback_) {
-      callback_->Run();
-    }
-  }
-
- private:
-  base::WeakPtr<PrintServersProvider> provider_;
-  base::Optional<std::vector<PrintServer>> servers_;
-  std::unique_ptr<base::RepeatingCallback<void()>> callback_;
-};
-
 class ServerPrintersProviderImpl
     : public ServerPrintersProvider,
       public base::SupportsWeakPtr<ServerPrintersProviderImpl> {
  public:
-  explicit ServerPrintersProviderImpl(Profile* profile)
-      : user_policy_provider_(std::make_unique<PrintServersPolicyProvider>(
-            PrintServersProviderFactory::Get()->GetForProfile(profile),
-            profile->GetPrefs(),
-            prefs::kExternalPrintServersAllowlist)),
-        device_policy_provider_(std::make_unique<PrintServersPolicyProvider>(
-            PrintServersProviderFactory::Get()->GetForDevice(),
-            g_browser_process->local_state(),
-            prefs::kDeviceExternalPrintServersAllowlist)) {
+  ServerPrintersProviderImpl() {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-    user_policy_provider_->SetListener(
-        base::BindRepeating(&ServerPrintersProviderImpl::NotifyPolicyChanged,
-                            weak_ptr_factory_.GetWeakPtr()));
-    device_policy_provider_->SetListener(
-        base::BindRepeating(&ServerPrintersProviderImpl::NotifyPolicyChanged,
-                            weak_ptr_factory_.GetWeakPtr()));
   }
 
   ~ServerPrintersProviderImpl() override = default;
@@ -122,7 +64,7 @@
   }
 
   void OnServersChanged(bool servers_are_complete,
-                        const std::map<GURL, PrintServer>& servers) {
+                        const std::map<GURL, PrintServer>& servers) override {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     // Create an entry in the device log.
     if (servers_are_complete) {
@@ -210,25 +152,6 @@
   }
 
  private:
-  void NotifyPolicyChanged() {
-    std::map<GURL, PrintServer> all_servers;
-    auto& device_servers = device_policy_provider_->GetPrinterServers();
-    if (device_servers.has_value()) {
-      for (const auto& server : device_servers.value()) {
-        all_servers.emplace(server.GetUrl(), server);
-      }
-    }
-    auto& user_servers = user_policy_provider_->GetPrinterServers();
-    if (user_servers.has_value()) {
-      for (const auto& server : user_servers.value()) {
-        all_servers.emplace(server.GetUrl(), server);
-      }
-    }
-
-    bool is_complete = user_servers.has_value() || device_servers.has_value();
-    OnServersChanged(is_complete, all_servers);
-  }
-
   // Returns true <=> all policies have been parsed and applied and all servers
   // have been queried (even when some errors occurred).
   bool IsComplete() const {
@@ -247,9 +170,6 @@
   // URLs that are being queried now with corresponding fetcher objects.
   std::map<GURL, std::unique_ptr<ServerPrintersFetcher>> fetchers_;
 
-  std::unique_ptr<PrintServersPolicyProvider> user_policy_provider_;
-  std::unique_ptr<PrintServersPolicyProvider> device_policy_provider_;
-
   SEQUENCE_CHECKER(sequence_checker_);
   base::WeakPtrFactory<ServerPrintersProviderImpl> weak_ptr_factory_{this};
   DISALLOW_COPY_AND_ASSIGN(ServerPrintersProviderImpl);
@@ -258,9 +178,8 @@
 }  // namespace
 
 // static
-std::unique_ptr<ServerPrintersProvider> ServerPrintersProvider::Create(
-    Profile* profile) {
-  return std::make_unique<ServerPrintersProviderImpl>(profile);
+std::unique_ptr<ServerPrintersProvider> ServerPrintersProvider::Create() {
+  return std::make_unique<ServerPrintersProviderImpl>();
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/printing/server_printers_provider.h b/chrome/browser/chromeos/printing/server_printers_provider.h
index 773214e..df08c5b 100644
--- a/chrome/browser/chromeos/printing/server_printers_provider.h
+++ b/chrome/browser/chromeos/printing/server_printers_provider.h
@@ -5,28 +5,27 @@
 #ifndef CHROME_BROWSER_CHROMEOS_PRINTING_SERVER_PRINTERS_PROVIDER_H_
 #define CHROME_BROWSER_CHROMEOS_PRINTING_SERVER_PRINTERS_PROVIDER_H_
 
+#include <map>
 #include <memory>
 #include <vector>
 
 #include "base/macros.h"
+#include "chrome/browser/chromeos/printing/print_server.h"
 #include "chrome/browser/chromeos/printing/printer_detector.h"
 #include "components/keyed_service/core/keyed_service.h"
 
-class Profile;
-
 namespace chromeos {
 
-// Uses classes PrintServersProvider and ServerPrintersFetcher to track list of
-// external print servers and printers exposed by them. These printers are
-// called server printers. All changes in the final list of available server
-// printers are signaled through a callback registered with the method
+// Given a list of external print servers, uses ServerPrintersFetcher to track
+// list of printers exposed by them. These printers are called server printers.
+// All changes in the final list of available server printers are signaled
+// through a callback registered with the method
 // RegisterPrintersFoundCallback(...). All methods must be called from the UI
 // sequence, the callback is also called from this sequence.
-class ServerPrintersProvider : public KeyedService {
+class ServerPrintersProvider {
  public:
-  // |profile| is a user profile, it cannot be nullptr.
-  static std::unique_ptr<ServerPrintersProvider> Create(Profile* profile);
-  ~ServerPrintersProvider() override = default;
+  static std::unique_ptr<ServerPrintersProvider> Create();
+  virtual ~ServerPrintersProvider() = default;
 
   using OnPrintersUpdateCallback = base::RepeatingCallback<void(bool complete)>;
 
@@ -35,6 +34,12 @@
   // unregister the current one.
   virtual void RegisterPrintersFoundCallback(OnPrintersUpdateCallback cb) = 0;
 
+  // |servers_are_complete| is true if all policies have been parsed and
+  // applied. |servers| contains the current list of print servers to query for
+  // printers.
+  virtual void OnServersChanged(bool servers_are_complete,
+                                const std::map<GURL, PrintServer>& servers) = 0;
+
   virtual std::vector<PrinterDetector::DetectedPrinter> GetPrinters() = 0;
 
  protected:
diff --git a/chrome/browser/chromeos/printing/server_printers_provider_factory.cc b/chrome/browser/chromeos/printing/server_printers_provider_factory.cc
deleted file mode 100644
index c2a182b..0000000
--- a/chrome/browser/chromeos/printing/server_printers_provider_factory.cc
+++ /dev/null
@@ -1,50 +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 "chrome/browser/chromeos/printing/server_printers_provider_factory.h"
-
-#include "base/no_destructor.h"
-#include "chrome/browser/chromeos/printing/server_printers_provider.h"
-#include "chrome/browser/profiles/incognito_helpers.h"
-#include "chrome/browser/profiles/profile.h"
-#include "components/keyed_service/content/browser_context_dependency_manager.h"
-
-namespace chromeos {
-
-// static
-ServerPrintersProviderFactory* ServerPrintersProviderFactory::GetInstance() {
-  static base::NoDestructor<ServerPrintersProviderFactory> instance;
-  return instance.get();
-}
-
-// static
-ServerPrintersProvider* ServerPrintersProviderFactory::GetForBrowserContext(
-    content::BrowserContext* context) {
-  return static_cast<ServerPrintersProvider*>(
-      GetInstance()->GetServiceForBrowserContext(context, true));
-}
-
-ServerPrintersProviderFactory::ServerPrintersProviderFactory()
-    : BrowserContextKeyedServiceFactory(
-          "ServerPrintersProviderFactory",
-          BrowserContextDependencyManager::GetInstance()) {}
-
-ServerPrintersProviderFactory::~ServerPrintersProviderFactory() = default;
-
-KeyedService* ServerPrintersProviderFactory::BuildServiceInstanceFor(
-    content::BrowserContext* context) const {
-  auto* profile = Profile::FromBrowserContext(context);
-  return ServerPrintersProvider::Create(profile).release();
-}
-
-content::BrowserContext* ServerPrintersProviderFactory::GetBrowserContextToUse(
-    content::BrowserContext* context) const {
-  return chrome::GetBrowserContextRedirectedInIncognito(context);
-}
-
-bool ServerPrintersProviderFactory::ServiceIsNULLWhileTesting() const {
-  return true;
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/printing/server_printers_provider_factory.h b/chrome/browser/chromeos/printing/server_printers_provider_factory.h
deleted file mode 100644
index 0a48e42..0000000
--- a/chrome/browser/chromeos/printing/server_printers_provider_factory.h
+++ /dev/null
@@ -1,47 +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 CHROME_BROWSER_CHROMEOS_PRINTING_SERVER_PRINTERS_PROVIDER_FACTORY_H_
-#define CHROME_BROWSER_CHROMEOS_PRINTING_SERVER_PRINTERS_PROVIDER_FACTORY_H_
-
-#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
-
-namespace content {
-class BrowserContext;
-}
-
-namespace base {
-template <typename T>
-class NoDestructor;
-}
-
-namespace chromeos {
-
-class ServerPrintersProvider;
-
-class ServerPrintersProviderFactory : public BrowserContextKeyedServiceFactory {
- public:
-  static ServerPrintersProviderFactory* GetInstance();
-  static ServerPrintersProvider* GetForBrowserContext(
-      content::BrowserContext* context);
-
- private:
-  friend class base::NoDestructor<ServerPrintersProviderFactory>;
-
-  ServerPrintersProviderFactory();
-  ~ServerPrintersProviderFactory() override;
-
-  // BrowserContextKeyedServiceFactory overrides:
-  KeyedService* BuildServiceInstanceFor(
-      content::BrowserContext* context) const override;
-  content::BrowserContext* GetBrowserContextToUse(
-      content::BrowserContext* context) const override;
-  bool ServiceIsNULLWhileTesting() const override;
-
-  DISALLOW_COPY_AND_ASSIGN(ServerPrintersProviderFactory);
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_PRINTING_SERVER_PRINTERS_PROVIDER_FACTORY_H_
diff --git a/chrome/browser/chromeos/printing/server_printers_provider_unittest.cc b/chrome/browser/chromeos/printing/server_printers_provider_unittest.cc
index b78e4e55..c7b45e3 100644
--- a/chrome/browser/chromeos/printing/server_printers_provider_unittest.cc
+++ b/chrome/browser/chromeos/printing/server_printers_provider_unittest.cc
@@ -4,20 +4,16 @@
 
 #include "chrome/browser/chromeos/printing/server_printers_provider.h"
 
+#include <map>
 #include <memory>
 #include <string>
 
-#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/printing/print_server.h"
 #include "chrome/browser/chromeos/printing/print_servers_provider.h"
 #include "chrome/browser/chromeos/printing/print_servers_provider_factory.h"
-#include "chrome/browser/chromeos/printing/printer_detector.h"
-#include "chrome/common/pref_names.h"
 #include "chrome/test/base/scoped_testing_local_state.h"
 #include "chrome/test/base/testing_browser_process.h"
-#include "chrome/test/base/testing_profile.h"
 #include "components/policy/proto/chrome_device_policy.pb.h"
-#include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "components/user_manager/scoped_user_manager.h"
 #include "content/public/test/browser_task_environment.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
@@ -36,89 +32,35 @@
 
 namespace {
 
-const char kAccountName[] = "test";
+chromeos::PrintServer PrintServer1() {
+  GURL url("http://192.168.1.5/printer");
+  chromeos::PrintServer print_server("id1", url, "LexaPrint");
+  return print_server;
+}
 
-// An example of configuration file with print servers for user policy.
-const char kUserExternalPrintServersContentsJson[] = R"json(
-[
-  {
-    "id": "id1",
-    "display_name": "LexaPrint - User",
-    "url": "ipp://192.168.1.5/user-printer",
-  }, {
-    "id": "id2",
-    "display_name": "Color Laser - User",
-    "url":"ipps://user-print-server.intranet.example.com:443/ipp/cl2k4",
-  }, {
-    "id": "id3",
-    "display_name": "B&W Printer - User",
-    "url":"ipps://user-print-server.intranet.example.com:443/bwprinter",
-  }
-])json";
+chromeos::PrintServer PrintServer2() {
+  GURL url("https://print-server.intranet.example.com:443/ipp/cl2k4");
+  chromeos::PrintServer print_server("id2", url, "Color Laser");
+  return print_server;
+}
 
-Printer UserPrinter1() {
+Printer Printer1() {
   Printer printer("server-20e91b728d4d04bc68132ced81772ef5");
-  printer.set_display_name("LexaPrint - User Name");
-  std::string server("ipp://192.168.1.5");
+  printer.set_display_name("LexaPrint - Name");
+  std::string server("ipp://192.168.1.5:80");
   printer.set_print_server_uri(server);
-  Uri url("ipp://192.168.1.5:631/printers/LexaPrint - User Name");
+  Uri url("ipp://192.168.1.5:80/printers/LexaPrint - Name");
   printer.SetUri(url);
   return printer;
 }
 
-Printer UserPrinter2() {
+Printer Printer2() {
   Printer printer("server-5da95e01216b1fe0ee1de25dc8d0a6e8");
-  printer.set_display_name("Color Laser - User Name");
-  std::string server("ipps://user-print-server.intranet.example.com");
+  printer.set_display_name("Color Laser - Name");
+  std::string server("ipps://print-server.intranet.example.com");
   printer.set_print_server_uri(server);
   Uri url(
-      "ipps://user-print-server.intranet.example.com:443/printers/"
-      "Color Laser "
-      "- User Name");
-  printer.SetUri(url);
-  return printer;
-}
-
-// An example of configuration file with print servers for device policy.
-const char kDeviceExternalPrintServersContentsJson[] = R"json(
-[
-  {
-    "id": "id1",
-    "display_name": "LexaPrint - Device",
-    "url": "ipp://192.168.1.5/device-printer",
-  }, {
-    "id": "id2",
-    "display_name": "Color Laser - Device",
-    "url":"ipps://device-print-server.intranet.example.com:443/ipp/cl2k4",
-  }, {
-    "id": "id3",
-    "display_name": "B&W Printer - Device",
-    "url":"ipps://device-print-server.intranet.example.com:443/bwprinter",
-  }
-])json";
-
-// An example allowlist for device policy.
-const std::vector<std::string> kDevicePrintServersPolicyAllowlist = {
-    "id3", "idX", "id1"};
-
-Printer DevicePrinter1() {
-  Printer printer("server-f4a2ce25d8f9e6335d36f8253f8cf047");
-  printer.set_display_name("LexaPrint - Device Name");
-  std::string server("ipp://192.168.1.5");
-  Uri url("ipp://192.168.1.5:631/printers/LexaPrint - Device Name");
-  printer.set_print_server_uri(server);
-  printer.SetUri(url);
-  return printer;
-}
-
-Printer DevicePrinter2() {
-  Printer printer("server-1f88fe69dd2ce98ae6c195f3eb295a6d");
-  printer.set_display_name("B&W Printer - Device Name");
-  std::string server("ipps://device-print-server.intranet.example.com");
-  printer.set_print_server_uri(server);
-  Uri url(
-      "ipps://device-print-server.intranet.example.com:443/printers/"
-      "B&W Printer - Device Name");
+      "ipps://print-server.intranet.example.com/printers/Color Laser - Name");
   printer.SetUri(url);
   return printer;
 }
@@ -140,8 +82,7 @@
 class ServerPrintersProviderTest : public ::testing::Test {
  public:
   ServerPrintersProviderTest()
-      : local_state_(TestingBrowserProcess::GetGlobal()),
-        test_shared_loader_factory_(
+      : test_shared_loader_factory_(
             base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
                 &test_url_loader_factory_)) {}
 
@@ -152,23 +93,7 @@
 
     ASSERT_TRUE(test_server_.Start());
 
-    SetupUserProfile();
-
-    server_printers_provider_ = ServerPrintersProvider::Create(profile_.get());
-  }
-
-  void SetupUserProfile() {
-    auto unique_user_manager = std::make_unique<FakeChromeUserManager>();
-    auto* user_manager = unique_user_manager.get();
-    user_manager_enabler_ = std::make_unique<user_manager::ScopedUserManager>(
-        std::move(unique_user_manager));
-
-    TestingProfile::Builder profile_builder;
-    profile_builder.SetProfileName(kAccountName);
-    profile_ = profile_builder.Build();
-    user_manager->AddUserWithAffiliationAndTypeAndProfile(
-        AccountId::FromUserEmail(kAccountName), false,
-        user_manager::UserType::USER_TYPE_REGULAR, profile_.get());
+    server_printers_provider_ = ServerPrintersProvider::Create();
   }
 
   void TearDown() override { PrintServersProviderFactory::Get()->Shutdown(); }
@@ -188,120 +113,53 @@
     return response_body;
   }
 
-  void ApplyDevicePolicy() {
-    device_print_servers_provider_ =
-        PrintServersProviderFactory::Get()->GetForDevice();
-    device_print_servers_provider_->SetData(
-        std::make_unique<std::string>(kDeviceExternalPrintServersContentsJson));
-    // Apply device allowlist.
-    auto device_allowlist =
-        std::make_unique<base::Value>(base::Value::Type::LIST);
-
-    for (const std::string& id : kDevicePrintServersPolicyAllowlist)
-      device_allowlist->Append(base::Value(id));
-    local_state_.Get()->SetManagedPref(
-        prefs::kDeviceExternalPrintServersAllowlist,
-        std::move(device_allowlist));
-  }
-
-  void ApplyUserPolicy() {
-    static const std::vector<std::string> kUserPrintServersPolicyAllowlist = {
-        "idX", "id2", "id1"};
-    user_print_servers_provider_ =
-        PrintServersProviderFactory::Get()->GetForProfile(profile_.get());
-    user_print_servers_provider_->SetData(
-        std::make_unique<std::string>(kUserExternalPrintServersContentsJson));
-    // Apply user allowlist.
-    auto user_allowlist = std::make_unique<base::ListValue>();
-    for (const std::string& id : kUserPrintServersPolicyAllowlist)
-      user_allowlist->Append(base::Value(id));
-    profile_->GetTestingPrefService()->SetManagedPref(
-        prefs::kExternalPrintServersAllowlist, std::move(user_allowlist));
+  void OnServersChanged(bool is_complete,
+                        std::vector<chromeos::PrintServer> print_servers) {
+    std::map<GURL, chromeos::PrintServer> new_print_servers;
+    for (auto& print_server : print_servers) {
+      new_print_servers.emplace(print_server.GetUrl(), print_server);
+    }
+    server_printers_provider_->OnServersChanged(is_complete, new_print_servers);
   }
 
   // Everything must be called on Chrome_UIThread.
   content::BrowserTaskEnvironment task_environment_;
 
-  ScopedTestingLocalState local_state_;
-
   network::TestURLLoaderFactory test_url_loader_factory_;
 
   scoped_refptr<network::WeakWrapperSharedURLLoaderFactory>
       test_shared_loader_factory_;
 
-  std::unique_ptr<TestingProfile> profile_;
-
-  std::unique_ptr<user_manager::ScopedUserManager> user_manager_enabler_;
-
   net::test_server::EmbeddedTestServer test_server_;
 
-  base::WeakPtr<PrintServersProvider> user_print_servers_provider_;
-  base::WeakPtr<PrintServersProvider> device_print_servers_provider_;
-
   std::unique_ptr<ServerPrintersProvider> server_printers_provider_;
 };
 
-TEST_F(ServerPrintersProviderTest, GetPrinters_OnlyDevicePolicy) {
+TEST_F(ServerPrintersProviderTest, GetPrinters) {
   test_url_loader_factory_.AddResponse(
-      "http://192.168.1.5:631/device-printer",
-      CreateResponse("LexaPrint - Device Name", "LexaPrint Description"));
+      "http://192.168.1.5/printer",
+      CreateResponse("LexaPrint - Name", "LexaPrint Description"));
   test_url_loader_factory_.AddResponse(
-      "https://device-print-server.intranet.example.com:443/bwprinter",
-      CreateResponse("B&W Printer - Device Name", "B&W Printer Description"));
+      "https://print-server.intranet.example.com:443/ipp/cl2k4",
+      CreateResponse("Color Laser - Name", "Color Laser Description"));
 
   EXPECT_TRUE(server_printers_provider_->GetPrinters().empty());
 
-  ApplyDevicePolicy();
+  std::vector<PrintServer> print_servers;
+  print_servers.push_back(PrintServer1());
+  print_servers.push_back(PrintServer2());
+  OnServersChanged(true, print_servers);
   task_environment_.RunUntilIdle();
 
-  EXPECT_THAT(server_printers_provider_->GetPrinters(),
-              UnorderedElementsAre(PrinterMatcher(DevicePrinter1()),
-                                   PrinterMatcher(DevicePrinter2())));
-}
+  auto first = server_printers_provider_->GetPrinters().front();
 
-TEST_F(ServerPrintersProviderTest, GetPrinters_OnlyUserPolicy) {
-  test_url_loader_factory_.AddResponse(
-      "http://192.168.1.5:631/user-printer",
-      CreateResponse("LexaPrint - User Name", "LexaPrint Description"));
-  test_url_loader_factory_.AddResponse(
-      "https://user-print-server.intranet.example.com/ipp/cl2k4",
-      CreateResponse("Color Laser - User Name", "Color Laser Description"));
-
-  EXPECT_TRUE(server_printers_provider_->GetPrinters().empty());
-
-  ApplyUserPolicy();
-  task_environment_.RunUntilIdle();
+  LOG(INFO) << first.printer.uri().GetNormalized()
+            << " server:" << first.printer.print_server_uri()
+            << " name:" << first.printer.display_name();
 
   EXPECT_THAT(server_printers_provider_->GetPrinters(),
-              UnorderedElementsAre(PrinterMatcher(UserPrinter1()),
-                                   PrinterMatcher(UserPrinter2())));
-}
-
-TEST_F(ServerPrintersProviderTest, GetPrinters_UserAndDevicePolicy) {
-  test_url_loader_factory_.AddResponse(
-      "http://192.168.1.5:631/device-printer",
-      CreateResponse("LexaPrint - Device Name", "LexaPrint Description"));
-  test_url_loader_factory_.AddResponse(
-      "https://device-print-server.intranet.example.com:443/bwprinter",
-      CreateResponse("B&W Printer - Device Name", "B&W Printer Description"));
-  test_url_loader_factory_.AddResponse(
-      "http://192.168.1.5:631/user-printer",
-      CreateResponse("LexaPrint - User Name", "LexaPrint Description"));
-  test_url_loader_factory_.AddResponse(
-      "https://user-print-server.intranet.example.com/ipp/cl2k4",
-      CreateResponse("Color Laser - User Name", "Color Laser Description"));
-
-  EXPECT_TRUE(server_printers_provider_->GetPrinters().empty());
-
-  ApplyUserPolicy();
-  ApplyDevicePolicy();
-  task_environment_.RunUntilIdle();
-
-  EXPECT_THAT(server_printers_provider_->GetPrinters(),
-              UnorderedElementsAre(PrinterMatcher(DevicePrinter1()),
-                                   PrinterMatcher(DevicePrinter2()),
-                                   PrinterMatcher(UserPrinter1()),
-                                   PrinterMatcher(UserPrinter2())));
+              UnorderedElementsAre(PrinterMatcher(Printer1()),
+                                   PrinterMatcher(Printer2())));
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/content_settings/content_settings_policy_provider_unittest.cc b/chrome/browser/content_settings/content_settings_policy_provider_unittest.cc
index ac18117..a7ce69d 100644
--- a/chrome/browser/content_settings/content_settings_policy_provider_unittest.cc
+++ b/chrome/browser/content_settings/content_settings_policy_provider_unittest.cc
@@ -164,40 +164,6 @@
   provider.ShutdownOnUIThread();
 }
 
-TEST_F(PolicyProviderTest, ResourceIdentifier) {
-  TestingProfile profile;
-  sync_preferences::TestingPrefServiceSyncable* prefs =
-      profile.GetTestingPrefService();
-
-  auto value = std::make_unique<base::ListValue>();
-  value->AppendString("http://mail.google.com:80");
-  prefs->SetManagedPref(prefs::kManagedPluginsAllowedForUrls, std::move(value));
-
-  PolicyProvider provider(prefs);
-
-  GURL youtube_url("http://www.youtube.com");
-  GURL google_url("http://mail.google.com");
-
-  EXPECT_EQ(CONTENT_SETTING_DEFAULT,
-            TestUtils::GetContentSetting(&provider, youtube_url, youtube_url,
-                                         ContentSettingsType::PLUGINS,
-                                         "someplugin", false));
-
-  // There is currently no policy support for resource content settings.
-  // Resource identifiers are simply ignored by the PolicyProvider.
-  EXPECT_EQ(CONTENT_SETTING_ALLOW,
-            TestUtils::GetContentSetting(&provider, google_url, google_url,
-                                         ContentSettingsType::PLUGINS,
-                                         std::string(), false));
-
-  EXPECT_EQ(CONTENT_SETTING_DEFAULT,
-            TestUtils::GetContentSetting(&provider, google_url, google_url,
-                                         ContentSettingsType::PLUGINS,
-                                         "someplugin", false));
-
-  provider.ShutdownOnUIThread();
-}
-
 TEST_F(PolicyProviderTest, AutoSelectCertificateList) {
   TestingProfile profile;
   sync_preferences::TestingPrefServiceSyncable* prefs =
@@ -261,52 +227,4 @@
   provider.ShutdownOnUIThread();
 }
 
-TEST_F(PolicyProviderTest, WildcardsMatchingTest) {
-  // Enabling the feature which disallows wildcard matching for Plugin content
-  // settings
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitFromCommandLine(
-      "DisallowWildcardsInPluginContentSettings", std::string());
-
-  TestingProfile profile;
-  sync_preferences::TestingPrefServiceSyncable* prefs =
-      profile.GetTestingPrefService();
-  auto value = std::make_unique<base::ListValue>();
-  value->AppendString("[*.]google.com");
-  value->AppendString("http://drive.google.com:443/home");
-  value->AppendString("www.foo.com:*/*");
-  value->AppendString("*://[*.]bar.com:*/*");
-  prefs->SetManagedPref(prefs::kManagedPluginsAllowedForUrls, std::move(value));
-
-  PolicyProvider provider(prefs);
-
-  GURL google_mail_url("http://mail.google.com");
-  GURL google_drive_url("http://drive.google.com:443/settings");
-  GURL foo_url("https://www.foo.com:443/home");
-  GURL bar_url("https://foobar.com:443/");
-
-  // mail.google.com doesnt match because it's not an exact match
-  EXPECT_EQ(CONTENT_SETTING_DEFAULT,
-            TestUtils::GetContentSetting(
-                &provider, google_mail_url, google_mail_url,
-                ContentSettingsType::PLUGINS, std::string(), false));
-
-  // drive.google.com matches because it's an exact match
-  EXPECT_EQ(CONTENT_SETTING_ALLOW,
-            TestUtils::GetContentSetting(
-                &provider, google_drive_url, google_drive_url,
-                ContentSettingsType::PLUGINS, std::string(), false));
-
-  EXPECT_EQ(CONTENT_SETTING_ALLOW,
-            TestUtils::GetContentSetting(&provider, foo_url, foo_url,
-                                         ContentSettingsType::PLUGINS,
-                                         std::string(), false));
-
-  EXPECT_EQ(CONTENT_SETTING_DEFAULT,
-            TestUtils::GetContentSetting(&provider, bar_url, bar_url,
-                                         ContentSettingsType::PLUGINS,
-                                         std::string(), false));
-  provider.ShutdownOnUIThread();
-}
-
 }  // namespace content_settings
diff --git a/chrome/browser/crash_recovery_browsertest.cc b/chrome/browser/crash_recovery_browsertest.cc
index 1e014d7..8a21b15 100644
--- a/chrome/browser/crash_recovery_browsertest.cc
+++ b/chrome/browser/crash_recovery_browsertest.cc
@@ -96,13 +96,7 @@
 };
 
 // Test that reload works after a crash.
-// Flaky timeouts on Win7 Tests (dbg)(1); see https://crbug.com/985255.
-#if defined(OS_WIN) && !defined(NDEBUG)
-#define MAYBE_Reload DISABLED_Reload
-#else
-#define MAYBE_Reload Reload
-#endif
-IN_PROC_BROWSER_TEST_F(CrashRecoveryBrowserTest, MAYBE_Reload) {
+IN_PROC_BROWSER_TEST_F(CrashRecoveryBrowserTest, Reload) {
   // The title of the active tab should change each time this URL is loaded.
   GURL url(
       "data:text/html,<script>document.title=new Date().valueOf()</script>");
@@ -127,14 +121,7 @@
 }
 
 // Test that reload after a crash forces a cache revalidation.
-//
-// Flaky timeouts on Win7 Tests (dbg)(1); see https://crbug.com/985255.
-#if defined(OS_WIN) && !defined(NDEBUG)
-#define MAYBE_ReloadCacheRevalidate DISABLED_ReloadCacheRevalidate
-#else
-#define MAYBE_ReloadCacheRevalidate ReloadCacheRevalidate
-#endif
-IN_PROC_BROWSER_TEST_F(CrashRecoveryBrowserTest, MAYBE_ReloadCacheRevalidate) {
+IN_PROC_BROWSER_TEST_F(CrashRecoveryBrowserTest, ReloadCacheRevalidate) {
   const char kTestPath[] = "/test";
 
   // Use the test server so as not to bypass cache behavior. The title of the
@@ -163,13 +150,7 @@
 // There was an earlier bug (1270510) in process-per-site in which the max page
 // ID of the RenderProcessHost was stale, so the NavigationEntry in the new tab
 // was not committed.  This prevents regression of that bug.
-// Flaky timeouts on Win7 Tests (dbg)(1); see https://crbug.com/985255.
-#if defined(OS_WIN) && !defined(NDEBUG)
-#define MAYBE_LoadInNewTab DISABLED_LoadInNewTab
-#else
-#define MAYBE_LoadInNewTab LoadInNewTab
-#endif
-IN_PROC_BROWSER_TEST_F(CrashRecoveryBrowserTest, MAYBE_LoadInNewTab) {
+IN_PROC_BROWSER_TEST_F(CrashRecoveryBrowserTest, LoadInNewTab) {
   const base::FilePath::CharType kTitle2File[] =
       FILE_PATH_LITERAL("title2.html");
 
@@ -196,14 +177,7 @@
 
 // Tests that reloads of navigation errors behave correctly after a crash.
 // Regression test for http://crbug.com/348918
-//
-// Flaky timeouts on Win7 Tests (dbg)(1); see https://crbug.com/985255.
-#if defined(OS_WIN) && !defined(NDEBUG)
-#define MAYBE_DoubleReloadWithError DISABLED_DoubleReloadWithError
-#else
-#define MAYBE_DoubleReloadWithError DoubleReloadWithError
-#endif
-IN_PROC_BROWSER_TEST_F(CrashRecoveryBrowserTest, MAYBE_DoubleReloadWithError) {
+IN_PROC_BROWSER_TEST_F(CrashRecoveryBrowserTest, DoubleReloadWithError) {
   GURL url(content::GetWebUIURL("bogus"));
   ui_test_utils::NavigateToURL(browser(), url);
   ASSERT_EQ(url, GetActiveWebContents()->GetVisibleURL());
@@ -221,14 +195,7 @@
 
 // Tests that a beforeunload handler doesn't run if user navigates to
 // chrome::crash.
-//
-// Flaky timeouts on Win7 Tests (dbg)(1); see https://crbug.com/985255.
-#if defined(OS_WIN) && !defined(NDEBUG)
-#define MAYBE_BeforeUnloadNotRun DISABLED_BeforeUnloadNotRun
-#else
-#define MAYBE_BeforeUnloadNotRun BeforeUnloadNotRun
-#endif
-IN_PROC_BROWSER_TEST_F(CrashRecoveryBrowserTest, MAYBE_BeforeUnloadNotRun) {
+IN_PROC_BROWSER_TEST_F(CrashRecoveryBrowserTest, BeforeUnloadNotRun) {
   const char* kBeforeUnloadHTML =
     "<html><body>"
     "<script>window.onbeforeunload=function(e){return 'foo'}</script>"
diff --git a/chrome/browser/devtools/devtools_window.cc b/chrome/browser/devtools/devtools_window.cc
index 0503e8a..f43695a 100644
--- a/chrome/browser/devtools/devtools_window.cc
+++ b/chrome/browser/devtools/devtools_window.cc
@@ -1584,7 +1584,8 @@
     wp_prefs->SetKey(kDevToolsApp, std::move(dev_tools_defaults));
   }
 
-  browser_ = new Browser(Browser::CreateParams::CreateForDevTools(profile_));
+  browser_ =
+      Browser::Create(Browser::CreateParams::CreateForDevTools(profile_));
   browser_->tab_strip_model()->AddWebContents(
       OwnedMainWebContents::TakeWebContents(
           std::move(owned_main_web_contents_)),
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc
index 823c095f..ea18e535 100644
--- a/chrome/browser/download/download_browsertest.cc
+++ b/chrome/browser/download/download_browsertest.cc
@@ -2721,8 +2721,8 @@
 // Times out often on debug ChromeOS because test is slow.
 #if defined(OS_CHROMEOS) && (!defined(NDEBUG) || defined(MEMORY_SANITIZER))
 #define MAYBE_SaveLargeImage DISABLED_SaveLargeImage
-#elif defined(OS_MAC) || defined(OS_LINUX)
-// Started to be flaky on Linux and Mac too. https://crbug.com/1141263
+#elif defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX)
+// Flaking on Windows, macOS, and Linux. https://crbug.com/1141263
 #define MAYBE_SaveLargeImage DISABLED_SaveLargeImage
 #else
 #define MAYBE_SaveLargeImage SaveLargeImage
diff --git a/chrome/browser/download/download_crx_util.cc b/chrome/browser/download/download_crx_util.cc
index 912b7f1..d8d5dbce 100644
--- a/chrome/browser/download/download_crx_util.cc
+++ b/chrome/browser/download/download_crx_util.cc
@@ -54,7 +54,7 @@
     if (!web_contents) {
       Browser* browser = chrome::FindLastActiveWithProfile(profile);
       if (!browser) {
-        browser = new Browser(
+        browser = Browser::Create(
             Browser::CreateParams(Browser::TYPE_NORMAL, profile, true));
       }
       web_contents = browser->tab_strip_model()->GetActiveWebContents();
diff --git a/chrome/browser/extensions/api/debugger/debugger_apitest.cc b/chrome/browser/extensions/api/debugger/debugger_apitest.cc
index 5037f004..ae29728 100644
--- a/chrome/browser/extensions/api/debugger/debugger_apitest.cc
+++ b/chrome/browser/extensions/api/debugger/debugger_apitest.cc
@@ -215,7 +215,7 @@
   scoped_refptr<DebuggerDetachFunction> detach_function;
 
   Browser* another_browser =
-      new Browser(Browser::CreateParams(profile(), true));
+      Browser::Create(Browser::CreateParams(profile(), true));
   AddBlankTabAndShow(another_browser);
   AddBlankTabAndShow(another_browser);
   int tab_id2 = sessions::SessionTabHelper::IdForTab(
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc b/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
index ad26d5d..b900e63 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
@@ -361,7 +361,7 @@
   Browser::CreateParams params(profile(), true);
   params.type = Browser::TYPE_NORMAL;
   params.window = browser_window_.get();
-  browser_.reset(new Browser(params));
+  browser_.reset(Browser::Create(params));
 
   // Allow the API to be created.
   EventRouterFactory::GetInstance()->SetTestingFactory(
diff --git a/chrome/browser/extensions/api/management/management_api_unittest.cc b/chrome/browser/extensions/api/management/management_api_unittest.cc
index ffd97fd..33badd9 100644
--- a/chrome/browser/extensions/api/management/management_api_unittest.cc
+++ b/chrome/browser/extensions/api/management/management_api_unittest.cc
@@ -155,7 +155,7 @@
   Browser::CreateParams params(profile(), true);
   params.type = Browser::TYPE_NORMAL;
   params.window = browser_window_.get();
-  browser_.reset(new Browser(params));
+  browser_.reset(Browser::Create(params));
 }
 
 void ManagementApiUnitTest::TearDown() {
diff --git a/chrome/browser/extensions/api/permissions/permissions_api_unittest.cc b/chrome/browser/extensions/api/permissions/permissions_api_unittest.cc
index 17d7dc8..e0e44e2 100644
--- a/chrome/browser/extensions/api/permissions/permissions_api_unittest.cc
+++ b/chrome/browser/extensions/api/permissions/permissions_api_unittest.cc
@@ -142,7 +142,7 @@
     Browser::CreateParams params(profile(), true);
     params.type = Browser::TYPE_NORMAL;
     params.window = browser_window_.get();
-    browser_.reset(new Browser(params));
+    browser_.reset(Browser::Create(params));
   }
   // ExtensionServiceTestBase:
   void TearDown() override {
diff --git a/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc b/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc
index 592b1ae..903eef8 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc
@@ -119,7 +119,7 @@
   Browser::CreateParams params(profile(), true);
   params.type = Browser::TYPE_NORMAL;
   params.window = browser_window_.get();
-  browser_.reset(new Browser(params));
+  browser_.reset(Browser::Create(params));
   scoped_screen_override_ =
       std::make_unique<ScopedScreenOverride>(&test_screen_);
 }
diff --git a/chrome/browser/extensions/api/tabs/tabs_test.cc b/chrome/browser/extensions/api/tabs/tabs_test.cc
index f0bf023..937ebb8a 100644
--- a/chrome/browser/extensions/api/tabs/tabs_test.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_test.cc
@@ -185,7 +185,7 @@
   // minimize/maximize programmatically?
 
   // Popup.
-  Browser* popup_browser = new Browser(
+  Browser* popup_browser = Browser::Create(
       Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile(), true));
   function = new WindowsGetFunction();
   function->set_extension(extension.get());
@@ -677,7 +677,7 @@
   // Test creates new popup window, closes it right away and then tries to open
   // a new tab in it. Tab should not be opened in the popup window, but in a
   // tabbed browser window.
-  Browser* popup_browser = new Browser(
+  Browser* popup_browser = Browser::Create(
       Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile(), true));
   int window_id = ExtensionTabUtil::GetWindowId(popup_browser);
   chrome::CloseWindow(popup_browser);
@@ -855,11 +855,11 @@
     bool as_popup) {
   Browser* new_browser;
   if (as_popup)
-    new_browser = new Browser(
+    new_browser = Browser::Create(
         Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile(), true));
   else
     new_browser =
-        new Browser(Browser::CreateParams(browser()->profile(), true));
+        Browser::Create(Browser::CreateParams(browser()->profile(), true));
   AddBlankTabAndShow(new_browser);
   return new_browser;
 }
@@ -1240,7 +1240,7 @@
       " \"maxWidth\": 400, \"maxHeight\": 400}}");
 
   Browser* browser_window =
-      new Browser(Browser::CreateParams(browser()->profile(), true));
+      Browser::Create(Browser::CreateParams(browser()->profile(), true));
   AddBlankTabAndShow(browser_window);
 
   DevToolsWindow* devtools_window =
diff --git a/chrome/browser/extensions/extension_context_menu_model.cc b/chrome/browser/extensions/extension_context_menu_model.cc
index 8648aad..2287412a 100644
--- a/chrome/browser/extensions/extension_context_menu_model.cc
+++ b/chrome/browser/extensions/extension_context_menu_model.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/extensions/chrome_extension_browser_constants.h"
 #include "chrome/browser/extensions/context_menu_matcher.h"
 #include "chrome/browser/extensions/extension_action_runner.h"
+#include "chrome/browser/extensions/extension_management.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/extensions/extension_uninstall_dialog.h"
 #include "chrome/browser/extensions/extension_util.h"
@@ -84,15 +85,24 @@
   return false;
 }
 
+// Returns true if the given |extension| is required to remain pinned/visible in
+// the toolbar by policy.
+bool IsExtensionForcePinned(const Extension& extension, Profile* profile) {
+  auto* management = ExtensionManagementFactory::GetForBrowserContext(profile);
+  return base::Contains(management->GetForcePinnedList(), extension.id());
+}
+
 // Returns the id for the visibility command for the given |extension|.
 int GetVisibilityStringId(
     Profile* profile,
     const Extension* extension,
     ExtensionContextMenuModel::ButtonVisibility button_visibility) {
   if (base::FeatureList::IsEnabled(features::kExtensionsToolbarMenu)) {
-    return button_visibility == ExtensionContextMenuModel::PINNED
-               ? IDS_EXTENSIONS_UNPIN_FROM_TOOLBAR
-               : IDS_EXTENSIONS_PIN_TO_TOOLBAR;
+    if (IsExtensionForcePinned(*extension, profile))
+      return IDS_EXTENSIONS_PINNED_BY_ADMIN;
+    if (button_visibility == ExtensionContextMenuModel::PINNED)
+      return IDS_EXTENSIONS_UNPIN_FROM_TOOLBAR;
+    return IDS_EXTENSIONS_PIN_TO_TOOLBAR;
   }
   DCHECK(profile);
   int string_id = -1;
@@ -296,9 +306,9 @@
     // Extension pinning/unpinning is not available for Incognito as this leaves
     // a trace of user activity.
     case TOGGLE_VISIBILITY:
-      if (base::FeatureList::IsEnabled(features::kExtensionsToolbarMenu))
-        return !browser_->profile()->IsOffTheRecord();
-      return true;
+      return (base::FeatureList::IsEnabled(features::kExtensionsToolbarMenu) &&
+              !browser_->profile()->IsOffTheRecord() &&
+              !IsExtensionForcePinned(*extension, profile_));
     // Manage extensions is always enabled.
     case MANAGE_EXTENSIONS:
       return true;
@@ -429,6 +439,12 @@
       GetVisibilityStringId(profile_, extension, button_visibility);
   DCHECK_NE(-1, visibility_string_id);
   AddItemWithStringId(TOGGLE_VISIBILITY, visibility_string_id);
+  if (IsExtensionForcePinned(*extension, profile_)) {
+    int toggle_visibility_index = GetIndexOfCommandId(TOGGLE_VISIBILITY);
+    SetIcon(toggle_visibility_index,
+            ui::ImageModel::FromVectorIcon(vector_icons::kBusinessIcon,
+                                           gfx::kChromeIconGrey, 16));
+  }
 
   if (!is_component_) {
     AddSeparator(ui::NORMAL_SEPARATOR);
diff --git a/chrome/browser/extensions/extension_context_menu_model_unittest.cc b/chrome/browser/extensions/extension_context_menu_model_unittest.cc
index 5e8d75ce..592911a 100644
--- a/chrome/browser/extensions/extension_context_menu_model_unittest.cc
+++ b/chrome/browser/extensions/extension_context_menu_model_unittest.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/json/json_reader.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/stringprintf.h"
@@ -324,7 +325,7 @@
     Browser::CreateParams params(profile(), true);
     test_window_.reset(new TestBrowserWindow());
     params.window = test_window_.get();
-    browser_.reset(new Browser(params));
+    browser_.reset(Browser::Create(params));
   }
   return browser_.get();
 }
@@ -613,6 +614,62 @@
   }
 }
 
+// Test that the "pin" and "unpin" menu items is disabled when the extension is
+// force-pinned via ExtensionSettings.
+TEST_F(ExtensionContextMenuModelTest, ExtensionContextMenuForcePinned) {
+  InitializeEmptyExtensionService();
+  Browser* browser = GetBrowser();
+  extension_action_test_util::CreateToolbarModelForProfile(profile());
+  const Extension* extension = AddExtension(
+      "extension", manifest_keys::kBrowserAction, Manifest::INTERNAL);
+  const Extension* force_pinned_extension =
+      AddExtension("force_pinned_extension", manifest_keys::kBrowserAction,
+                   Manifest::INTERNAL);
+
+  std::string json = base::StringPrintf(
+      R"({
+        "%s": {
+          "toolbar_pin": "force_pinned"
+        }
+      })",
+      force_pinned_extension->id().c_str());
+  base::Optional<base::Value> parsed = base::JSONReader::Read(json);
+  policy::PolicyMap map;
+  map.Set("ExtensionSettings", policy::POLICY_LEVEL_MANDATORY,
+          policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_PLATFORM,
+          std::move(parsed), nullptr);
+  policy_provider()->UpdateChromePolicy(map);
+
+  // For laziness.
+  const ExtensionContextMenuModel::MenuEntries visibility_command =
+      ExtensionContextMenuModel::TOGGLE_VISIBILITY;
+  const base::string16 unpin_string =
+      l10n_util::GetStringUTF16(IDS_EXTENSIONS_UNPIN_FROM_TOOLBAR);
+  const base::string16 force_pinned_string =
+      l10n_util::GetStringUTF16(IDS_EXTENSIONS_PINNED_BY_ADMIN);
+
+  {
+    // Not force-pinned.
+    ExtensionContextMenuModel menu(
+        extension, browser, ExtensionContextMenuModel::PINNED, nullptr, true);
+    int index = menu.GetIndexOfCommandId(visibility_command);
+    EXPECT_NE(-1, index);
+    EXPECT_TRUE(menu.IsEnabledAt(index));
+    EXPECT_EQ(unpin_string, menu.GetLabelAt(index));
+  }
+
+  {
+    // Force-pinned.
+    ExtensionContextMenuModel menu(force_pinned_extension, browser,
+                                   ExtensionContextMenuModel::PINNED, nullptr,
+                                   true);
+    int index = menu.GetIndexOfCommandId(visibility_command);
+    EXPECT_NE(-1, index);
+    EXPECT_FALSE(menu.IsEnabledAt(index));
+    EXPECT_EQ(force_pinned_string, menu.GetLabelAt(index));
+  }
+}
+
 TEST_F(ExtensionContextMenuModelTest, ExtensionContextUninstall) {
   InitializeEmptyExtensionService();
 
diff --git a/chrome/browser/extensions/extension_management.cc b/chrome/browser/extensions/extension_management.cc
index 87c0f9b..aecef847 100644
--- a/chrome/browser/extensions/extension_management.cc
+++ b/chrome/browser/extensions/extension_management.cc
@@ -9,7 +9,7 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/logging.h"
-#include "base/metrics/histogram_macros.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/stl_util.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_split.h"
@@ -332,6 +332,15 @@
   return default_settings_->blocked_install_message;
 }
 
+ExtensionIdSet ExtensionManagement::GetForcePinnedList() const {
+  ExtensionIdSet force_pinned_list;
+  for (const auto& entry : settings_by_id_) {
+    if (entry.second->toolbar_pin == ToolbarPinMode::kForcePinned)
+      force_pinned_list.insert(entry.first);
+  }
+  return force_pinned_list;
+}
+
 bool ExtensionManagement::CheckMinimumVersion(
     const Extension* extension,
     std::string* required_version) const {
@@ -529,6 +538,11 @@
         }
       }
     }
+    size_t force_pinned_count = GetForcePinnedList().size();
+    if (force_pinned_count > 0) {
+      base::UmaHistogramCounts100("Extensions.ForceToolbarPinnedCount",
+                                  force_pinned_count);
+    }
   }
 }
 
diff --git a/chrome/browser/extensions/extension_management.h b/chrome/browser/extensions/extension_management.h
index 53e7ae90..8bd180cf 100644
--- a/chrome/browser/extensions/extension_management.h
+++ b/chrome/browser/extensions/extension_management.h
@@ -75,6 +75,18 @@
     INSTALLATION_REMOVED,
   };
 
+  // Behavior for "Pin extension to toolbar" from the extensions menu, default
+  // is kDefaultUnpinned
+  // * kDefaultUnpinned: Extension starts unpinned, but the user can still pin
+  //                     it afterwards.
+  // * kForcePinned: Extension starts pinned to the toolbar, and the user
+  //                 cannot unpin it.
+  // TODO(crbug.com/1071314): Add kDefaultPinned state.
+  enum class ToolbarPinMode {
+    kDefaultUnpinned = 0,
+    kForcePinned,
+  };
+
   explicit ExtensionManagement(Profile* profile);
   ~ExtensionManagement() override;
 
@@ -194,6 +206,10 @@
   bool CheckMinimumVersion(const Extension* extension,
                            std::string* required_version) const;
 
+  // Returns the list of extensions with "force_pinned" mode for the
+  // "toolbar_pin" setting.
+  ExtensionIdSet GetForcePinnedList() const;
+
   // Returns whether the profile associated with this instance is supervised.
   bool is_child() const { return is_child_; }
 
diff --git a/chrome/browser/extensions/extension_management_constants.cc b/chrome/browser/extensions/extension_management_constants.cc
index c8c73c1..9230b684 100644
--- a/chrome/browser/extensions/extension_management_constants.cc
+++ b/chrome/browser/extensions/extension_management_constants.cc
@@ -35,6 +35,10 @@
 
 const char kBlockedInstallMessage[] = "blocked_install_message";
 
+const char kToolbarPin[] = "toolbar_pin";
+const char kForcePinned[] = "force_pinned";
+const char kDefaultUnpinned[] = "default_unpinned";
+
 const AllowedTypesMapEntry kAllowedTypesMap[] = {
   { "extension",           Manifest::TYPE_EXTENSION },
   { "theme",               Manifest::TYPE_THEME },
diff --git a/chrome/browser/extensions/extension_management_constants.h b/chrome/browser/extensions/extension_management_constants.h
index cb8b081..8846a5c 100644
--- a/chrome/browser/extensions/extension_management_constants.h
+++ b/chrome/browser/extensions/extension_management_constants.h
@@ -38,6 +38,10 @@
 
 extern const char kUpdateUrlPrefix[];
 
+extern const char kToolbarPin[];
+extern const char kForcePinned[];
+extern const char kDefaultUnpinned[];
+
 // If the install of an extension is blocked this admin defined message is
 // appended to the error message displayed in the Chrome Webstore.
 extern const char kBlockedInstallMessage[];
diff --git a/chrome/browser/extensions/extension_management_internal.cc b/chrome/browser/extensions/extension_management_internal.cc
index 1dce3d0..a7de0533 100644
--- a/chrome/browser/extensions/extension_management_internal.cc
+++ b/chrome/browser/extensions/extension_management_internal.cc
@@ -184,6 +184,20 @@
     }
   }
 
+  std::string toolbar_pin_str;
+  if (dict->GetStringWithoutPathExpansion(schema_constants::kToolbarPin,
+                                          &toolbar_pin_str)) {
+    if (toolbar_pin_str == schema_constants::kDefaultUnpinned) {
+      toolbar_pin = ExtensionManagement::ToolbarPinMode::kDefaultUnpinned;
+    } else if (toolbar_pin_str == schema_constants::kForcePinned) {
+      toolbar_pin = ExtensionManagement::ToolbarPinMode::kForcePinned;
+    } else {
+      // Invalid value for 'toolbar_pin'.
+      LOG(WARNING) << kMalformedPreferenceWarning;
+      return false;
+    }
+  }
+
   return true;
 }
 
diff --git a/chrome/browser/extensions/extension_management_internal.h b/chrome/browser/extensions/extension_management_internal.h
index 55298a9b..c903ba7 100644
--- a/chrome/browser/extensions/extension_management_internal.h
+++ b/chrome/browser/extensions/extension_management_internal.h
@@ -134,6 +134,12 @@
   // exceptions etc. This string is limited to 1000 characters.
   std::string blocked_install_message;
 
+  // Allows admins to control whether the extension icon should be pinned to
+  // the toolbar next to the omnibar. If it is pinned, the icon is visible at
+  // all times.
+  ExtensionManagement::ToolbarPinMode toolbar_pin =
+      ExtensionManagement::ToolbarPinMode::kDefaultUnpinned;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(IndividualSettings);
 };
diff --git a/chrome/browser/extensions/extension_service_test_base.cc b/chrome/browser/extensions/extension_service_test_base.cc
index 9df5dec..9cbef72 100644
--- a/chrome/browser/extensions/extension_service_test_base.cc
+++ b/chrome/browser/extensions/extension_service_test_base.cc
@@ -26,6 +26,7 @@
 #include "chrome/browser/extensions/shared_module_service.h"
 #include "chrome/browser/extensions/test_extension_system.h"
 #include "chrome/browser/extensions/updater/extension_updater.h"
+#include "chrome/browser/policy/chrome_browser_policy_connector.h"
 #include "chrome/browser/prefs/browser_prefs.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
@@ -35,6 +36,7 @@
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/crx_file/crx_verifier.h"
+#include "components/policy/core/common/policy_service_impl.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/sync_preferences/pref_service_mock_factory.h"
 #include "components/sync_preferences/pref_service_syncable.h"
@@ -61,13 +63,18 @@
 std::unique_ptr<TestingProfile> BuildTestingProfile(
     const ExtensionServiceTestBase::ExtensionServiceInitParams& params) {
   TestingProfile::Builder profile_builder;
-  // Create a PrefService that only contains user defined preference values.
+  // Create a PrefService that only contains user defined preference values and
+  // policies.
   sync_preferences::PrefServiceMockFactory factory;
   // If pref_file is empty, TestingProfile automatically creates
   // sync_preferences::TestingPrefServiceSyncable instance.
   if (!params.pref_file.empty()) {
     factory.SetUserPrefsFile(params.pref_file,
                              base::ThreadTaskRunnerHandle::Get().get());
+    if (params.policy_service) {
+      factory.SetManagedPolicies(params.policy_service,
+                                 g_browser_process->browser_policy_connector());
+    }
     scoped_refptr<user_prefs::PrefRegistrySyncable> registry(
         new user_prefs::PrefRegistrySyncable);
     std::unique_ptr<sync_preferences::PrefServiceSyncable> prefs(
@@ -128,6 +135,9 @@
     return;
   }
   data_dir_ = test_data_dir.AppendASCII("extensions");
+
+  policy_service_ = std::make_unique<policy::PolicyServiceImpl>(
+      std::vector<policy::ConfigurationPolicyProvider*>{&policy_provider_});
 }
 
 ExtensionServiceTestBase::~ExtensionServiceTestBase() {
@@ -156,6 +166,8 @@
   params.profile_path = path;
   params.pref_file = prefs_filename;
   params.extensions_install_dir = extensions_install_dir;
+
+  params.policy_service = policy_service_.get();
   return params;
 }
 
@@ -328,6 +340,7 @@
     if (partition)
       partition->WaitForDeletionTasksForTesting();
   }
+  policy_provider_.Shutdown();
 }
 
 void ExtensionServiceTestBase::SetUpTestCase() {
diff --git a/chrome/browser/extensions/extension_service_test_base.h b/chrome/browser/extensions/extension_service_test_base.h
index a966f10..b6399b2 100644
--- a/chrome/browser/extensions/extension_service_test_base.h
+++ b/chrome/browser/extensions/extension_service_test_base.h
@@ -16,6 +16,9 @@
 #include "base/macros.h"
 #include "build/build_config.h"
 #include "chrome/test/base/scoped_testing_local_state.h"
+#include "components/policy/core/common/mock_configuration_policy_provider.h"
+#include "components/policy/core/common/policy_service.h"
+#include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_renderer_host.h"
 #include "content/public/test/test_utils.h"
 #include "extensions/browser/sandboxed_unpacker.h"
@@ -62,6 +65,8 @@
     bool profile_is_supervised = false;
     bool enable_bookmark_model = false;
 
+    policy::PolicyService* policy_service = nullptr;
+
     // Though you could use this constructor, you probably want to use
     // CreateDefaultInitParams(), and then make a change or two.
     ExtensionServiceInitParams();
@@ -141,6 +146,9 @@
   content::BrowserTaskEnvironment* task_environment() {
     return task_environment_.get();
   }
+  policy::MockConfigurationPolicyProvider* policy_provider() {
+    return &policy_provider_;
+  }
 
  private:
   // Must be declared before anything that may make use of the
@@ -158,6 +166,14 @@
   // Enable creation of WebContents without initializing a renderer.
   content::RenderViewHostTestEnabler rvh_test_enabler_;
 
+  // Provides policies for the PolicyService below, so this must be created
+  // before it.
+  policy::MockConfigurationPolicyProvider policy_provider_;
+
+  // PolicyService for the testing profile, so unit tests can use custom
+  // policies.
+  std::unique_ptr<policy::PolicyService> policy_service_;
+
  protected:
   // It's unfortunate that these are exposed to subclasses (rather than used
   // through the accessor methods above), but too many tests already use them
diff --git a/chrome/browser/extensions/extension_unload_browsertest.cc b/chrome/browser/extensions/extension_unload_browsertest.cc
index 5723224..177c390 100644
--- a/chrome/browser/extensions/extension_unload_browsertest.cc
+++ b/chrome/browser/extensions/extension_unload_browsertest.cc
@@ -191,13 +191,7 @@
   EXPECT_EQ(1, browser()->tab_strip_model()->count());
 }
 
-// Flaky timeouts on Win7 Tests (dbg)(1); see https://crbug.com/985255.
-#if defined(OS_WIN) && !defined(NDEBUG)
-#define MAYBE_CrashedTabs DISABLED_CrashedTabs
-#else
-#define MAYBE_CrashedTabs CrashedTabs
-#endif
-IN_PROC_BROWSER_TEST_F(ExtensionUnloadBrowserTest, MAYBE_CrashedTabs) {
+IN_PROC_BROWSER_TEST_F(ExtensionUnloadBrowserTest, CrashedTabs) {
   TestExtensionDir test_dir;
   test_dir.WriteManifest(
       R"({
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index ef69305..7a86afd 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -108,11 +108,6 @@
     "expiry_milestone": 89
   },
   {
-    "name": "android-files-in-files-app",
-    "owners": [ "fukino" ],
-    "expiry_milestone": 76
-  },
-  {
     "name": "android-managed-by-menu-item",
     "owners": [ "gangwu@google.com", "twellington" ],
     "expiry_milestone": 90
@@ -649,7 +644,7 @@
   {
     "name": "cookies-without-same-site-must-be-secure",
     "owners": [ "chlily", "morlovich" ],
-    "expiry_milestone": 88
+    "expiry_milestone": 90
   },
   {
     "name": "copy-link-to-text",
@@ -985,7 +980,7 @@
   {
     "name": "dns-httpssvc",
     "owners": [ "dmcardle", "ericorth" ],
-    "expiry_milestone": 88
+    "expiry_milestone": 91
   },
   {
     "name": "dns-over-https",
@@ -1533,7 +1528,7 @@
   {
     "name": "enable-experimental-kernel-vm-support",
     "owners": [ "zwisler" ],
-    "expiry_milestone": 87
+    "expiry_milestone": 95
   },
   {
     "name": "enable-experimental-productivity-features",
@@ -2598,7 +2593,7 @@
   {
     "name": "fill-on-account-select",
     "owners": [ "jdoerrie" ],
-    "expiry_milestone": 87
+    "expiry_milestone": 90
   },
   {
     "name": "filling-passwords-from-any-origin",
@@ -3723,7 +3718,7 @@
   {
     "name": "password-check",
     "owners": [ "jdoerrie", "vasilii" ],
-    "expiry_milestone": 87
+    "expiry_milestone": 90
   },
   {
     "name": "password-scripts-fetching",
@@ -4132,7 +4127,7 @@
   {
     "name": "same-site-by-default-cookies",
     "owners": [ "chlily", "morlovich" ],
-    "expiry_milestone": 88
+    "expiry_milestone": 90
   },
   {
     "name": "scanning-ui",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 9f77244..cd51cb8 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -2104,11 +2104,6 @@
     "Shows previews of the open windows for a given running app when hovering "
     "over the shelf.";
 
-const char kShowAndroidFilesInFilesAppName[] =
-    "Show Android files in Files app";
-const char kShowAndroidFilesInFilesAppDescription[] =
-    "Show Android files in Files app if Android is enabled on the device.";
-
 const char kShowAutofillSignaturesName[] = "Show autofill signatures.";
 const char kShowAutofillSignaturesDescription[] =
     "Annotates web forms with Autofill signatures as HTML attributes. Also "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index b800318..10de50c 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1217,9 +1217,6 @@
 extern const char kShelfHoverPreviewsName[];
 extern const char kShelfHoverPreviewsDescription[];
 
-extern const char kShowAndroidFilesInFilesAppName[];
-extern const char kShowAndroidFilesInFilesAppDescription[];
-
 extern const char kShowAutofillSignaturesName[];
 extern const char kShowAutofillSignaturesDescription[];
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index dcb36ee..fb73178f 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -13,6 +13,7 @@
 #include "base/metrics/field_trial_params.h"
 #include "base/stl_util.h"
 #include "chrome/browser/flags/jni_headers/ChromeFeatureList_jni.h"
+#include "chrome/browser/notifications/chime/android/features.h"
 #include "chrome/browser/performance_hints/performance_hints_features.h"
 #include "chrome/browser/share/features.h"
 #include "chrome/browser/sharing/shared_clipboard/feature_flags.h"
@@ -225,6 +226,7 @@
     &features::kDnsOverHttps,
     &net::features::kSameSiteByDefaultCookies,
     &net::features::kCookiesWithoutSameSiteMustBeSecure,
+    &notifications::features::kUseChimeAndroidSdk,
     &paint_preview::kPaintPreviewDemo,
     &paint_preview::kPaintPreviewShowOnStartup,
     &language::kDetailedLanguageSettings,
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java
index dcdc96e..9bcbcdb 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java
@@ -79,6 +79,7 @@
             put(ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_ICONS, false);
             put(ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_REGROUP, false);
             put(ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_THREE_BUTTON_ACTIONBAR, false);
+            put(ChromeFeatureList.USE_CHIME_ANDROID_SDK, false);
         }
     };
 
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index 9f49dcac..5c3ae14 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -444,6 +444,7 @@
     public static final String UPDATE_NOTIFICATION_IMMEDIATE_SHOW_OPTION =
             "UpdateNotificationScheduleServiceImmediateShowOption";
     public static final String USAGE_STATS = "UsageStats";
+    public static final String USE_CHIME_ANDROID_SDK = "UseChimeAndroidSdk";
     public static final String VR_BROWSING_FEEDBACK = "VrBrowsingFeedback";
     public static final String WEBAPK_ADAPTIVE_ICON = "WebApkAdaptiveIcon";
     public static final String WEB_AUTH = "WebAuthentication";
diff --git a/chrome/browser/metrics/metrics_service_browsertest.cc b/chrome/browser/metrics/metrics_service_browsertest.cc
index 671a51c..4e3572f8 100644
--- a/chrome/browser/metrics/metrics_service_browsertest.cc
+++ b/chrome/browser/metrics/metrics_service_browsertest.cc
@@ -167,9 +167,7 @@
 // Flaky on Linux. See http://crbug.com/131094
 // Child crashes fail the process on ASan (see crbug.com/411251,
 // crbug.com/368525).
-// Flaky timeouts on Win7 Tests (dbg)(1); see https://crbug.com/985255.
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(ADDRESS_SANITIZER) || \
-    (defined(OS_WIN) && !defined(NDEBUG))
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(ADDRESS_SANITIZER)
 #define MAYBE_CrashRenderers DISABLED_CrashRenderers
 #define MAYBE_CheckCrashRenderers DISABLED_CheckCrashRenderers
 #else
diff --git a/chrome/browser/nearby_sharing/proto/rpc_resources.proto b/chrome/browser/nearby_sharing/proto/rpc_resources.proto
index da6622fe..e85e70e 100644
--- a/chrome/browser/nearby_sharing/proto/rpc_resources.proto
+++ b/chrome/browser/nearby_sharing/proto/rpc_resources.proto
@@ -80,8 +80,20 @@
 }
 
 // A contact record from People backend.
-// NextId=5
+// NextId=6
 message ContactRecord {
+  // The type of the ContactRecord.
+  enum Type {
+    // The source of the contact is unknown.
+    UNKNOWN = 0;
+
+    // The source of the contact is from google (i.e. google.com/contacts).
+    GOOGLE_CONTACT = 1;
+
+    // The source of the contact is from a device.
+    DEVICE_CONTACT = 2;
+  }
+
   // The stable id of this contact record.
   string id = 1;
 
@@ -94,6 +106,9 @@
 
   // A list of phone numbers and emails under this contact record.
   repeated Contact.Identifier identifiers = 4;
+
+  // The type of the ContactRecord.
+  Type type = 5;
 }
 
 // A ShareTarget is a potential destination of a share.
diff --git a/chrome/browser/net/profile_network_context_service.cc b/chrome/browser/net/profile_network_context_service.cc
index 9ec42e7..8174cfc 100644
--- a/chrome/browser/net/profile_network_context_service.cc
+++ b/chrome/browser/net/profile_network_context_service.cc
@@ -159,6 +159,10 @@
            type == net::AmbientAuthAllowedProfileTypes::ALL;
   }
 
+  // System profile does not need ambient authentication.
+  if (profile->GetOriginalProfile()->IsSystemProfile())
+    return false;
+
   // Profile type not yet supported.
   NOTREACHED();
 
diff --git a/chrome/browser/net/reporting_browsertest.cc b/chrome/browser/net/reporting_browsertest.cc
index e5e6223..5fa0a63 100644
--- a/chrome/browser/net/reporting_browsertest.cc
+++ b/chrome/browser/net/reporting_browsertest.cc
@@ -251,8 +251,7 @@
 }
 
 // These tests intentionally crash a render process, and so fail ASan tests.
-// Flaky timeouts on Win7 Tests (dbg)(1); see https://crbug.com/985255.
-#if defined(ADDRESS_SANITIZER) || (defined(OS_WIN) && !defined(NDEBUG))
+#if defined(ADDRESS_SANITIZER)
 #define MAYBE_CrashReport DISABLED_CrashReport
 #define MAYBE_CrashReportUnresponsive DISABLED_CrashReportUnresponsive
 #else
diff --git a/chrome/browser/notifications/chime/android/BUILD.gn b/chrome/browser/notifications/chime/android/BUILD.gn
index 4e47c14..c0223d68 100644
--- a/chrome/browser/notifications/chime/android/BUILD.gn
+++ b/chrome/browser/notifications/chime/android/BUILD.gn
@@ -5,15 +5,7 @@
 import("//build/config/android/rules.gni")
 
 android_library("java") {
-  sources = [ "java/src/org/chromium/chrome/browser/notifications/chime/ChimeSession.java" ]
-
-  annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
-
-  deps = [
-    "//base:base_java",
-    "//base:jni_java",
-    "//chrome/android/modules/chime/public:java",
-  ]
+  sources = [ "java/src/org/chromium/chrome/browser/notifications/chime/ChimeDelegate.java" ]
 }
 
 source_set("android") {
@@ -22,14 +14,5 @@
     "features.h",
   ]
 
-  deps = [
-    ":jni_headers",
-    "//base",
-  ]
-}
-
-generate_jni("jni_headers") {
-  visibility = [ ":*" ]
-
-  sources = [ "java/src/org/chromium/chrome/browser/notifications/chime/ChimeSession.java" ]
+  deps = [ "//base" ]
 }
diff --git a/chrome/browser/notifications/chime/android/features.cc b/chrome/browser/notifications/chime/android/features.cc
index 91a0e86..afb0c10 100644
--- a/chrome/browser/notifications/chime/android/features.cc
+++ b/chrome/browser/notifications/chime/android/features.cc
@@ -3,12 +3,6 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/notifications/chime/android/features.h"
-#include "chrome/browser/notifications/chime/android/jni_headers/ChimeSession_jni.h"
-
-jboolean JNI_ChimeSession_IsEnabled(JNIEnv* env) {
-  return base::FeatureList::IsEnabled(
-      notifications::features::kUseChimeAndroidSdk);
-}
 
 namespace notifications {
 namespace features {
diff --git a/chrome/browser/notifications/chime/android/java/src/org/chromium/chrome/browser/notifications/chime/ChimeDelegate.java b/chrome/browser/notifications/chime/android/java/src/org/chromium/chrome/browser/notifications/chime/ChimeDelegate.java
new file mode 100644
index 0000000..8ec5b47
--- /dev/null
+++ b/chrome/browser/notifications/chime/android/java/src/org/chromium/chrome/browser/notifications/chime/ChimeDelegate.java
@@ -0,0 +1,15 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.notifications.chime;
+
+/**
+ * Chime interface.
+ */
+public interface ChimeDelegate {
+    /*
+     * Start a chime session.
+     */
+    public default void startSession() {}
+}
diff --git a/chrome/browser/notifications/chime/android/java/src/org/chromium/chrome/browser/notifications/chime/ChimeSession.java b/chrome/browser/notifications/chime/android/java/src/org/chromium/chrome/browser/notifications/chime/ChimeSession.java
deleted file mode 100644
index 87bb5418..0000000
--- a/chrome/browser/notifications/chime/android/java/src/org/chromium/chrome/browser/notifications/chime/ChimeSession.java
+++ /dev/null
@@ -1,48 +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.
-
-package org.chromium.chrome.browser.notifications.chime;
-
-import org.chromium.base.annotations.NativeMethods;
-import org.chromium.chrome.modules.chime.ChimeModule;
-
-/**
- * Used to register to Chime notification platform.
- */
-public class ChimeSession {
-    private static boolean sRegistered;
-
-    /**
-     * Registers to Chime and start to receive notifications.
-     */
-    public static void start() {
-        // TODO(xingliu): Find a better way to access feature in Java code.
-        // https://crbug.com/1017860.
-        if (!ChimeSessionJni.get().isEnabled() || sRegistered) return;
-
-        // Install the DFM and then reigster.
-        if (ChimeModule.isInstalled()) {
-            registerChimeInternal();
-            return;
-        }
-
-        ChimeModule.install((success) -> {
-            if (success) registerChimeInternal();
-        });
-    }
-
-    private static void registerChimeInternal() {
-        assert (ChimeModule.isInstalled());
-        sRegistered = true;
-        ChimeModule.getImpl().register();
-    }
-
-    @NativeMethods
-    interface Natives {
-        /**
-         * @return Whether Chime is enabled.
-         */
-        boolean isEnabled();
-    }
-}
diff --git a/chrome/browser/notifications/notification_platform_bridge_mac.mm b/chrome/browser/notifications/notification_platform_bridge_mac.mm
index dd2f51a..818a5596 100644
--- a/chrome/browser/notifications/notification_platform_bridge_mac.mm
+++ b/chrome/browser/notifications/notification_platform_bridge_mac.mm
@@ -457,7 +457,7 @@
         crash_reporter::GetCrashpadClient().GetHandlerMachPort());
     base::scoped_nsobject<CrXPCMachPort> xpcPort(
         [[CrXPCMachPort alloc] initWithMachSendRight:std::move(exceptionPort)]);
-    [proxy setMachExceptionPort:xpcPort];
+    [proxy setUseUNNotification:NO machExceptionPort:xpcPort];
     _setExceptionPort = YES;
   }
 
diff --git a/chrome/browser/password_manager/android/password_accessory_controller_impl.cc b/chrome/browser/password_manager/android/password_accessory_controller_impl.cc
index ef6682e4..ab1f2538 100644
--- a/chrome/browser/password_manager/android/password_accessory_controller_impl.cc
+++ b/chrome/browser/password_manager/android/password_accessory_controller_impl.cc
@@ -25,6 +25,7 @@
 #include "chrome/browser/password_manager/android/password_manager_launcher_android.h"
 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ssl/security_state_tab_helper.h"
 #include "chrome/browser/ui/passwords/manage_passwords_view_utils.h"
 #include "chrome/browser/vr/vr_tab_helper.h"
 #include "chrome/grit/generated_resources.h"
@@ -271,10 +272,9 @@
     }
   }
 
-  if (origin.GetURL().SchemeIsCryptographic() &&
+  if (IsSecureSite() && origin.GetURL().SchemeIsCryptographic() &&
       base::FeatureList::IsEnabled(
           password_manager::features::kFillingPasswordsFromAnyOrigin)) {
-    // TODO(crbug.com/1104132): Disable the feature in insecure websites.
     base::string16 button_title =
         is_password_field
             ? l10n_util::GetStringUTF16(
@@ -441,4 +441,16 @@
   all_passords_bottom_sheet_controller_.reset();
 }
 
+bool PasswordAccessoryControllerImpl::IsSecureSite() {
+  if (security_level_for_testing_) {
+    return security_level_for_testing_ == security_state::SECURE;
+  }
+
+  SecurityStateTabHelper::CreateForWebContents(web_contents_);
+  SecurityStateTabHelper* helper =
+      SecurityStateTabHelper::FromWebContents(web_contents_);
+
+  return helper && helper->GetSecurityLevel() == security_state::SECURE;
+}
+
 WEB_CONTENTS_USER_DATA_KEY_IMPL(PasswordAccessoryControllerImpl)
diff --git a/chrome/browser/password_manager/android/password_accessory_controller_impl.h b/chrome/browser/password_manager/android/password_accessory_controller_impl.h
index 7c234b8..8b9aca7a 100644
--- a/chrome/browser/password_manager/android/password_accessory_controller_impl.h
+++ b/chrome/browser/password_manager/android/password_accessory_controller_impl.h
@@ -20,6 +20,7 @@
 #include "components/autofill/core/common/password_generation_util.h"
 #include "components/password_manager/core/browser/credential_cache.h"
 #include "components/password_manager/core/browser/password_manager_client.h"
+#include "components/security_state/core/security_state.h"
 #include "content/public/browser/web_contents_user_data.h"
 #include "url/gurl.h"
 
@@ -79,6 +80,18 @@
       password_manager::ContentPasswordManagerDriver* driver,
       autofill::mojom::FocusedFieldType focused_field_type);
 
+  // Returns true if the current site attached to `web_contents_` has a SECURE
+  // security level.
+  bool IsSecureSite();
+
+#if defined(UNIT_TEST)
+  // Used for testing to set `security_level_for_testing_`.
+  void SetSecurityLevelForTesting(
+      security_state::SecurityLevel security_level) {
+    security_level_for_testing_ = security_level;
+  }
+#endif
+
  private:
   friend class content::WebContentsUserData<PasswordAccessoryControllerImpl>;
 
@@ -144,6 +157,10 @@
   // called with.
   autofill::mojom::FocusedFieldType last_focused_field_type_;
 
+  // Security level used for testing only.
+  security_state::SecurityLevel security_level_for_testing_ =
+      security_state::NONE;
+
   WEB_CONTENTS_USER_DATA_KEY_DECL();
 
   DISALLOW_COPY_AND_ASSIGN(PasswordAccessoryControllerImpl);
diff --git a/chrome/browser/password_manager/android/password_accessory_controller_impl_unittest.cc b/chrome/browser/password_manager/android/password_accessory_controller_impl_unittest.cc
index 21d8816..f04046b 100644
--- a/chrome/browser/password_manager/android/password_accessory_controller_impl_unittest.cc
+++ b/chrome/browser/password_manager/android/password_accessory_controller_impl_unittest.cc
@@ -34,6 +34,7 @@
 #include "components/password_manager/core/browser/stub_password_manager_client.h"
 #include "components/password_manager/core/browser/stub_password_manager_driver.h"
 #include "components/password_manager/core/common/password_manager_features.h"
+#include "components/security_state/core/security_state.h"
 #include "components/strings/grit/components_strings.h"
 #include "content/public/test/web_contents_tester.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -203,7 +204,7 @@
 
   void TearDown() override { mock_password_store_->ShutdownOnUIThread(); }
 
-  PasswordAccessoryController* controller() {
+  PasswordAccessoryControllerImpl* controller() {
     return PasswordAccessoryControllerImpl::FromWebContents(web_contents());
   }
 
@@ -639,6 +640,7 @@
 }
 
 TEST_F(PasswordAccessoryControllerTest, AddsShowOtherPasswordsIfEnabled) {
+  controller()->SetSecurityLevelForTesting(security_state::SECURE);
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(
       password_manager::features::kFillingPasswordsFromAnyOrigin);
@@ -658,6 +660,7 @@
 }
 
 TEST_F(PasswordAccessoryControllerTest, AddsShowOtherUsername) {
+  controller()->SetSecurityLevelForTesting(security_state::SECURE);
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(
       password_manager::features::kFillingPasswordsFromAnyOrigin);
@@ -677,7 +680,8 @@
 }
 
 TEST_F(PasswordAccessoryControllerTest,
-       AddsShowOtherPasswordForOnlySecuredSites) {
+       AddsShowOtherPasswordForOnlyCryptographicSchemeSites) {
+  controller()->SetSecurityLevelForTesting(security_state::SECURE);
   // `Setup` method sets the URL to https but http is required for this method.
   NavigateAndCommit(GURL(kExampleHttpSite));
   FocusWebContentsOnMainFrame();
@@ -698,6 +702,7 @@
 }
 
 TEST_F(PasswordAccessoryControllerTest, HidesShowOtherPasswordsIfDisabled) {
+  controller()->SetSecurityLevelForTesting(security_state::SECURE);
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndDisableFeature(
       password_manager::features::kFillingPasswordsFromAnyOrigin);
@@ -714,6 +719,24 @@
 }
 
 TEST_F(PasswordAccessoryControllerTest,
+       HideShowOtherPasswordForLowSecurityLevelSites) {
+  controller()->SetSecurityLevelForTesting(security_state::WARNING);
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(
+      password_manager::features::kFillingPasswordsFromAnyOrigin);
+  AccessorySheetData::Builder data_builder(AccessoryTabType::PASSWORDS,
+                                           passwords_empty_str(kExampleDomain));
+  data_builder.AppendFooterCommand(manage_passwords_str(),
+                                   autofill::AccessoryAction::MANAGE_PASSWORDS);
+  EXPECT_CALL(mock_manual_filling_controller_,
+              RefreshSuggestions(std::move(data_builder).Build()));
+
+  controller()->RefreshSuggestionsForField(
+      FocusedFieldType::kFillablePasswordField,
+      /*is_manual_generation_available=*/false);
+}
+
+TEST_F(PasswordAccessoryControllerTest,
        NoSaveToggleIfIsBlacklistedAndSavingDisabled) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitWithFeatures(
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc
index 181a75f3..62da373 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -107,7 +107,7 @@
 #include "chrome/browser/safe_browsing/advanced_protection_status_manager_factory.h"
 #include "third_party/blink/public/mojom/clipboard/clipboard.mojom.h"
 #include "ui/base/clipboard/clipboard.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 #include "ui/events/keycodes/keyboard_codes.h"
 #endif
 
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index 0769ba8..5f1feb31 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -277,12 +277,6 @@
   { key::kInsecurePrivateNetworkRequestsAllowedForUrls,
     prefs::kManagedInsecurePrivateNetworkAllowedForUrls,
     base::Value::Type::LIST },
-  { key::kPluginsAllowedForUrls,
-    prefs::kManagedPluginsAllowedForUrls,
-    base::Value::Type::LIST },
-  { key::kPluginsBlockedForUrls,
-    prefs::kManagedPluginsBlockedForUrls,
-    base::Value::Type::LIST },
   { key::kPopupsAllowedForUrls,
     prefs::kManagedPopupsAllowedForUrls,
     base::Value::Type::LIST },
@@ -370,9 +364,6 @@
   { key::kTranslateEnabled,
     prefs::kOfferTranslateEnabled,
     base::Value::Type::BOOLEAN },
-  { key::kAllowOutdatedPlugins,
-    prefs::kPluginsAllowOutdated,
-    base::Value::Type::BOOLEAN },
   { key::kRunAllFlashInAllowMode,
     prefs::kRunAllFlashInAllowMode,
     base::Value::Type::BOOLEAN },
diff --git a/chrome/browser/policy/content_settings_policy_browsertest.cc b/chrome/browser/policy/content_settings_policy_browsertest.cc
index c9d158f..f834eaa 100644
--- a/chrome/browser/policy/content_settings_policy_browsertest.cc
+++ b/chrome/browser/policy/content_settings_policy_browsertest.cc
@@ -325,49 +325,6 @@
   base::test::ScopedFeatureList scoped_feature_list_;
 };
 
-IN_PROC_BROWSER_TEST_F(DisallowWildcardPolicyTest, PluginTest) {
-  PolicyMap policies;
-  base::Value policy_value(base::Value::Type::LIST);
-  policy_value.Append("[*.]google.com");
-  policy_value.Append("http://drive.google.com:443/home");
-  policy_value.Append("www.foo.com:*/*");
-  policy_value.Append("*://[*.]bar.com:*/*");
-  SetPolicy(&policies, key::kPluginsAllowedForUrls, std::move(policy_value));
-  UpdateProviderPolicy(policies);
-
-  constexpr char kGoogleMailUrl[] = "http://mail.google.com:443";
-  constexpr char kGoogleDriveUrl[] = "http://drive.google.com:443";
-  constexpr char kFooUrl[] = "https://www.foo.com:443/home";
-  constexpr char kBarUrl[] = "https://foobar.com:443/";
-
-  permissions::PermissionManager* permission_manager =
-      PermissionManagerFactory::GetForProfile(browser()->profile());
-  EXPECT_EQ(
-      permission_manager
-          ->GetPermissionStatus(ContentSettingsType::PLUGINS,
-                                GURL(kGoogleMailUrl), GURL(kGoogleMailUrl))
-          .content_setting,
-      ContentSetting::CONTENT_SETTING_BLOCK);
-
-  EXPECT_EQ(
-      permission_manager
-          ->GetPermissionStatus(ContentSettingsType::PLUGINS,
-                                GURL(kGoogleDriveUrl), GURL(kGoogleDriveUrl))
-          .content_setting,
-      ContentSetting::CONTENT_SETTING_ALLOW);
-
-  EXPECT_EQ(permission_manager
-                ->GetPermissionStatus(ContentSettingsType::PLUGINS,
-                                      GURL(kFooUrl), GURL(kFooUrl))
-                .content_setting,
-            ContentSetting::CONTENT_SETTING_ALLOW);
-
-  EXPECT_EQ(permission_manager
-                ->GetPermissionStatus(ContentSettingsType::PLUGINS,
-                                      GURL(kBarUrl), GURL(kBarUrl))
-                .content_setting,
-            ContentSetting::CONTENT_SETTING_BLOCK);
-}
 
 class ScrollToTextFragmentPolicyTest
     : public PolicyTest,
diff --git a/chrome/browser/prefetch/prefetch_browsertest.cc b/chrome/browser/prefetch/prefetch_browsertest.cc
index 42c36f6..cb34265fa 100644
--- a/chrome/browser/prefetch/prefetch_browsertest.cc
+++ b/chrome/browser/prefetch/prefetch_browsertest.cc
@@ -134,7 +134,7 @@
 IN_PROC_BROWSER_TEST_F(PrefetchBrowserTest, IncognitoTest) {
   Profile* incognito_profile = browser()->profile()->GetPrimaryOTRProfile();
   Browser* incognito_browser =
-      new Browser(Browser::CreateParams(incognito_profile, true));
+      Browser::Create(Browser::CreateParams(incognito_profile, true));
 
   // Navigate just to have a tab in this window, otherwise there is no
   // WebContents for the incognito browser.
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 74a96b4d..bd71627 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -235,9 +235,8 @@
 #include "chrome/browser/nearby_sharing/common/nearby_share_prefs.h"
 #include "chrome/browser/search/instant_service.h"
 #include "chrome/browser/search/promos/promo_service.h"
-#include "chrome/browser/search/recipe_tasks/recipe_tasks_service.h"
 #include "chrome/browser/search/search_suggest/search_suggest_service.h"
-#include "chrome/browser/search/shopping_tasks/shopping_tasks_service.h"
+#include "chrome/browser/search/task_module/task_module_service.h"
 #include "chrome/browser/signin/signin_promo.h"
 #include "chrome/browser/ui/startup/startup_browser_creator.h"
 #include "chrome/browser/ui/webui/history/foreign_session_handler.h"
@@ -902,14 +901,13 @@
   ntp_tiles::CustomLinksManagerImpl::RegisterProfilePrefs(registry);
   PinnedTabCodec::RegisterProfilePrefs(registry);
   PromoService::RegisterProfilePrefs(registry);
-  RecipeTasksService::RegisterProfilePrefs(registry);
   SearchSuggestService::RegisterProfilePrefs(registry);
   settings::SettingsUI::RegisterProfilePrefs(registry);
   send_tab_to_self::SendTabToSelfBubbleController::RegisterProfilePrefs(
       registry);
-  ShoppingTasksService::RegisterProfilePrefs(registry);
   signin::RegisterProfilePrefs(registry);
   StartupBrowserCreator::RegisterProfilePrefs(registry);
+  TaskModuleService::RegisterProfilePrefs(registry);
   UnifiedAutoplayConfig::RegisterProfilePrefs(registry);
 #endif  // defined(OS_ANDROID)
 
diff --git a/chrome/browser/prefs/chrome_command_line_pref_store.cc b/chrome/browser/prefs/chrome_command_line_pref_store.cc
index 7559f8c..a3ad13a 100644
--- a/chrome/browser/prefs/chrome_command_line_pref_store.cc
+++ b/chrome/browser/prefs/chrome_command_line_pref_store.cc
@@ -67,7 +67,6 @@
         {switches::kDisable3DAPIs, prefs::kDisable3DAPIs, true},
         {switches::kEnableCloudPrintProxy, prefs::kCloudPrintProxyEnabled,
          true},
-        {switches::kAllowOutdatedPlugins, prefs::kPluginsAllowOutdated, true},
         {switches::kNoPings, prefs::kEnableHyperlinkAuditing, false},
         {switches::kAllowRunningInsecureContent,
          prefs::kWebKitAllowRunningInsecureContent, true},
diff --git a/chrome/browser/prerender/prerender_nostate_prefetch_browsertest.cc b/chrome/browser/prerender/prerender_nostate_prefetch_browsertest.cc
index 8758790..1aa3922f 100644
--- a/chrome/browser/prerender/prerender_nostate_prefetch_browsertest.cc
+++ b/chrome/browser/prerender/prerender_nostate_prefetch_browsertest.cc
@@ -1369,13 +1369,7 @@
   WaitForRequestCount(src_server()->GetURL(kPrefetchScript), 1);
 }
 
-// Flaky timeouts on Win7 Tests; see https://crbug.com/985255.
-#if defined(OS_WIN)
-#define MAYBE_RendererCrash DISABLED_RendererCrash
-#else
-#define MAYBE_RendererCrash RendererCrash
-#endif
-IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, MAYBE_RendererCrash) {
+IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, RendererCrash) {
   // Navigate to about:blank to get the session storage namespace.
   ui_test_utils::NavigateToURL(current_browser(), GURL(url::kAboutBlankURL));
   content::SessionStorageNamespace* storage_namespace =
diff --git a/chrome/browser/printing/DEPS b/chrome/browser/printing/DEPS
index f5a9247..e1f1f2b 100644
--- a/chrome/browser/printing/DEPS
+++ b/chrome/browser/printing/DEPS
@@ -1,3 +1,9 @@
 include_rules = [
   "+pdf/pdf.h",  # Test only.
 ]
+
+specific_include_rules = {
+  "print_backend_browsertest.cc": [
+    "+chrome/services/printing/print_backend_service_impl.h",
+  ]
+}
diff --git a/chrome/browser/printing/print_backend_browsertest.cc b/chrome/browser/printing/print_backend_browsertest.cc
new file mode 100644
index 0000000..c8a95046
--- /dev/null
+++ b/chrome/browser/printing/print_backend_browsertest.cc
@@ -0,0 +1,149 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/check_op.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "base/run_loop.h"
+#include "chrome/services/printing/print_backend_service_impl.h"
+#include "chrome/services/printing/public/mojom/print_backend_service.mojom.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "content/public/test/browser_test.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "printing/backend/test_print_backend.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace printing {
+
+namespace {
+
+constexpr char kDefaultPrinterName[] = "default-test-printer";
+
+}  // namespace
+
+// PrintBackendServiceTestImpl uses a TestPrintBackend to enable testing of the
+// PrintBackendService without relying upon the presence of real printer
+// drivers.
+class PrintBackendServiceTestImpl : public PrintBackendServiceImpl {
+ public:
+  explicit PrintBackendServiceTestImpl(
+      mojo::PendingReceiver<mojom::PrintBackendService> receiver)
+      : PrintBackendServiceImpl(std::move(receiver)) {}
+  PrintBackendServiceTestImpl(const PrintBackendServiceTestImpl&) = delete;
+  PrintBackendServiceTestImpl& operator=(const PrintBackendServiceTestImpl&) =
+      delete;
+  ~PrintBackendServiceTestImpl() override = default;
+
+  // Overrides which need special handling for using `test_print_backend_`.
+  void Init(const std::string& locale) override {
+    test_print_backend_ = base::MakeRefCounted<TestPrintBackend>();
+    print_backend_ = test_print_backend_;
+  }
+
+ private:
+  friend class PrintBackendBrowserTest;
+
+  scoped_refptr<TestPrintBackend> test_print_backend_;
+};
+
+class PrintBackendBrowserTest : public InProcessBrowserTest {
+ public:
+  PrintBackendBrowserTest() = default;
+  ~PrintBackendBrowserTest() override = default;
+
+  void PreRunTestOnMainThread() override {
+    InProcessBrowserTest::PreRunTestOnMainThread();
+
+    // Launch the service, and bind the testing interface to it.
+    mojo::PendingReceiver<mojom::PrintBackendService> receiver =
+        mojo::PendingRemote<mojom::PrintBackendService>()
+            .InitWithNewPipeAndPassReceiver();
+    print_backend_service_ =
+        std::make_unique<PrintBackendServiceTestImpl>(std::move(receiver));
+  }
+
+  // Initialize and load the backend service with some test print drivers.
+  void DoInitAndSetupTestData() {
+    print_backend_service_->Init(/*locale=*/"");
+    print_backend_service_->test_print_backend_->SetDefaultPrinterName(
+        kDefaultPrinterName);
+  }
+
+  // Public callbacks used by tests.
+  void OnDidGetDefaultPrinterName(
+      base::Optional<std::string>* capture_printer_name,
+      const base::Optional<std::string>& printer_name) {
+    *capture_printer_name = printer_name;
+    CheckForQuit();
+  }
+
+  // The following are helper functions for having a wait loop in the test and
+  // exit when expected messages are received.
+  void WaitUntilCallbackReceived() {
+    if (received_message_) {
+      // Callback happened before even needing to wait.
+      return;
+    }
+
+    base::RunLoop run_loop;
+    quit_callback_ = run_loop.QuitClosure();
+    run_loop.Run();
+  }
+
+  void CheckForQuit() {
+    received_message_ = true;
+    if (quit_callback_)
+      std::move(quit_callback_).Run();
+  }
+
+  // Get the print backend service being tested.
+  mojom::PrintBackendService* GetPrintBackendService() const {
+    return print_backend_service_.get();
+  }
+
+ private:
+  bool received_message_ = false;
+  base::OnceClosure quit_callback_;
+
+  std::unique_ptr<PrintBackendServiceTestImpl> print_backend_service_;
+};
+
+// A print backend service requires initialization prior to being used for a
+// query/command.  Verify that a query fails if one tries to use a new service
+// without having performed initialization.
+IN_PROC_BROWSER_TEST_F(PrintBackendBrowserTest, FailWithoutInit) {
+  base::Optional<std::string> default_printer_name;
+
+  // Safe to use base::Unretained(this) since waiting locally on the callback
+  // forces a shorter lifetime than `this`.
+  GetPrintBackendService()->GetDefaultPrinterName(
+      base::BindOnce(&PrintBackendBrowserTest::OnDidGetDefaultPrinterName,
+                     base::Unretained(this), &default_printer_name));
+  WaitUntilCallbackReceived();
+  EXPECT_FALSE(default_printer_name.has_value());
+}
+
+IN_PROC_BROWSER_TEST_F(PrintBackendBrowserTest, GetDefaultPrinterName) {
+  base::Optional<std::string> default_printer_name;
+
+  DoInitAndSetupTestData();
+
+  // Safe to use base::Unretained(this) since waiting locally on the callback
+  // forces a shorter lifetime than `this`.
+  GetPrintBackendService()->GetDefaultPrinterName(
+      base::BindOnce(&PrintBackendBrowserTest::OnDidGetDefaultPrinterName,
+                     base::Unretained(this), &default_printer_name));
+  WaitUntilCallbackReceived();
+  ASSERT_TRUE(default_printer_name.has_value());
+  EXPECT_EQ(default_printer_name.value(), kDefaultPrinterName);
+}
+
+}  // namespace printing
diff --git a/chrome/browser/printing/print_backend_service.cc b/chrome/browser/printing/print_backend_service.cc
new file mode 100644
index 0000000..aad099d
--- /dev/null
+++ b/chrome/browser/printing/print_backend_service.cc
@@ -0,0 +1,76 @@
+// 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/printing/print_backend_service.h"
+
+#include <string>
+
+#include "base/containers/flat_map.h"
+#include "base/no_destructor.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "chrome/grit/generated_resources.h"
+#include "chrome/services/printing/public/mojom/print_backend_service.mojom.h"
+#include "content/public/browser/service_process_host.h"
+#include "mojo/public/cpp/bindings/remote.h"
+
+namespace {
+
+// Amount of idle time to wait before resetting the connection to the service.
+constexpr base::TimeDelta kResetOnIdleTimeout =
+    base::TimeDelta::FromSeconds(20);
+
+}  // namespace
+
+const mojo::Remote<printing::mojom::PrintBackendService>&
+GetPrintBackendService(const std::string& locale,
+                       const std::string& printer_name) {
+  static base::NoDestructor<base::flat_map<
+      std::string, mojo::Remote<printing::mojom::PrintBackendService>>>
+      remotes;
+  std::string remote_id;
+#if defined(OS_WIN)
+  // Windows drivers are not thread safe.  Use a process per driver to prevent
+  // bad interactions when interfacing to multiple drivers in parallel.
+  // https://crbug.com/957242
+  remote_id = printer_name;
+#endif
+  auto iter = remotes->find(remote_id);
+  if (iter == remotes->end()) {
+    // First time for this `remote_id`.
+    auto result = remotes->emplace(
+        printer_name, mojo::Remote<printing::mojom::PrintBackendService>());
+    iter = result.first;
+  }
+
+  mojo::Remote<printing::mojom::PrintBackendService>& service = iter->second;
+  if (!service) {
+    content::ServiceProcessHost::Launch(
+        service.BindNewPipeAndPassReceiver(),
+        content::ServiceProcessHost::Options()
+            .WithDisplayName(IDS_UTILITY_PROCESS_PRINT_BACKEND_SERVICE_NAME)
+            .Pass());
+
+    // Ensure that if the interface is ever disconnected (e.g. the service
+    // process crashes) or goes idle for a short period of time -- meaning
+    // there are no in-flight messages and no other interfaces bound through
+    // this one -- then we will reset `remote`, causing the service process to
+    // be terminated if it isn't already.
+    service.reset_on_disconnect();
+    // TODO(crbug.com/809738) Interactions with the service should be expected
+    // as long as any Print Preview dialogs are open (and there could be more
+    // than one preview open at a time).  Keeping the service present as long
+    // as those are open would help provide a more responsive experience for
+    // the user.  For now, to ensure that this process doesn't stick around
+    // forever we make it go away after a short delay of idleness, but that
+    // should be adjusted to happen only after all UI references have been
+    // removed.
+    service.reset_on_idle_timeout(kResetOnIdleTimeout);
+
+    // Initialize the new service for the desired locale.
+    service->Init(locale);
+  }
+
+  return service;
+}
diff --git a/chrome/browser/printing/print_backend_service.h b/chrome/browser/printing/print_backend_service.h
new file mode 100644
index 0000000..6887c44
--- /dev/null
+++ b/chrome/browser/printing/print_backend_service.h
@@ -0,0 +1,19 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_PRINTING_PRINT_BACKEND_SERVICE_H_
+#define CHROME_BROWSER_PRINTING_PRINT_BACKEND_SERVICE_H_
+
+#include <string>
+
+#include "chrome/services/printing/public/mojom/print_backend_service.mojom.h"
+#include "mojo/public/cpp/bindings/remote.h"
+
+// Acquires a remote handle to the Print Backend Service instance, launching a
+// process to host the service if necessary.
+const mojo::Remote<printing::mojom::PrintBackendService>&
+GetPrintBackendService(const std::string& locale,
+                       const std::string& printer_name);
+
+#endif  // CHROME_BROWSER_PRINTING_PRINT_BACKEND_SERVICE_H_
diff --git a/chrome/browser/profiles/avatar_menu_actions_desktop.cc b/chrome/browser/profiles/avatar_menu_actions_desktop.cc
index 6db41b6..93ab731 100644
--- a/chrome/browser/profiles/avatar_menu_actions_desktop.cc
+++ b/chrome/browser/profiles/avatar_menu_actions_desktop.cc
@@ -29,7 +29,7 @@
   if (!settings_browser) {
     const Browser::CreateParams params(ProfileManager::GetLastUsedProfile(),
                                        true);
-    settings_browser = new Browser(params);
+    settings_browser = Browser::Create(params);
   }
   chrome::ShowSettingsSubPage(settings_browser, chrome::kCreateProfileSubPage);
   ProfileMetrics::LogProfileAddNewUser(type);
@@ -38,7 +38,7 @@
 void AvatarMenuActionsDesktop::EditProfile(Profile* profile) {
   Browser* settings_browser = browser_;
   if (!settings_browser) {
-    settings_browser = new Browser(Browser::CreateParams(profile, true));
+    settings_browser = Browser::Create(Browser::CreateParams(profile, true));
   }
   // TODO(davidben): The manageProfile page only allows editting the profile
   // associated with the browser it is opened in. AvatarMenuActionsDesktop
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc
index f17e7b1a..dd4aa05 100644
--- a/chrome/browser/profiles/profile.cc
+++ b/chrome/browser/profiles/profile.cc
@@ -372,7 +372,8 @@
 }
 
 bool Profile::IsIncognitoProfile() const {
-  return IsPrimaryOTRProfile() && !IsGuestSession();
+  return IsPrimaryOTRProfile() && !IsGuestSession() &&
+         !GetOriginalProfile()->IsSystemProfile();
 }
 
 // static
diff --git a/chrome/browser/profiles/profile.h b/chrome/browser/profiles/profile.h
index 833fb337a..29775e75 100644
--- a/chrome/browser/profiles/profile.h
+++ b/chrome/browser/profiles/profile.h
@@ -398,9 +398,10 @@
   std::string GetDebugName() const;
 
   // IsRegularProfile() and IsIncognitoProfile() are mutually exclusive.
-  // IsSystemProfile() implies that IsRegularProfile() is true.
-  // IsOffTheRecord() is true for the off the record profile of incognito mode
-  // and guest sessions, and also non-primary OffTheRecord profiles.
+  // IsSystemProfile() implies that IsRegularProfile() is true. Note that system
+  //   profile will also create an OffTheRecord profile.
+  // IsOffTheRecord() is true for the off the record profile of Incognito mode,
+  // system profile, Guest sessions, and also non-primary OffTheRecord profiles.
 
   // Returns whether it's a regular profile.
   bool IsRegularProfile() const;
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
index 2f3bfd7..a05f577 100644
--- a/chrome/browser/profiles/profile_manager.cc
+++ b/chrome/browser/profiles/profile_manager.cc
@@ -269,12 +269,6 @@
 }
 #endif
 
-bool IsProfileDirectoryMarkedForDeletion(const base::FilePath& profile_path) {
-  auto it = ProfilesToDelete().find(profile_path);
-  return it != ProfilesToDelete().end() &&
-         it->second == ProfileDeletionStage::MARKED;
-}
-
 // Physically remove deleted profile directories from disk.
 void NukeProfileFromDisk(const base::FilePath& profile_path) {
   // Delete both the profile directory and its corresponding cache.
@@ -382,6 +376,14 @@
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 }
 
+// static
+bool ProfileManager::IsProfileDirectoryMarkedForDeletion(
+    const base::FilePath& profile_path) {
+  const auto it = ProfilesToDelete().find(profile_path);
+  return it != ProfilesToDelete().end() &&
+         it->second == ProfileDeletionStage::MARKED;
+}
+
 #if BUILDFLAG(ENABLE_SESSION_SERVICE)
 // static
 void ProfileManager::ShutdownSessionServices() {
diff --git a/chrome/browser/profiles/profile_manager.h b/chrome/browser/profiles/profile_manager.h
index b9112a7..ccbe94c 100644
--- a/chrome/browser/profiles/profile_manager.h
+++ b/chrome/browser/profiles/profile_manager.h
@@ -224,6 +224,10 @@
   static void CleanUpGuestProfile();
 #endif
 
+  // Returns if profile is marked for deletion.
+  static bool IsProfileDirectoryMarkedForDeletion(
+      const base::FilePath& profile_dir);
+
   // Autoloads profiles if they are running background apps.
   void AutoloadProfiles();
 
diff --git a/chrome/browser/profiles/profile_window_browsertest.cc b/chrome/browser/profiles/profile_window_browsertest.cc
index 6f647454..626b615 100644
--- a/chrome/browser/profiles/profile_window_browsertest.cc
+++ b/chrome/browser/profiles/profile_window_browsertest.cc
@@ -309,9 +309,17 @@
 
   // Open a new guest browser window. Since this is a separate session, the find
   // in page text should have been cleared (along with all other browsing data).
-  profiles::FindOrCreateNewWindowForProfile(
-      guest_profile, chrome::startup::IS_NOT_PROCESS_STARTUP,
-      chrome::startup::IS_NOT_FIRST_RUN, true /*always_create*/);
+  // For ephemeral Guest profiles, after closing the last Guest browser the
+  // Guest profile is scheduled for deletion and is not considered a Guest
+  // profile anymore. Therefore the next Guest window requires opening a new
+  // browser and refreshing the profile object.
+  if (IsEphemeral()) {
+    guest_profile = CreateGuestBrowser()->profile();
+  } else {
+    profiles::FindOrCreateNewWindowForProfile(
+        guest_profile, chrome::startup::IS_NOT_PROCESS_STARTUP,
+        chrome::startup::IS_NOT_FIRST_RUN, true /*always_create*/);
+  }
   EXPECT_EQ(base::string16(),
             FindBarStateFactory::GetForBrowserContext(guest_profile)
                 ->GetSearchPrepopulateText());
diff --git a/chrome/browser/renderer_context_menu/copy_link_to_text_menu_observer.cc b/chrome/browser/renderer_context_menu/copy_link_to_text_menu_observer.cc
index 2afb160..7e866d5 100644
--- a/chrome/browser/renderer_context_menu/copy_link_to_text_menu_observer.cc
+++ b/chrome/browser/renderer_context_menu/copy_link_to_text_menu_observer.cc
@@ -13,8 +13,8 @@
 #include "content/public/browser/context_menu_params.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
 #include "ui/base/clipboard/scoped_clipboard_writer.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace {
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
index 5b26fc72..6043ab9 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -157,8 +157,8 @@
 #include "third_party/blink/public/public_buildflags.h"
 #include "third_party/metrics_proto/omnibox_input_type.pb.h"
 #include "ui/base/clipboard/clipboard.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
 #include "ui/base/clipboard/scoped_clipboard_writer.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 #include "ui/base/emoji/emoji_panel_helper.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/models/image_model.h"
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn
index 0f31d3d6..8d2163b 100644
--- a/chrome/browser/resources/BUILD.gn
+++ b/chrome/browser/resources/BUILD.gn
@@ -171,8 +171,7 @@
 
     deps = [
       "//chrome/browser/promo_browser_command:mojo_bindings_js",
-      "//chrome/browser/search/recipe_tasks:mojo_bindings_js",
-      "//chrome/browser/search/shopping_tasks:mojo_bindings_js",
+      "//chrome/browser/search/task_module:mojo_bindings_js",
       "//chrome/browser/ui/webui/new_tab_page:mojo_bindings_js",
       "//skia/public/mojom:mojom_js",
     ]
diff --git a/chrome/browser/resources/about_sys/about_sys.html b/chrome/browser/resources/about_sys/about_sys.html
index 2c364771..66f7960 100644
--- a/chrome/browser/resources/about_sys/about_sys.html
+++ b/chrome/browser/resources/about_sys/about_sys.html
@@ -5,6 +5,7 @@
     <title>$i18n{title}</title>
     <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
     <link rel="stylesheet" href="about_sys.css">
+    <script src="chrome://resources/js/assert.js"></script>
     <script src="chrome://resources/js/util.js"></script>
     <script src="chrome://resources/js/load_time_data.js"></script>
     <script src="about_sys.js"></script>
diff --git a/chrome/browser/resources/certificate_viewer.html b/chrome/browser/resources/certificate_viewer.html
index ac5653f9..5588079 100644
--- a/chrome/browser/resources/certificate_viewer.html
+++ b/chrome/browser/resources/certificate_viewer.html
@@ -15,6 +15,7 @@
     <script src="chrome://resources/js/cr/ui/focus_outline_manager.js"></script>
     <script src="chrome://resources/js/cr/ui/tabs.js"></script>
     <script src="chrome://resources/js/cr/ui/tree.js"></script>
+    <script src="chrome://resources/js/assert.js"></script>
     <script src="chrome://resources/js/util.js"></script>
     <script src="certificate_viewer.js"></script>
   </head>
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/magnifier/magnifier_test.js b/chrome/browser/resources/chromeos/accessibility/accessibility_common/magnifier/magnifier_test.js
index 357a90d2..e58be0b 100644
--- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/magnifier/magnifier_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/magnifier/magnifier_test.js
@@ -51,29 +51,34 @@
   }
 };
 
-TEST_F('MagnifierE2ETest', 'MovesScreenMagnifierToFocusedElement', function() {
-  const site = `
+// Disabled - flaky: https://crbug.com/1139939
+TEST_F(
+    'MagnifierE2ETest', 'DISABLED_MovesScreenMagnifierToFocusedElement',
+    function() {
+      const site = `
         <button id="apple">Apple</button>
         <button id="banana">Banana</button>
       `;
-  this.runWithLoadedTree(site, async function(root) {
-    // Validate magnifier wants to move to root.
-    const rootLocation = await getNextMagnifierLocation();
-    assertTrue(RectUtil.equal(rootLocation, root.location));
+      this.runWithLoadedTree(site, async function(root) {
+        // Validate magnifier wants to move to root.
+        const rootLocation = await getNextMagnifierLocation();
+        assertTrue(RectUtil.equal(rootLocation, root.location));
 
-    // Focus banana node.
-    const banana =
-        root.find({role: RoleType.BUTTON, attributes: {name: 'Banana'}});
-    banana.focus();
+        // Focus banana node.
+        const banana =
+            root.find({role: RoleType.BUTTON, attributes: {name: 'Banana'}});
+        banana.focus();
 
-    // Validate magnifier wants to move to banana.
-    const bananaLocation = await getNextMagnifierLocation();
-    assertTrue(RectUtil.equal(bananaLocation, banana.location));
-  });
-});
+        // Validate magnifier wants to move to banana.
+        const bananaLocation = await getNextMagnifierLocation();
+        assertTrue(RectUtil.equal(bananaLocation, banana.location));
+      });
+    });
 
+// Disabled - flaky: https://crbug.com/1139939
 TEST_F(
-    'MagnifierE2ETest', 'MovesScreenMagnifierToActiveDescendant', function() {
+    'MagnifierE2ETest', 'DISABLED_MovesScreenMagnifierToActiveDescendant',
+    function() {
       const site = `
     <div role="group" id="parent" aria-activedescendant="apple">
       <div id="apple" role="treeitem">Apple</div>
diff --git a/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_graphics_tracing.html b/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_graphics_tracing.html
index b2edec15..a1c7ec3f 100644
--- a/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_graphics_tracing.html
+++ b/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_graphics_tracing.html
@@ -9,6 +9,7 @@
     <link rel="stylesheet" href="arc_tracing.css">
     <script src="chrome://resources/js/cr.js"></script>
     <script src="chrome://resources/js/cr/ui.js"></script>
+    <script src="chrome://resources/js/assert.js"></script>
     <script src="chrome://resources/js/util.js"></script>
     <script src="arc_tracing_ui.js"></script>
     <script src="arc_graphics_tracing_ui.js"></script>
diff --git a/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_overview_tracing.html b/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_overview_tracing.html
index 787b417..6d8220b 100644
--- a/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_overview_tracing.html
+++ b/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_overview_tracing.html
@@ -9,6 +9,7 @@
     <link rel="stylesheet" href="arc_tracing.css">
     <script src="chrome://resources/js/cr.js"></script>
     <script src="chrome://resources/js/cr/ui.js"></script>
+    <script src="chrome://resources/js/assert.js"></script>
     <script src="chrome://resources/js/util.js"></script>
     <script src="arc_tracing_ui.js"></script>
     <script src="arc_overview_tracing_ui.js"></script>
diff --git a/chrome/browser/resources/chromeos/arc_power_control/arc_power_control.html b/chrome/browser/resources/chromeos/arc_power_control/arc_power_control.html
index 43b99bd..11f484c 100644
--- a/chrome/browser/resources/chromeos/arc_power_control/arc_power_control.html
+++ b/chrome/browser/resources/chromeos/arc_power_control/arc_power_control.html
@@ -10,6 +10,7 @@
     <link rel="stylesheet" href="arc_tracing.css">
     <script src="chrome://resources/js/cr.js"></script>
     <script src="chrome://resources/js/cr/ui.js"></script>
+    <script src="chrome://resources/js/assert.js"></script>
     <script src="chrome://resources/js/util.js"></script>
     <script src="arc_tracing_ui.js"></script>
     <script src="arc_power_control.js"></script>
diff --git a/chrome/browser/resources/chromeos/arc_support/main.html b/chrome/browser/resources/chromeos/arc_support/main.html
index c65f987..d85ac1eb 100644
--- a/chrome/browser/resources/chromeos/arc_support/main.html
+++ b/chrome/browser/resources/chromeos/arc_support/main.html
@@ -14,6 +14,7 @@
     <style include="cr-hidden-style"></style>
   </custom-style>
   <script src="chrome://resources/js/load_time_data.js"></script>
+  <script src="chrome://resources/js/assert.js"></script>
   <script src="chrome://resources/js/util.js"></script>
   <script src="chrome://resources/js/i18n_template_no_process.js"></script>
   <script src="chrome://resources/js/cr.js"></script>
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_optin.html b/chrome/browser/resources/chromeos/assistant_optin/assistant_optin.html
index fe2589c..c74bc288 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/assistant_optin.html
+++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_optin.html
@@ -36,6 +36,7 @@
 
 <script src="chrome://resources/js/cr.js"></script>
 <script src="chrome://resources/js/load_time_data.js"></script>
+<script src="chrome://resources/js/assert.js"></script>
 <script src="chrome://resources/js/util.js"></script>
 <script src="strings.js"></script>
 <script src="assistant_optin.js"></script>
diff --git a/chrome/browser/resources/chromeos/cryptohome.html b/chrome/browser/resources/chromeos/cryptohome.html
index 22181f0..3420e8c 100644
--- a/chrome/browser/resources/chromeos/cryptohome.html
+++ b/chrome/browser/resources/chromeos/cryptohome.html
@@ -4,6 +4,7 @@
     <title>About Cryptohome</title>
     <meta charset="utf-8">
     <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
+    <script src="chrome://resources/js/assert.js"></script>
     <script src="chrome://resources/js/util.js"></script>
     <script src="chrome://cryptohome/cryptohome.js"></script>
   </head>
diff --git a/chrome/browser/resources/chromeos/drive_internals.html b/chrome/browser/resources/chromeos/drive_internals.html
index 4ddca0f..7f93740 100644
--- a/chrome/browser/resources/chromeos/drive_internals.html
+++ b/chrome/browser/resources/chromeos/drive_internals.html
@@ -5,6 +5,7 @@
     <meta charset="utf-8">
     <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
     <link rel="stylesheet" href="drive_internals.css">
+    <script src="chrome://resources/js/assert.js"></script>
     <script src="chrome://resources/js/util.js"></script>
     <script src="chrome://drive-internals/drive_internals.js"></script>
   </head>
diff --git a/chrome/browser/resources/chromeos/first_run/app/main.html b/chrome/browser/resources/chromeos/first_run/app/main.html
index 255f718..2cc7b86 100644
--- a/chrome/browser/resources/chromeos/first_run/app/main.html
+++ b/chrome/browser/resources/chromeos/first_run/app/main.html
@@ -10,6 +10,7 @@
     <link rel="stylesheet" href="../step.css">
     <link rel="stylesheet" href="style.css">
     <script src="chrome://resources/js/load_time_data.js"></script>
+    <script src="chrome://resources/js/assert.js"></script>
     <script src="chrome://resources/js/util.js"></script>
     <script src="chrome://resources/js/i18n_template_no_process.js"></script>
     <script src="main.js"></script>
diff --git a/chrome/browser/resources/chromeos/first_run/first_run.html b/chrome/browser/resources/chromeos/first_run/first_run.html
index 1bd8f86..cefe149a 100644
--- a/chrome/browser/resources/chromeos/first_run/first_run.html
+++ b/chrome/browser/resources/chromeos/first_run/first_run.html
@@ -13,6 +13,7 @@
     <script src="chrome://resources/js/cr.js"></script>
     <script src="chrome://resources/js/cr/ui.js"></script>
     <script src="chrome://resources/js/load_time_data.js"></script>
+    <script src="chrome://resources/js/assert.js"></script>
     <script src="chrome://resources/js/util.js"></script>
     <script src="chrome://first-run/first_run.js"></script>
     <script src="chrome://first-run/strings.js"></script>
diff --git a/chrome/browser/resources/chromeos/login/discover/discover_app.html b/chrome/browser/resources/chromeos/login/discover/discover_app.html
index 4394d23..3ac0762 100644
--- a/chrome/browser/resources/chromeos/login/discover/discover_app.html
+++ b/chrome/browser/resources/chromeos/login/discover/discover_app.html
@@ -13,6 +13,7 @@
     <link rel="import" href="chrome://resources/html/i18n_behavior.html">
     <script src="chrome://resources/js/cr.js"></script>
     <script src="chrome://resources/js/load_time_data.js"></script>
+    <script src="chrome://resources/js/assert.js"></script>
     <script src="chrome://resources/js/util.js"></script>
     <script src="chrome://oobe/strings.js"></script>
     <script src="chrome://resources/js/i18n_template_no_process.js"></script>
diff --git a/chrome/browser/resources/chromeos/login/md_login.html b/chrome/browser/resources/chromeos/login/md_login.html
index c6346d5..d832e7b 100644
--- a/chrome/browser/resources/chromeos/login/md_login.html
+++ b/chrome/browser/resources/chromeos/login/md_login.html
@@ -33,6 +33,7 @@
 <script src="chrome://resources/js/event_tracker.js"></script>
 <script src="chrome://resources/js/cr/event_target.js"></script>
 <script src="chrome://resources/js/cr/ui.js"></script>
+<script src="chrome://resources/js/assert.js"></script>
 <script src="chrome://resources/js/cr/ui/array_data_model.js"></script>
 <script src="chrome://resources/js/cr/ui/dialogs.js"></script>
 <script src="chrome://resources/js/cr/ui/list_selection_controller.js"></script>
diff --git a/chrome/browser/resources/chromeos/login/oobe.html b/chrome/browser/resources/chromeos/login/oobe.html
index 27f124b..9393f9a 100644
--- a/chrome/browser/resources/chromeos/login/oobe.html
+++ b/chrome/browser/resources/chromeos/login/oobe.html
@@ -37,6 +37,7 @@
 <script src="chrome://resources/js/event_tracker.js"></script>
 <script src="chrome://resources/js/cr/event_target.js"></script>
 <script src="chrome://resources/js/cr/ui.js"></script>
+<script src="chrome://resources/js/assert.js"></script>
 <script src="chrome://resources/js/cr/ui/array_data_model.js"></script>
 <script src="chrome://resources/js/cr/ui/dialogs.js"></script>
 <script src="chrome://resources/js/cr/ui/list_selection_controller.js"></script>
diff --git a/chrome/browser/resources/chromeos/machine_learning/machine_learning_internals.html b/chrome/browser/resources/chromeos/machine_learning/machine_learning_internals.html
index cad2900..84e7a5a1 100644
--- a/chrome/browser/resources/chromeos/machine_learning/machine_learning_internals.html
+++ b/chrome/browser/resources/chromeos/machine_learning/machine_learning_internals.html
@@ -11,6 +11,7 @@
   <script src="chrome://resources/js/cr/ui.js"></script>
   <script src="chrome://resources/js/cr/ui/focus_outline_manager.js"></script>
   <script src="chrome://resources/js/cr/ui/tabs.js"></script>
+  <script src="chrome://resources/js/assert.js"></script>
   <script src="chrome://resources/js/util.js"></script>
   <script src="chromeos/services/machine_learning/public/mojom/tensor.mojom-lite.js"></script>
   <script src="chromeos/services/machine_learning/public/mojom/graph_executor.mojom-lite.js"></script>
diff --git a/chrome/browser/resources/chromeos/mobile_setup.html b/chrome/browser/resources/chromeos/mobile_setup.html
index 8f73338..6dafa49 100644
--- a/chrome/browser/resources/chromeos/mobile_setup.html
+++ b/chrome/browser/resources/chromeos/mobile_setup.html
@@ -7,6 +7,7 @@
 <link rel="stylesheet" href="chrome://resources/css/dialogs.css"></link>
 <link rel="stylesheet" href="mobile_setup.css"></link>
 <script src="chrome://resources/js/cr.js"></script>
+<script src="chrome://resources/js/assert.js"></script>
 <script src="chrome://resources/js/util.js"></script>
 <script src="chrome://resources/js/cr/ui/dialogs.js"></script>
 <script src="chrome://resources/cr_components/chromeos/cellular_setup/webview_post_util.js">
diff --git a/chrome/browser/resources/chromeos/mobile_setup_portal.html b/chrome/browser/resources/chromeos/mobile_setup_portal.html
index bca648d..626c20d 100644
--- a/chrome/browser/resources/chromeos/mobile_setup_portal.html
+++ b/chrome/browser/resources/chromeos/mobile_setup_portal.html
@@ -6,6 +6,7 @@
 <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
 <link rel="stylesheet" href="mobile_setup.css"></link>
 <script src="chrome://resources/js/cr.js"></script>
+<script src="chrome://resources/js/assert.js"></script>
 <script src="chrome://resources/js/util.js"></script>
 <script src="chrome://resources/cr_components/chromeos/cellular_setup/webview_post_util.js">
 </script>
diff --git a/chrome/browser/resources/chromeos/multidevice_internals/browser_tabs_model_form.html b/chrome/browser/resources/chromeos/multidevice_internals/browser_tabs_model_form.html
index c7af2299..346bb2cd 100644
--- a/chrome/browser/resources/chromeos/multidevice_internals/browser_tabs_model_form.html
+++ b/chrome/browser/resources/chromeos/multidevice_internals/browser_tabs_model_form.html
@@ -47,18 +47,6 @@
           browser-tab-metadata="{{browserTabTwoMetadata_}}">
       </browser-tabs-metadata-form>
     </div>
-    <div class="cr-row">
-      <div class="column">3: </div>
-      <browser-tabs-metadata-form
-          browser-tab-metadata="{{browserTabThreeMetadata_}}">
-      </browser-tabs-metadata-form>
-    </div>
-    <div class="cr-row">
-      <div class="column">4: </div>
-      <browser-tabs-metadata-form
-          browser-tab-metadata="{{browserTabFourMetadata_}}">
-      </browser-tabs-metadata-form>
-    </div>
   </template>
 </div>
 
diff --git a/chrome/browser/resources/chromeos/multidevice_internals/browser_tabs_model_form.js b/chrome/browser/resources/chromeos/multidevice_internals/browser_tabs_model_form.js
index d54e4ae..c0c83ee 100644
--- a/chrome/browser/resources/chromeos/multidevice_internals/browser_tabs_model_form.js
+++ b/chrome/browser/resources/chromeos/multidevice_internals/browser_tabs_model_form.js
@@ -34,23 +34,12 @@
       type: Object,
     },
 
-    /** @private{BrowserTabsMetadataModel} */
-    browserTabThreeMetadata_: {
-      type: Object,
-    },
-
-    /** @private{BrowserTabsMetadataModel} */
-    browserTabFourMetadata_: {
-      type: Object,
-    },
-
     /** @type{number} */
     nValidTabs_: {
       type: Number,
       computed:
           'computeNValidTabs_(isTabSyncEnabled_, browserTabOneMetadata_, ' +
-          'browserTabTwoMetadata_, browserTabThreeMetadata_, ' +
-          'browserTabFourMetadata_)',
+          'browserTabTwoMetadata_)',
     },
   },
 
@@ -67,10 +56,7 @@
    * @private
    */
   getAllBrowserTabMetadatas_() {
-    return [
-      this.browserTabOneMetadata_, this.browserTabTwoMetadata_,
-      this.browserTabThreeMetadata_, this.browserTabFourMetadata_
-    ];
+    return [this.browserTabOneMetadata_, this.browserTabTwoMetadata_];
   },
 
   /**
@@ -93,9 +79,7 @@
       const syncDisabledBrowserTabsModel = {
         isTabSyncEnabled: false,
         browserTabOneMetadata: null,
-        browserTabTwoMetadata: null,
-        browserTabThreeMetadata: null,
-        browserTabFourMetadata: null,
+        browserTabTwoMetadata: null
       };
       this.browserProxy_.setBrowserTabs(syncDisabledBrowserTabsModel);
       return;
@@ -104,9 +88,7 @@
     const browserTabsModel = {
       isTabSyncEnabled: this.isTabSyncEnabled_,
       browserTabOneMetadata: this.browserTabOneMetadata_,
-      browserTabTwoMetadata: this.browserTabTwoMetadata_,
-      browserTabThreeMetadata: this.browserTabThreeMetadata_,
-      browserTabFourMetadata: this.browserTabFourMetadata_,
+      browserTabTwoMetadata: this.browserTabTwoMetadata_
     };
     this.browserProxy_.setBrowserTabs(browserTabsModel);
   },
diff --git a/chrome/browser/resources/chromeos/multidevice_internals/types.js b/chrome/browser/resources/chromeos/multidevice_internals/types.js
index 0a27a9a..1eca6a0 100644
--- a/chrome/browser/resources/chromeos/multidevice_internals/types.js
+++ b/chrome/browser/resources/chromeos/multidevice_internals/types.js
@@ -142,9 +142,7 @@
  * @typedef {{
  *   isTabSyncEnabled: boolean,
  *   browserTabOneMetadata: ?BrowserTabsMetadataModel,
- *   browserTabTwoMetadata: ?BrowserTabsMetadataModel,
- *   browserTabThreeMetadata: ?BrowserTabsMetadataModel,
- *   browserTabFourMetadata: ?BrowserTabsMetadataModel,
+ *   browserTabTwoMetadata: ?BrowserTabsMetadataModel
  * }}
  */
 export let BrowserTabsModel;
diff --git a/chrome/browser/resources/chromeos/password_change/lock_screen_reauth.html b/chrome/browser/resources/chromeos/password_change/lock_screen_reauth.html
index c830eb3d..2b68643e 100644
--- a/chrome/browser/resources/chromeos/password_change/lock_screen_reauth.html
+++ b/chrome/browser/resources/chromeos/password_change/lock_screen_reauth.html
@@ -8,6 +8,7 @@
   <script src="chrome://resources/js/cr.js"></script>
   <script src="chrome://resources/js/cr/event_target.js"></script>
   <script src="chrome://resources/js/load_time_data.js"></script>
+  <script src="chrome://resources/js/assert.js"></script>
   <script src="chrome://resources/js/util.js"></script>
   <script src="chrome://lock-reauth/authenticator.js"></script>
 
@@ -126,4 +127,4 @@
   </lock-reauth>
 </body>
 
-</html>
\ No newline at end of file
+</html>
diff --git a/chrome/browser/resources/chromeos/password_change/password_change.html b/chrome/browser/resources/chromeos/password_change/password_change.html
index d35cbf1..17e4c10f 100644
--- a/chrome/browser/resources/chromeos/password_change/password_change.html
+++ b/chrome/browser/resources/chromeos/password_change/password_change.html
@@ -10,6 +10,7 @@
   <script src="chrome://resources/js/cr.js"></script>
   <script src="chrome://resources/js/cr/event_target.js"></script>
   <script src="chrome://resources/js/load_time_data.js"></script>
+  <script src="chrome://resources/js/assert.js"></script>
   <script src="chrome://resources/js/util.js"></script>
 
   <script src="chrome://password-change/authenticator.js"></script>
diff --git a/chrome/browser/resources/chromeos/power.html b/chrome/browser/resources/chromeos/power.html
index 4980cc94..53567015 100644
--- a/chrome/browser/resources/chromeos/power.html
+++ b/chrome/browser/resources/chromeos/power.html
@@ -5,6 +5,7 @@
   <title>$i18n{titleText}</title>
   <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
   <link rel="stylesheet" href="power.css">
+  <script src="chrome://resources/js/assert.js"></script>
   <script src="chrome://resources/js/promise_resolver.js"></script>
   <script src="chrome://resources/js/cr.js"></script>
   <script src="chrome://resources/js/load_time_data.js"></script>
diff --git a/chrome/browser/resources/chromeos/slow.html b/chrome/browser/resources/chromeos/slow.html
index 5392c89..7ac47b3 100644
--- a/chrome/browser/resources/chromeos/slow.html
+++ b/chrome/browser/resources/chromeos/slow.html
@@ -8,6 +8,7 @@
 <link rel="stylesheet" href="chrome://resources/css/widgets.css">
 <link rel="stylesheet" href="slow.css">
 <script src="chrome://resources/js/cr.js"></script>
+<script src="chrome://resources/js/assert.js"></script>
 <script src="chrome://resources/js/util.js"></script>
 <script src="slow.js"></script>
 </head>
diff --git a/chrome/browser/resources/chromeos/sys_internals/index.html b/chrome/browser/resources/chromeos/sys_internals/index.html
index 0a89e1b7..b9ce771 100644
--- a/chrome/browser/resources/chromeos/sys_internals/index.html
+++ b/chrome/browser/resources/chromeos/sys_internals/index.html
@@ -13,6 +13,7 @@
   <title>System Internals</title>
   <link rel="stylesheet" type="text/css" href="index.css">
   <script src="chrome://resources/js/cr.js"></script>
+  <script src="chrome://resources/js/assert.js"></script>
   <script src="chrome://resources/js/promise_resolver.js"></script>
   <script src="chrome://resources/js/util.js"></script>
   <script type="text/javascript" src="line_chart.js"></script>
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/js/main_scripts.js b/chrome/browser/resources/chromeos/wallpaper_manager/js/main_scripts.js
index 884e632..d5b8b83c 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/js/main_scripts.js
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/js/main_scripts.js
@@ -4,6 +4,7 @@
 
 // <include src="../../../../../../ui/webui/resources/js/cr.js">
 // <include src="../../../../../../ui/webui/resources/js/event_tracker.js">
+// <include src="../../../../../../ui/webui/resources/js/assert.js">
 // <include src="../../../../../../ui/webui/resources/js/load_time_data.js">
 // <include
 // src="../../../../../../ui/webui/resources/js/i18n_template_no_process.js">
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/main.html b/chrome/browser/resources/chromeos/wallpaper_manager/main.html
index 4acdefeb..69f7242 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/main.html
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/main.html
@@ -20,6 +20,7 @@
     Keep the list in sync with js/main_scripts.js. -->
     <script src="../../../../../ui/webui/resources/js/cr.js"></script>
     <script src="../../../../../ui/webui/resources/js/event_tracker.js"></script>
+    <script src="../../../../../ui/webui/resources/js/assert.js"></script>
     <script src="../../../../../ui/webui/resources/js/load_time_data.js"></script>
     <script src="../../../../../ui/webui/resources/js/i18n_template_no_process.js"></script>
     <script src="../../../../../ui/webui/resources/js/util.js"></script>
diff --git a/chrome/browser/resources/chromeos/zip_archiver/html/passphrase.html b/chrome/browser/resources/chromeos/zip_archiver/html/passphrase.html
index 2a8c05f..d893eff 100644
--- a/chrome/browser/resources/chromeos/zip_archiver/html/passphrase.html
+++ b/chrome/browser/resources/chromeos/zip_archiver/html/passphrase.html
@@ -3,6 +3,7 @@
   <head>
     <script src="chrome://resources/polymer/v1_0/html-imports/html-imports.min.js"></script>
 
+    <script src="chrome://resources/js/assert.js"></script>
     <script src="chrome://resources/js/util.js"></script>
     <script src="chrome://resources/js/load_time_data.js"></script>
     <script src="chrome://resources/js/i18n_template_no_process.js"></script>
diff --git a/chrome/browser/resources/device_log_ui/device_log_ui.html b/chrome/browser/resources/device_log_ui/device_log_ui.html
index 49c93f9..7b8ed70a 100644
--- a/chrome/browser/resources/device_log_ui/device_log_ui.html
+++ b/chrome/browser/resources/device_log_ui/device_log_ui.html
@@ -6,6 +6,7 @@
   <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
   <link rel="stylesheet" href="device_log_ui.css">
   <script src="chrome://resources/js/load_time_data.js"></script>
+  <script src="chrome://resources/js/assert.js"></script>
   <script src="chrome://resources/js/util.js"></script>
   <script src="strings.js"></script>
   <script src="device_log_ui.js"></script>
diff --git a/chrome/browser/resources/domain_reliability_internals/domain_reliability_internals.html b/chrome/browser/resources/domain_reliability_internals/domain_reliability_internals.html
index 10203ebc..16ef608 100644
--- a/chrome/browser/resources/domain_reliability_internals/domain_reliability_internals.html
+++ b/chrome/browser/resources/domain_reliability_internals/domain_reliability_internals.html
@@ -5,6 +5,7 @@
   <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
   <link rel="stylesheet" href="domain_reliability_internals.css">
   <script src="chrome://resources/js/cr.js"></script>
+  <script src="chrome://resources/js/assert.js"></script>
   <script src="chrome://resources/js/util.js"></script>
   <script src="chrome://resources/js/jstemplate_compiled.js"></script>
   <script src="domain_reliability_internals.js"></script>
diff --git a/chrome/browser/resources/engagement/site_engagement.html b/chrome/browser/resources/engagement/site_engagement.html
index 458b900..a4e0cb6 100644
--- a/chrome/browser/resources/engagement/site_engagement.html
+++ b/chrome/browser/resources/engagement/site_engagement.html
@@ -5,6 +5,7 @@
   <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
   <script src="chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js"></script>
   <script src="chrome://resources/mojo/url/mojom/url.mojom-lite.js"></script>
+  <script src="chrome://resources/js/assert.js"></script>
   <script src="chrome://resources/js/util.js"></script>
   <script src="components/site_engagement/core/mojom/site_engagement_details.mojom-lite.js">
   </script>
diff --git a/chrome/browser/resources/explore_sites_internals/explore_sites_internals.html b/chrome/browser/resources/explore_sites_internals/explore_sites_internals.html
index ac94797..d57697e 100644
--- a/chrome/browser/resources/explore_sites_internals/explore_sites_internals.html
+++ b/chrome/browser/resources/explore_sites_internals/explore_sites_internals.html
@@ -15,6 +15,7 @@
   <link rel="stylesheet" href="explore_sites_internals.css">
 
   <script src="chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js"></script>
+  <script src="chrome://resources/js/assert.js"></script>
   <script src="chrome://resources/js/util.js"></script>
   <script src="explore_sites_internals.mojom-lite.js"></script>
 
diff --git a/chrome/browser/resources/feed_internals/feed_internals.html b/chrome/browser/resources/feed_internals/feed_internals.html
index 82df40eb..e471c1a 100644
--- a/chrome/browser/resources/feed_internals/feed_internals.html
+++ b/chrome/browser/resources/feed_internals/feed_internals.html
@@ -18,6 +18,7 @@
   <script src="chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js"></script>
   <script src="chrome://resources/mojo/url/mojom/url.mojom-lite.js"></script>
   <script src="chrome://resources/mojo/mojo/public/mojom/base/time.mojom-lite.js"></script>
+  <script src="chrome://resources/js/assert.js"></script>
   <script src="chrome://resources/js/util.js"></script>
   <script src="feed_internals.mojom-lite.js"></script>
 
diff --git a/chrome/browser/resources/feedback/html/assistant_logs_info.html b/chrome/browser/resources/feedback/html/assistant_logs_info.html
index 9f796bbc..72cbf2b5 100644
--- a/chrome/browser/resources/feedback/html/assistant_logs_info.html
+++ b/chrome/browser/resources/feedback/html/assistant_logs_info.html
@@ -6,6 +6,7 @@
 <link rel="stylesheet" href="../css/assistant_logs_info.css"></link>
 
 <script src="chrome://resources/js/i18n_template_no_process.js"></script>
+<script src="chrome://resources/js/assert.js"></script>
 <script src="chrome://resources/js/util.js"></script>
 <script src="../js/assistant_logs_info.js"></script>
 </head>
diff --git a/chrome/browser/resources/feedback/html/default.html b/chrome/browser/resources/feedback/html/default.html
index af9683f..3dd032f6 100644
--- a/chrome/browser/resources/feedback/html/default.html
+++ b/chrome/browser/resources/feedback/html/default.html
@@ -11,6 +11,7 @@
 
   <script src="chrome://resources/js/load_time_data.js"></script>
   <script src="chrome://resources/js/i18n_template_no_process.js"></script>
+  <script src="chrome://resources/js/assert.js"></script>
   <script src="chrome://resources/js/util.js"></script>
   <script src="../js/feedback_util.js"></script>
   <script src="../js/take_screenshot.js"></script>
diff --git a/chrome/browser/resources/feedback/html/sys_info.html b/chrome/browser/resources/feedback/html/sys_info.html
index f125409..940cd47 100644
--- a/chrome/browser/resources/feedback/html/sys_info.html
+++ b/chrome/browser/resources/feedback/html/sys_info.html
@@ -7,6 +7,7 @@
     <link rel="stylesheet" href="chrome://resources/css/spinner.css">
     <link rel="stylesheet" href="../../about_sys/about_sys.css">
     <link rel="stylesheet" href="../css/sys_info.css">
+    <script src="chrome://resources/js/assert.js"></script>
     <script src="chrome://resources/js/util.js"></script>
     <script src="chrome://resources/js/i18n_template_no_process.js"></script>
     <script src="../js/sys_info.js"></script>
diff --git a/chrome/browser/resources/gaia_auth_host/authenticator.js b/chrome/browser/resources/gaia_auth_host/authenticator.js
index 92a671fc..9d12441 100644
--- a/chrome/browser/resources/gaia_auth_host/authenticator.js
+++ b/chrome/browser/resources/gaia_auth_host/authenticator.js
@@ -1240,13 +1240,6 @@
           console.error('Authenticator: contentWindow is null.');
         }
 
-        if (this.authMode == AuthMode.DEFAULT) {
-          chrome.send('metricsHandler:recordBooleanHistogram', [
-            'ChromeOS.GAIA.AuthenticatorContentWindowNull',
-            !this.webview_.contentWindow
-          ]);
-        }
-
         this.fireReadyEvent_();
         // Focus webview after dispatching event when webview is already
         // visible.
diff --git a/chrome/browser/resources/identity_internals/identity_internals.html b/chrome/browser/resources/identity_internals/identity_internals.html
index d30fc010..0d74153 100644
--- a/chrome/browser/resources/identity_internals/identity_internals.html
+++ b/chrome/browser/resources/identity_internals/identity_internals.html
@@ -7,6 +7,7 @@
   <link rel="stylesheet" href="identity_internals.css">
   <script src="chrome://resources/js/cr.js"></script>
   <script src="chrome://resources/js/cr/ui.js"></script>
+  <script src="chrome://resources/js/assert.js"></script>
   <script src="chrome://resources/js/util.js"></script>
   <script src="identity_internals.js"></script>
 </head>
diff --git a/chrome/browser/resources/inspect/inspect.html b/chrome/browser/resources/inspect/inspect.html
index 50b9762..ea5cccb 100644
--- a/chrome/browser/resources/inspect/inspect.html
+++ b/chrome/browser/resources/inspect/inspect.html
@@ -10,6 +10,7 @@
 <title>Inspect with Chrome Developer Tools</title>
 <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
 <link rel="stylesheet" href="inspect.css">
+<script src="chrome://resources/js/assert.js"></script>
 <script src="chrome://resources/js/util.js"></script>
 <script src="inspect.js"></script>
 </head>
diff --git a/chrome/browser/resources/interventions_internals/index.html b/chrome/browser/resources/interventions_internals/index.html
index dd5f3ad..0e1492c 100644
--- a/chrome/browser/resources/interventions_internals/index.html
+++ b/chrome/browser/resources/interventions_internals/index.html
@@ -7,6 +7,7 @@
     <script src="chrome://resources/js/cr.js"></script>
     <script src="chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js"></script>
     <script src="chrome://resources/mojo/url/mojom/url.mojom-lite.js"></script>
+    <script src="chrome://resources/js/assert.js"></script>
     <script src="chrome://resources/js/util.js"></script>
     <script src="chrome/browser/ui/webui/interventions_internals/interventions_internals.mojom-lite.js">
     </script>
diff --git a/chrome/browser/resources/invalidations/about_invalidations.html b/chrome/browser/resources/invalidations/about_invalidations.html
index e15459fd..2a5918d 100644
--- a/chrome/browser/resources/invalidations/about_invalidations.html
+++ b/chrome/browser/resources/invalidations/about_invalidations.html
@@ -4,6 +4,7 @@
   <meta charset="utf-8">
   <title>Invalidations</title>
   <script src="chrome://resources/js/cr.js"></script>
+  <script src="chrome://resources/js/assert.js"></script>
   <script src="chrome://resources/js/util.js"></script>
   <script src="chrome://invalidations/about_invalidations.js"></script>
   <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
diff --git a/chrome/browser/resources/local_discovery/local_discovery.html b/chrome/browser/resources/local_discovery/local_discovery.html
index 9dc7d52..54cdbff5 100644
--- a/chrome/browser/resources/local_discovery/local_discovery.html
+++ b/chrome/browser/resources/local_discovery/local_discovery.html
@@ -10,6 +10,7 @@
 
   <script src="chrome://resources/js/action_link.js"></script>
   <script src="chrome://resources/js/cr.js"></script>
+  <script src="chrome://resources/js/assert.js"></script>
   <script src="chrome://resources/js/util.js"></script>
   <script src="chrome://resources/js/load_time_data.js"></script>
   <script src="chrome://resources/js/cr/ui/overlay.js"></script>
diff --git a/chrome/browser/resources/media/media_engagement.html b/chrome/browser/resources/media/media_engagement.html
index b1a0fdf..ef8ab65 100644
--- a/chrome/browser/resources/media/media_engagement.html
+++ b/chrome/browser/resources/media/media_engagement.html
@@ -9,6 +9,7 @@
   <script src="chrome://resources/mojo/mojo/public/mojom/base/unguessable_token.mojom-lite.js"></script>
   <script src="chrome://resources/mojo/url/mojom/url.mojom-lite.js"></script>
   <script src="chrome://resources/mojo/url/mojom/origin.mojom-lite.js"></script>
+  <script src="chrome://resources/js/assert.js"></script>
   <script src="chrome://resources/js/util.js"></script>
 
   <script src="chrome/browser/media/media_engagement_score_details.mojom-lite.js">
diff --git a/chrome/browser/resources/media/media_feeds.html b/chrome/browser/resources/media/media_feeds.html
index e6919df..53913a9 100644
--- a/chrome/browser/resources/media/media_feeds.html
+++ b/chrome/browser/resources/media/media_feeds.html
@@ -14,6 +14,7 @@
   <script src="chrome://resources/mojo/url/mojom/url.mojom-lite.js"></script>
   <script src="ui/gfx/geometry/mojom/geometry.mojom-lite.js"></script>
   <script src="services/media_session/public/mojom/media_session.mojom-lite.js"></script>
+  <script src="chrome://resources/js/assert.js"></script>
   <script src="chrome://resources/js/util.js"></script>
 
   <script src="chrome/browser/media/feeds/media_feeds_store.mojom-lite.js">
diff --git a/chrome/browser/resources/media/media_history.html b/chrome/browser/resources/media/media_history.html
index 894eb8a..3daa5a2 100644
--- a/chrome/browser/resources/media/media_history.html
+++ b/chrome/browser/resources/media/media_history.html
@@ -7,6 +7,7 @@
   <link rel="stylesheet" href="chrome://resources/css/tabs.css">
 
   <script src="chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js"></script>
+  <script src="chrome://resources/js/assert.js"></script>
   <script src="chrome://resources/js/promise_resolver.js"></script>
   <script src="chrome://resources/js/util.js"></script>
   <script src="chrome://resources/mojo/mojo/public/mojom/base/big_buffer.mojom-lite.js"></script>
diff --git a/chrome/browser/resources/media/webrtc_logs.html b/chrome/browser/resources/media/webrtc_logs.html
index c5e9f80..20cd3c16 100644
--- a/chrome/browser/resources/media/webrtc_logs.html
+++ b/chrome/browser/resources/media/webrtc_logs.html
@@ -6,6 +6,7 @@
   <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
   <link rel="stylesheet" href="webrtc_logs.css">
   <script src="chrome://resources/js/load_time_data.js"></script>
+  <script src="chrome://resources/js/assert.js"></script>
   <script src="chrome://resources/js/util.js"></script>
   <script src="strings.js"></script>
   <script src="webrtc_logs.js"></script>
diff --git a/chrome/browser/resources/net_internals/index.html b/chrome/browser/resources/net_internals/index.html
index cf44da3..e901832 100644
--- a/chrome/browser/resources/net_internals/index.html
+++ b/chrome/browser/resources/net_internals/index.html
@@ -13,6 +13,7 @@
     <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
     <link rel="stylesheet" href="main.css">
     <link rel="stylesheet" href="chromeos_view.css">
+    <script src="chrome://resources/js/assert.js"></script>
     <script src="chrome://resources/js/util.js"></script>
     <script src="chrome://resources/js/cr.js"></script>
     <script src="chrome://net-internals/index.js"></script>
diff --git a/chrome/browser/resources/new_tab_page/BUILD.gn b/chrome/browser/resources/new_tab_page/BUILD.gn
index f9d6632..7588d9a 100644
--- a/chrome/browser/resources/new_tab_page/BUILD.gn
+++ b/chrome/browser/resources/new_tab_page/BUILD.gn
@@ -362,8 +362,7 @@
       "new_tab_page.mojom-lite.js",
       "omnibox.mojom-lite.js",
       "promo_browser_command.mojom-lite.js",
-      "modules/recipe_tasks/recipe_tasks.mojom-lite.js",
-      "modules/shopping_tasks/shopping_tasks.mojom-lite.js",
+      "modules/task_module/task_module.mojom-lite.js",
       "foo.mojom-lite.js",
     ]
   }
diff --git a/chrome/browser/resources/new_tab_page/modules/BUILD.gn b/chrome/browser/resources/new_tab_page/modules/BUILD.gn
index f514641..6739d6c 100644
--- a/chrome/browser/resources/new_tab_page/modules/BUILD.gn
+++ b/chrome/browser/resources/new_tab_page/modules/BUILD.gn
@@ -15,8 +15,7 @@
   deps = [
     ":module_registry",
     "kaleidoscope:module",
-    "recipe_tasks:module",
-    "shopping_tasks:module",
+    "task_module:module",
   ]
   if (!is_official_build) {
     deps += [ "dummy:module" ]
@@ -45,8 +44,7 @@
   public_deps = [
     ":web_components_local",
     "dummy:web_components",
-    "recipe_tasks:web_components",
-    "shopping_tasks:web_components",
+    "task_module:web_components",
   ]
 }
 
@@ -65,8 +63,7 @@
       "module_descriptor.js",
       "modules.js",
       "module_registry.js",
-      "recipe_tasks/recipe_tasks_handler_proxy.js",
-      "shopping_tasks/shopping_tasks_handler_proxy.js",
+      "task_module/task_module_handler_proxy.js",
     ]
     if (!is_official_build) {
       in_files += [ "dummy/foo_proxy.js" ]
@@ -81,8 +78,7 @@
     in_files = [
       "module_wrapper.js",
       "dummy/module.js",
-      "recipe_tasks/module.js",
-      "shopping_tasks/module.js",
+      "task_module/module.js",
     ]
   }
 }
diff --git a/chrome/browser/resources/new_tab_page/modules/modules.js b/chrome/browser/resources/new_tab_page/modules/modules.js
index 22051578..2be827d 100644
--- a/chrome/browser/resources/new_tab_page/modules/modules.js
+++ b/chrome/browser/resources/new_tab_page/modules/modules.js
@@ -14,20 +14,19 @@
 import {kaleidoscopeDescriptor} from './kaleidoscope/module.js';
 import {ModuleDescriptor} from './module_descriptor.js';
 import {ModuleRegistry} from './module_registry.js';
-import {recipeTasksDescriptor} from './recipe_tasks/module.js';
-import {shoppingTasksDescriptor} from './shopping_tasks/module.js';
+import {recipeTasksDescriptor, shoppingTasksDescriptor} from './task_module/module.js';
 
 /** @type {!Array<!ModuleDescriptor>} */
 const descriptors = [];
 
-if (loadTimeData.getBoolean('recipeTasksModuleEnabled')) {
-  descriptors.push(recipeTasksDescriptor);
-}
-
 if (loadTimeData.getBoolean('shoppingTasksModuleEnabled')) {
   descriptors.push(shoppingTasksDescriptor);
 }
 
+if (loadTimeData.getBoolean('recipeTasksModuleEnabled')) {
+  descriptors.push(recipeTasksDescriptor);
+}
+
 if (loadTimeData.getBoolean('kaleidoscopeModuleEnabled')) {
   descriptors.push(kaleidoscopeDescriptor);
 }
diff --git a/chrome/browser/resources/new_tab_page/modules/modules_resources.grdp b/chrome/browser/resources/new_tab_page/modules/modules_resources.grdp
index b471e0f..f071df2c 100644
--- a/chrome/browser/resources/new_tab_page/modules/modules_resources.grdp
+++ b/chrome/browser/resources/new_tab_page/modules/modules_resources.grdp
@@ -19,14 +19,9 @@
   <include name="IDR_NEW_TAB_PAGE_MODULE_WRAPPER_JS"
       file="${root_gen_dir}/chrome/browser/resources/new_tab_page/modules/module_wrapper.js"
       use_base_dir="false" type="BINDATA" compress="false" />
-  <include name="IDR_NEW_TAB_PAGE_MODULES_RECIPE_TASKS_MODULE_JS"
-      file="${root_gen_dir}/chrome/browser/resources/new_tab_page/modules/recipe_tasks/module.js"
+  <include name="IDR_NEW_TAB_PAGE_MODULES_TASK_MODULE_MODULE_JS"
+      file="${root_gen_dir}/chrome/browser/resources/new_tab_page/modules/task_module/module.js"
       use_base_dir="false" type="BINDATA" compress="false" />
-  <include name="IDR_NEW_TAB_PAGE_MODULES_RECIPE_TASKS_RECIPE_TASKS_HANDLER_PROXY_JS"
-      file="modules/recipe_tasks/recipe_tasks_handler_proxy.js" type="BINDATA" compress="false" />
-  <include name="IDR_NEW_TAB_PAGE_MODULES_SHOPPING_TASKS_MODULE_JS"
-      file="${root_gen_dir}/chrome/browser/resources/new_tab_page/modules/shopping_tasks/module.js"
-      use_base_dir="false" type="BINDATA" compress="false" />
-  <include name="IDR_NEW_TAB_PAGE_MODULES_SHOPPING_TASKS_SHOPPING_TASKS_HANDLER_PROXY_JS"
-      file="modules/shopping_tasks/shopping_tasks_handler_proxy.js" type="BINDATA" compress="false" />
+  <include name="IDR_NEW_TAB_PAGE_MODULES_TASK_MODULE_TASK_MODULE_HANDLER_PROXY_JS"
+      file="modules/task_module/task_module_handler_proxy.js" type="BINDATA" compress="false" />
 </grit-part>
diff --git a/chrome/browser/resources/new_tab_page/modules/recipe_tasks/BUILD.gn b/chrome/browser/resources/new_tab_page/modules/recipe_tasks/BUILD.gn
deleted file mode 100644
index 7976e4d..0000000
--- a/chrome/browser/resources/new_tab_page/modules/recipe_tasks/BUILD.gn
+++ /dev/null
@@ -1,28 +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.
-
-import("//third_party/closure_compiler/compile_js.gni")
-import("//tools/polymer/html_to_js.gni")
-
-js_library("module") {
-  deps = [
-    ":recipe_tasks_handler_proxy",
-    "..:module_descriptor",
-    "../..:img",
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-    "//ui/webui/resources/cr_elements/cr_grid",
-    "//ui/webui/resources/js:load_time_data.m",
-  ]
-}
-
-js_library("recipe_tasks_handler_proxy") {
-  deps = [
-    "//chrome/browser/search/recipe_tasks:mojo_bindings_js_library_for_compile",
-    "//ui/webui/resources/js:cr.m",
-  ]
-}
-
-html_to_js("web_components") {
-  js_files = [ "module.js" ]
-}
diff --git a/chrome/browser/resources/new_tab_page/modules/recipe_tasks/module.html b/chrome/browser/resources/new_tab_page/modules/recipe_tasks/module.html
deleted file mode 100644
index a922a6b..0000000
--- a/chrome/browser/resources/new_tab_page/modules/recipe_tasks/module.html
+++ /dev/null
@@ -1,168 +0,0 @@
-<style>
-  :host {
-    box-sizing: border-box;
-    display: block;
-    height: 100%;
-    padding-inline-end: 15px;
-    padding-inline-start: 15px;
-    width: 100%;
-  }
-
-  #recipes {
-    display: flex;
-    flex-direction: row;
-  }
-
-  .recipe {
-    border-radius: 4px;
-    display: flex;
-    flex-direction: column;
-    outline: none;
-    text-decoration: none;
-    width: 120px;
-  }
-
-  :host-context(.focus-outline-visible) .recipe:focus {
-    box-shadow: var(--ntp-focus-shadow);
-  }
-
-  .recipe + .recipe {
-    margin-inline-start: 16px;
-  }
-
-  .image {
-    background: var(--google-grey-50);
-    border-radius: 4px;
-    box-sizing: border-box;
-    height: 100px;
-    margin-bottom: 8px;
-    width: 120px;
-  }
-
-  img {
-    border-radius: 4px;
-    height: 100%;
-    object-fit: cover;
-    width: 100%;
-  }
-
-  .price {
-    color: var(--cr-primary-text-color);
-    font-size: 13px;
-    font-weight: bold;
-    height: 14px;
-    line-height: 15px;
-    margin-bottom: 8px;
-  }
-
-  .name {
-    color: var(--cr-primary-text-color);
-    font-size: 12px;
-    line-height: 20px;
-    margin-bottom: 4px;
-    overflow: hidden;
-    text-overflow: ellipsis;
-    white-space: nowrap;
-  }
-
-  .info {
-    color: var(--cr-secondary-text-color);
-    font-size: 11px;
-    height: 13px;
-    text-overflow: ellipsis;
-  }
-
-  #relatedSearches {
-    display: flex;
-    flex-direction: row;
-    margin-top: 16px;
-  }
-
-  .pill {
-    align-items: center;
-    border: solid var(--ntp-border-color) 1px;
-    border-radius: 16px;
-    box-sizing: border-box;
-    display: flex;
-    flex-direction: row;
-    flex-shrink: 0;
-    height: 32px;
-    outline: none;
-    text-decoration: none;
-  }
-
-  :host-context(.focus-outline-visible) .pill:focus {
-    box-shadow: var(--ntp-focus-shadow);
-  }
-
-  .pill + .pill {
-    margin-inline-start: 8px;
-  }
-
-  .loupe {
-    -webkit-mask-image: url(search.svg);
-    -webkit-mask-repeat: no-repeat;
-    -webkit-mask-size: 100%;
-    background-color: var(--cr-secondary-text-color);
-    height: 16px;
-    margin-inline-start: 12px;
-    width: 16px;
-  }
-
-  .search-text {
-    color: var(--cr-primary-text-color);
-    font-size: 13px;
-    margin-inline-end: 12px;
-    margin-inline-start: 8px;
-  }
-
-  cr-dialog::part(dialog) {
-    width: 459px;
-  }
-
-  cr-dialog [slot='body'] div:not(:last-of-type) {
-    margin-bottom: 24px;
-  }
-
-  cr-dialog [slot='body'] a[href] {
-    color: var(--cr-link-color);
-    text-decoration: none;
-  }
-</style>
-<div id="recipes">
-  <template is="dom-repeat" id="recipesRepeat"
-      items="[[recipeTask.recipes]]" on-dom-change="onDomChange_">
-    <a class="recipe" href="[[item.targetUrl.url]]" on-click="onRecipeClick_"
-        on-auxclick="onRecipeClick_">
-      <div class="image">
-        <img is="ntp-img" auto-src="[[item.imageUrl.url]]"></img>
-      </div>
-      <div class="name"  title="[[item.name]]">[[item.name]]</div>
-      <div class="info">[[item.info]]</div>
-    </a>
-  </template>
-</div>
-<div id="relatedSearches">
-  <template is="dom-repeat" id="relatedSearchesRepeat"
-      items="[[recipeTask.relatedSearches]]" on-dom-change="onDomChange_">
-    <a class="pill" href="[[item.targetUrl.url]]" on-click="onPillClick_"
-        on-auxclick="onPillClick_">
-      <div class="loupe"></div>
-      <div class="search-text">[[item.text]]</div>
-    </a>
-  </template>
-</div>
-<template is="dom-if" if="[[showInfoDialog]]" restamp>
-  <cr-dialog show-on-attach>
-    <div slot="title">$i18n{modulesTasksInfoTitle}</div>
-    <div slot="body">
-      <div>$i18nRaw{modulesTasksInfo1}</div>
-      <div>$i18nRaw{modulesTasksInfo2}</div>
-    </div>
-    <div slot="button-container">
-      <cr-button class="action-button" on-click="onCloseClick_">
-        $i18n{modulesTasksInfoClose}
-      </cr-button>
-    </div>
-  </cr-dialog>
-</template>
diff --git a/chrome/browser/resources/new_tab_page/modules/recipe_tasks/module.js b/chrome/browser/resources/new_tab_page/modules/recipe_tasks/module.js
deleted file mode 100644
index 727dbdd..0000000
--- a/chrome/browser/resources/new_tab_page/modules/recipe_tasks/module.js
+++ /dev/null
@@ -1,121 +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.
-
-import '../../img.js';
-
-import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
-import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {ModuleDescriptor} from '../module_descriptor.js';
-import {RecipeTasksHandlerProxy} from './recipe_tasks_handler_proxy.js';
-
-/**
- * @fileoverview Implements the UI of the recipes module. This module shows
- * recently view and related recipes
- */
-
-class RecipeTasksModuleElement extends PolymerElement {
-  static get is() {
-    return 'ntp-recipe-tasks-module';
-  }
-
-  static get template() {
-    return html`{__html_template__}`;
-  }
-
-  static get properties() {
-    return {
-      /** @type {recipeTasks.mojom.RecipeTask} */
-      recipeTask: Object,
-
-      /** @type {boolean} */
-      showInfoDialog: Boolean,
-    };
-  }
-
-  /** @override */
-  ready() {
-    super.ready();
-    /** @type {IntersectionObserver} */
-    this.intersectionObserver_ = null;
-  }
-
-  /**
-   * @param {!Event} e
-   * @private
-   */
-  onRecipeClick_(e) {
-    const index = this.$.recipesRepeat.indexForElement(e.target);
-    RecipeTasksHandlerProxy.getInstance().handler.onRecipeClicked(index);
-    this.dispatchEvent(new Event('usage', {bubbles: true, composed: true}));
-  }
-
-  /**
-   * @param {!Event} e
-   * @private
-   */
-  onPillClick_(e) {
-    const index = this.$.relatedSearchesRepeat.indexForElement(e.target);
-    RecipeTasksHandlerProxy.getInstance().handler.onRelatedSearchClicked(index);
-    this.dispatchEvent(new Event('usage', {bubbles: true, composed: true}));
-  }
-
-  /** @private */
-  onCloseClick_() {
-    this.showInfoDialog = false;
-  }
-
-  /** @private */
-  onDomChange_() {
-    if (!this.intersectionObserver_) {
-      this.intersectionObserver_ = new IntersectionObserver(entries => {
-        entries.forEach(({intersectionRatio, target}) => {
-          target.style.visibility =
-              intersectionRatio < 1 ? 'hidden' : 'visible';
-        });
-        this.dispatchEvent(new Event('visibility-update'));
-      }, {root: this, threshold: 1});
-    } else {
-      this.intersectionObserver_.disconnect();
-    }
-    this.shadowRoot.querySelectorAll('.recipe, .pill')
-        .forEach(el => this.intersectionObserver_.observe(el));
-  }
-}
-
-customElements.define(RecipeTasksModuleElement.is, RecipeTasksModuleElement);
-
-/** @return {!Promise<?{element: !HTMLElement, title: string}>} */
-async function createModule() {
-  const {recipeTask} = await RecipeTasksHandlerProxy.getInstance()
-                           .handler.getPrimaryRecipeTask();
-  if (!recipeTask) {
-    return null;
-  }
-  const element = new RecipeTasksModuleElement();
-  element.recipeTask = recipeTask;
-  return {
-    element: element,
-    title: recipeTask.title,
-    actions: {
-      info: () => {
-        element.showInfoDialog = true;
-      },
-      dismiss: () => {
-        RecipeTasksHandlerProxy.getInstance().handler.dismissRecipeTask(
-            recipeTask.name);
-        return loadTimeData.getStringF(
-            'dismissModuleToastMessage', recipeTask.name);
-      },
-      restore: () => {
-        RecipeTasksHandlerProxy.getInstance().handler.restoreRecipeTask(
-            recipeTask.name);
-      },
-    },
-  };
-}
-
-/** @type {!ModuleDescriptor} */
-export const recipeTasksDescriptor = new ModuleDescriptor(
-    /*id=*/ 'recipe_tasks',
-    /*heightPx=*/ 206, createModule);
diff --git a/chrome/browser/resources/new_tab_page/modules/recipe_tasks/recipe_tasks_handler_proxy.js b/chrome/browser/resources/new_tab_page/modules/recipe_tasks/recipe_tasks_handler_proxy.js
deleted file mode 100644
index 4ec43cc1..0000000
--- a/chrome/browser/resources/new_tab_page/modules/recipe_tasks/recipe_tasks_handler_proxy.js
+++ /dev/null
@@ -1,21 +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.
-
-import './recipe_tasks.mojom-lite.js';
-
-import {addSingletonGetter} from 'chrome://resources/js/cr.m.js';
-
-/**
- * @fileoverview This file provides a class that exposes the Mojo handler
- * interface used for retrieving the recipe task for the recipe task module.
- */
-
-export class RecipeTasksHandlerProxy {
-  constructor() {
-    /** @type {!recipeTasks.mojom.RecipeTasksHandlerRemote} */
-    this.handler = recipeTasks.mojom.RecipeTasksHandler.getRemote();
-  }
-}
-
-addSingletonGetter(RecipeTasksHandlerProxy);
diff --git a/chrome/browser/resources/new_tab_page/modules/shopping_tasks/module.js b/chrome/browser/resources/new_tab_page/modules/shopping_tasks/module.js
deleted file mode 100644
index 2e555a5d..0000000
--- a/chrome/browser/resources/new_tab_page/modules/shopping_tasks/module.js
+++ /dev/null
@@ -1,124 +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.
-
-import '../../img.js';
-
-import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
-import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {ModuleDescriptor} from '../module_descriptor.js';
-import {ShoppingTasksHandlerProxy} from './shopping_tasks_handler_proxy.js';
-
-/**
- * @fileoverview Implements the UI of the shopping tasks module. This module
- * shows a currently active shopping search journey and facilitates the user to
- * that search journey up again.
- */
-
-class ShoppingTasksModuleElement extends PolymerElement {
-  static get is() {
-    return 'ntp-shopping-tasks-module';
-  }
-
-  static get template() {
-    return html`{__html_template__}`;
-  }
-
-  static get properties() {
-    return {
-      /** @type {shoppingTasks.mojom.ShoppingTask} */
-      shoppingTask: Object,
-
-      /** @type {boolean} */
-      showInfoDialog: Boolean,
-    };
-  }
-
-  /** @override */
-  ready() {
-    super.ready();
-    /** @type {IntersectionObserver} */
-    this.intersectionObserver_ = null;
-  }
-
-  /**
-   * @param {!Event} e
-   * @private
-   */
-  onProductClick_(e) {
-    const index = this.$.productsRepeat.indexForElement(e.target);
-    ShoppingTasksHandlerProxy.getInstance().handler.onProductClicked(index);
-    this.dispatchEvent(new Event('usage', {bubbles: true, composed: true}));
-  }
-
-  /**
-   * @param {!Event} e
-   * @private
-   */
-  onPillClick_(e) {
-    const index = this.$.relatedSearchesRepeat.indexForElement(e.target);
-    ShoppingTasksHandlerProxy.getInstance().handler.onRelatedSearchClicked(
-        index);
-    this.dispatchEvent(new Event('usage', {bubbles: true, composed: true}));
-  }
-
-  /** @private */
-  onCloseClick_() {
-    this.showInfoDialog = false;
-  }
-
-  /** @private */
-  onDomChange_() {
-    if (!this.intersectionObserver_) {
-      this.intersectionObserver_ = new IntersectionObserver(entries => {
-        entries.forEach(({intersectionRatio, target}) => {
-          target.style.visibility =
-              intersectionRatio < 1 ? 'hidden' : 'visible';
-        });
-        this.dispatchEvent(new Event('visibility-update'));
-      }, {root: this, threshold: 1});
-    } else {
-      this.intersectionObserver_.disconnect();
-    }
-    this.shadowRoot.querySelectorAll('.product, .pill')
-        .forEach(el => this.intersectionObserver_.observe(el));
-  }
-}
-
-customElements.define(
-    ShoppingTasksModuleElement.is, ShoppingTasksModuleElement);
-
-/** @return {!Promise<?{element: !HTMLElement, title: string}>} */
-async function createModule() {
-  const {shoppingTask} = await ShoppingTasksHandlerProxy.getInstance()
-                             .handler.getPrimaryShoppingTask();
-  if (!shoppingTask) {
-    return null;
-  }
-  const element = new ShoppingTasksModuleElement();
-  element.shoppingTask = shoppingTask;
-  return {
-    element: element,
-    title: shoppingTask.title,
-    actions: {
-      info: () => {
-        element.showInfoDialog = true;
-      },
-      dismiss: () => {
-        ShoppingTasksHandlerProxy.getInstance().handler.dismissShoppingTask(
-            shoppingTask.name);
-        return loadTimeData.getStringF(
-            'dismissModuleToastMessage', shoppingTask.name);
-      },
-      restore: () => {
-        ShoppingTasksHandlerProxy.getInstance().handler.restoreShoppingTask(
-            shoppingTask.name);
-      },
-    },
-  };
-}
-
-/** @type {!ModuleDescriptor} */
-export const shoppingTasksDescriptor = new ModuleDescriptor(
-    /*id=*/ 'shopping_tasks',
-    /*heightPx=*/ 270, createModule);
diff --git a/chrome/browser/resources/new_tab_page/modules/shopping_tasks/shopping_tasks_handler_proxy.js b/chrome/browser/resources/new_tab_page/modules/shopping_tasks/shopping_tasks_handler_proxy.js
deleted file mode 100644
index b0bdb3c..0000000
--- a/chrome/browser/resources/new_tab_page/modules/shopping_tasks/shopping_tasks_handler_proxy.js
+++ /dev/null
@@ -1,21 +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.
-
-import './shopping_tasks.mojom-lite.js';
-
-import {addSingletonGetter} from 'chrome://resources/js/cr.m.js';
-
-/**
- * @fileoverview This file provides a class that exposes the Mojo handler
- * interface used for retrieving the shopping task for the shopping task module.
- */
-
-export class ShoppingTasksHandlerProxy {
-  constructor() {
-    /** @type {!shoppingTasks.mojom.ShoppingTasksHandlerRemote} */
-    this.handler = shoppingTasks.mojom.ShoppingTasksHandler.getRemote();
-  }
-}
-
-addSingletonGetter(ShoppingTasksHandlerProxy);
diff --git a/chrome/browser/resources/new_tab_page/modules/shopping_tasks/BUILD.gn b/chrome/browser/resources/new_tab_page/modules/task_module/BUILD.gn
similarity index 79%
rename from chrome/browser/resources/new_tab_page/modules/shopping_tasks/BUILD.gn
rename to chrome/browser/resources/new_tab_page/modules/task_module/BUILD.gn
index de4d362..ca698ee5 100644
--- a/chrome/browser/resources/new_tab_page/modules/shopping_tasks/BUILD.gn
+++ b/chrome/browser/resources/new_tab_page/modules/task_module/BUILD.gn
@@ -7,7 +7,7 @@
 
 js_library("module") {
   deps = [
-    ":shopping_tasks_handler_proxy",
+    ":task_module_handler_proxy",
     "..:module_descriptor",
     "../..:img",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
@@ -16,9 +16,9 @@
   ]
 }
 
-js_library("shopping_tasks_handler_proxy") {
+js_library("task_module_handler_proxy") {
   deps = [
-    "//chrome/browser/search/shopping_tasks:mojo_bindings_js_library_for_compile",
+    "//chrome/browser/search/task_module:mojo_bindings_js_library_for_compile",
     "//ui/webui/resources/js:cr.m",
   ]
 }
diff --git a/chrome/browser/resources/new_tab_page/modules/shopping_tasks/module.html b/chrome/browser/resources/new_tab_page/modules/task_module/module.html
similarity index 76%
rename from chrome/browser/resources/new_tab_page/modules/shopping_tasks/module.html
rename to chrome/browser/resources/new_tab_page/modules/task_module/module.html
index b6d06ea..a090d46 100644
--- a/chrome/browser/resources/new_tab_page/modules/shopping_tasks/module.html
+++ b/chrome/browser/resources/new_tab_page/modules/task_module/module.html
@@ -1,4 +1,4 @@
-<style>
+<style include="cr-hidden-style">
   :host {
     box-sizing: border-box;
     display: block;
@@ -8,12 +8,12 @@
     width: 100%;
   }
 
-  #products {
+  #taskItems {
     display: flex;
     flex-direction: row;
   }
 
-  .product {
+  .task-item {
     border-radius: 4px;
     display: flex;
     flex-direction: column;
@@ -22,30 +22,45 @@
     width: 120px;
   }
 
-  :host-context(.focus-outline-visible) .product:focus {
+  :host-context(.focus-outline-visible) .task-item:focus {
     box-shadow: var(--ntp-focus-shadow);
   }
 
-  .product + .product {
+  .task-item:not([hidden]) + .task-item {
     margin-inline-start: 16px;
   }
 
   .image {
-    background: var(--google-grey-50);
     border-radius: 4px;
     box-sizing: border-box;
-    height: 120px;
     margin-bottom: 8px;
-    padding: 10px;
     width: 120px;
   }
 
+  :host([shopping]) .image {
+    background: var(--google-grey-50);
+    height: 120px;
+    padding: 10px;
+  }
+
+  :host([recipe]) .image {
+    height: 100px;
+  }
+
   img {
     height: 100%;
-    object-fit: contain;
     width: 100%;
   }
 
+  :host([shopping]) img {
+    object-fit: contain;
+  }
+
+  :host([recipe]) img {
+    border-radius: 4px;
+    object-fit: cover;
+  }
+
   .price {
     color: var(--cr-primary-text-color);
     font-size: 13px;
@@ -56,15 +71,23 @@
   }
 
   .name {
+    color: var(--cr-primary-text-color);
+    font-size: 12px;
+    line-height: 20px;
+    margin-bottom: 4px;
+    overflow: hidden;
+  }
+
+  :host([shopping]) .name {
     -webkit-box-orient: vertical;
     -webkit-line-clamp: 2;
-    color: var(--cr-primary-text-color);
     display: -webkit-box;
-    font-size: 12px;
     height: 40px;
-    line-height: 20px;
-    margin-bottom: 5px;
-    overflow: hidden;
+  }
+
+  :host([recipe]) .name {
+    text-overflow: ellipsis;
+    white-space: nowrap;
   }
 
   .info {
@@ -119,6 +142,7 @@
   }
 
   cr-dialog::part(dialog) {
+    position: fixed;
     width: 459px;
   }
 
@@ -131,23 +155,23 @@
     text-decoration: none;
   }
 </style>
-<div id="products">
-  <template is="dom-repeat" id="productsRepeat"
-      items="[[shoppingTask.products]]" on-dom-change="onDomChange_">
-    <a class="product" href="[[item.targetUrl.url]]" on-click="onProductClick_"
-        on-auxclick="onProductClick_">
+<div id="taskItems">
+  <template is="dom-repeat" id="taskItemsRepeat" items="[[task.taskItems]]"
+      on-dom-change="onDomChange_">
+    <a class="task-item" href="[[item.targetUrl.url]]"
+        on-click="onTaskItemClick_" on-auxclick="onTaskItemClick_">
       <div class="image">
         <img is="ntp-img" auto-src="[[item.imageUrl.url]]"></img>
       </div>
-      <div class="price">[[item.price]]</div>
-      <div class="name"  title="[[item.name]]">[[item.name]]</div>
+      <div class="price" hidden$="[[!item.price]]">[[item.price]]</div>
+      <div class="name" title="[[item.name]]">[[item.name]]</div>
       <div class="info">[[item.info]]</div>
     </a>
   </template>
 </div>
 <div id="relatedSearches">
   <template is="dom-repeat" id="relatedSearchesRepeat"
-      items="[[shoppingTask.relatedSearches]]" on-dom-change="onDomChange_">
+      items="[[task.relatedSearches]]" on-dom-change="onDomChange_">
     <a class="pill" href="[[item.targetUrl.url]]" on-click="onPillClick_"
         on-auxclick="onPillClick_">
       <div class="loupe"></div>
diff --git a/chrome/browser/resources/new_tab_page/modules/task_module/module.js b/chrome/browser/resources/new_tab_page/modules/task_module/module.js
new file mode 100644
index 0000000..58217b3
--- /dev/null
+++ b/chrome/browser/resources/new_tab_page/modules/task_module/module.js
@@ -0,0 +1,150 @@
+// 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 '../../img.js';
+import 'chrome://resources/cr_elements/hidden_style_css.m.js';
+
+import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
+import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {ModuleDescriptor} from '../module_descriptor.js';
+import {TaskModuleHandlerProxy} from './task_module_handler_proxy.js';
+
+/**
+ * @fileoverview Implements the UI of a task module. This module shows a
+ * currently active task search journey and provides a way for the user to
+ * continue that search journey.
+ */
+
+class TaskModuleElement extends PolymerElement {
+  static get is() {
+    return 'ntp-task-module';
+  }
+
+  static get template() {
+    return html`{__html_template__}`;
+  }
+
+  static get properties() {
+    return {
+      /** @type {!taskModule.mojom.TaskModuleType} */
+      taskModuleType: {
+        type: Number,
+        observer: 'onTaskModuleTypeChange_',
+      },
+
+      /** @type {!taskModule.mojom.Task} */
+      task: Object,
+
+      /** @type {boolean} */
+      showInfoDialog: Boolean,
+    };
+  }
+
+  constructor() {
+    super();
+    /** @type {IntersectionObserver} */
+    this.intersectionObserver_ = null;
+  }
+
+  /** @private */
+  onTaskModuleTypeChange_() {
+    switch (this.taskModuleType) {
+      case taskModule.mojom.TaskModuleType.kRecipe:
+        this.toggleAttribute('recipe');
+        break;
+      case taskModule.mojom.TaskModuleType.kShopping:
+        this.toggleAttribute('shopping');
+        break;
+    }
+  }
+
+  /**
+   * @param {!Event} e
+   * @private
+   */
+  onTaskItemClick_(e) {
+    const index = this.$.taskItemsRepeat.indexForElement(e.target);
+    TaskModuleHandlerProxy.getInstance().handler.onTaskItemClicked(
+        this.taskModuleType, index);
+    this.dispatchEvent(new Event('usage', {bubbles: true, composed: true}));
+  }
+
+  /**
+   * @param {!Event} e
+   * @private
+   */
+  onPillClick_(e) {
+    const index = this.$.relatedSearchesRepeat.indexForElement(e.target);
+    TaskModuleHandlerProxy.getInstance().handler.onRelatedSearchClicked(
+        this.taskModuleType, index);
+    this.dispatchEvent(new Event('usage', {bubbles: true, composed: true}));
+  }
+
+  /** @private */
+  onCloseClick_() {
+    this.showInfoDialog = false;
+  }
+
+  /** @private */
+  onDomChange_() {
+    if (!this.intersectionObserver_) {
+      this.intersectionObserver_ = new IntersectionObserver(entries => {
+        entries.forEach(({intersectionRatio, target}) => {
+          target.style.visibility =
+              intersectionRatio < 1 ? 'hidden' : 'visible';
+        });
+        this.dispatchEvent(new Event('visibility-update'));
+      }, {root: this, threshold: 1});
+    } else {
+      this.intersectionObserver_.disconnect();
+    }
+    this.shadowRoot.querySelectorAll('.task-item, .pill')
+        .forEach(el => this.intersectionObserver_.observe(el));
+  }
+}
+
+customElements.define(TaskModuleElement.is, TaskModuleElement);
+
+/** @return {!Promise<?{element: !HTMLElement, title: string}>} */
+async function createModule(taskModuleType) {
+  const {task} =
+      await TaskModuleHandlerProxy.getInstance().handler.getPrimaryTask(
+          taskModuleType);
+  if (!task) {
+    return null;
+  }
+  const element = new TaskModuleElement();
+  element.taskModuleType = taskModuleType;
+  element.task = task;
+  return {
+    element: element,
+    title: task.title,
+    actions: {
+      info: () => {
+        element.showInfoDialog = true;
+      },
+      dismiss: () => {
+        TaskModuleHandlerProxy.getInstance().handler.dismissTask(
+            taskModuleType, task.name);
+        return loadTimeData.getStringF('dismissModuleToastMessage', task.name);
+      },
+      restore: () => {
+        TaskModuleHandlerProxy.getInstance().handler.restoreTask(
+            taskModuleType, task.name);
+      },
+    },
+  };
+}
+
+/** @type {!ModuleDescriptor} */
+export const recipeTasksDescriptor = new ModuleDescriptor(
+    /*id=*/ 'recipe_tasks',
+    /*heightPx=*/ 206,
+    createModule.bind(null, taskModule.mojom.TaskModuleType.kRecipe));
+
+/** @type {!ModuleDescriptor} */
+export const shoppingTasksDescriptor = new ModuleDescriptor(
+    /*id=*/ 'shopping_tasks',
+    /*heightPx=*/ 270,
+    createModule.bind(null, taskModule.mojom.TaskModuleType.kShopping));
diff --git a/chrome/browser/resources/new_tab_page/modules/task_module/task_module_handler_proxy.js b/chrome/browser/resources/new_tab_page/modules/task_module/task_module_handler_proxy.js
new file mode 100644
index 0000000..2b45ab6
--- /dev/null
+++ b/chrome/browser/resources/new_tab_page/modules/task_module/task_module_handler_proxy.js
@@ -0,0 +1,21 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import './task_module.mojom-lite.js';
+
+import {addSingletonGetter} from 'chrome://resources/js/cr.m.js';
+
+/**
+ * @fileoverview This file provides a class that exposes the Mojo handler
+ * interface used for retrieving a shopping task for a task module.
+ */
+
+export class TaskModuleHandlerProxy {
+  constructor() {
+    /** @type {!taskModule.mojom.TaskModuleHandlerRemote} */
+    this.handler = taskModule.mojom.TaskModuleHandler.getRemote();
+  }
+}
+
+addSingletonGetter(TaskModuleHandlerProxy);
diff --git a/chrome/browser/resources/new_tab_page/new_tab_page.js b/chrome/browser/resources/new_tab_page/new_tab_page.js
index 61617ef..4f0b397 100644
--- a/chrome/browser/resources/new_tab_page/new_tab_page.js
+++ b/chrome/browser/resources/new_tab_page/new_tab_page.js
@@ -23,9 +23,7 @@
 export {kaleidoscopeDescriptor} from './modules/kaleidoscope/module.js';
 export {ModuleDescriptor} from './modules/module_descriptor.js';
 export {ModuleRegistry} from './modules/module_registry.js';
-export {recipeTasksDescriptor} from './modules/recipe_tasks/module.js';
-export {RecipeTasksHandlerProxy} from './modules/recipe_tasks/recipe_tasks_handler_proxy.js';
-export {shoppingTasksDescriptor} from './modules/shopping_tasks/module.js';
-export {ShoppingTasksHandlerProxy} from './modules/shopping_tasks/shopping_tasks_handler_proxy.js';
+export {recipeTasksDescriptor, shoppingTasksDescriptor} from './modules/task_module/module.js';
+export {TaskModuleHandlerProxy} from './modules/task_module/task_module_handler_proxy.js';
 export {PromoBrowserCommandProxy} from './promo_browser_command_proxy.js';
 export {$$, createScrollBorders, decodeString16, mojoString16} from './utils.js';
diff --git a/chrome/browser/resources/new_tab_page/new_tab_page_resources_common.grdp b/chrome/browser/resources/new_tab_page/new_tab_page_resources_common.grdp
index bab35c5..b8ab1c62 100644
--- a/chrome/browser/resources/new_tab_page/new_tab_page_resources_common.grdp
+++ b/chrome/browser/resources/new_tab_page/new_tab_page_resources_common.grdp
@@ -70,10 +70,7 @@
       file="one_google_bar_api.js" type="BINDATA" compress="false" />
   <include name="IDR_NEW_TAB_PAGE_PROMO_BROWSER_COMMAND_PROXY_JS"
       file="promo_browser_command_proxy.js" type="BINDATA" compress="false" />
-  <include name="IDR_NEW_TAB_PAGE_MODULES_RECIPE_TASKS_RECIPE_TASKS_MOJO_LITE_JS"
-      file="${root_gen_dir}/chrome/browser/search/recipe_tasks/recipe_tasks.mojom-lite.js"
-      use_base_dir="false" type="BINDATA" />
-  <include name="IDR_NEW_TAB_PAGE_MODULES_SHOPPING_TASKS_SHOPPING_TASKS_MOJO_LITE_JS"
-      file="${root_gen_dir}/chrome/browser/search/shopping_tasks/shopping_tasks.mojom-lite.js"
+  <include name="IDR_NEW_TAB_PAGE_MODULES_TASK_MODULE_TASK_MODULE_MOJO_LITE_JS"
+      file="${root_gen_dir}/chrome/browser/search/task_module/task_module.mojom-lite.js"
       use_base_dir="false" type="BINDATA" />
 </grit-part>
diff --git a/chrome/browser/resources/ntp4/incognito_tab.html b/chrome/browser/resources/ntp4/incognito_tab.html
index 8b181857..dfb7dd8 100644
--- a/chrome/browser/resources/ntp4/incognito_tab.html
+++ b/chrome/browser/resources/ntp4/incognito_tab.html
@@ -9,6 +9,7 @@
 <title>$i18n{title}</title>
 <meta name="viewport" content="width=device-width">
 <link id="incognitothemecss" rel="stylesheet">
+<script src="chrome://resources/js/assert.js"></script>
 <script src="chrome://resources/js/util.js"></script>
 <script>
 // Until themes can clear the cache, force-reload the theme stylesheet.
diff --git a/chrome/browser/resources/ntp4/new_tab.html b/chrome/browser/resources/ntp4/new_tab.html
index 2423932..9eccd0db 100644
--- a/chrome/browser/resources/ntp4/new_tab.html
+++ b/chrome/browser/resources/ntp4/new_tab.html
@@ -14,6 +14,7 @@
       content="user-scalable=no, width=device-width, maximum-scale=1.0">
 
 <link id="themecss" rel="stylesheet">
+<script src="../../../../ui/webui/resources/js/assert.js"></script>
 <script src="../../../../ui/webui/resources/js/util.js"></script>
 <script>
 // Until themes can clear the cache, force-reload the theme stylesheet.
diff --git a/chrome/browser/resources/predictors/predictors.html b/chrome/browser/resources/predictors/predictors.html
index 731baa20..d7f1f90d 100644
--- a/chrome/browser/resources/predictors/predictors.html
+++ b/chrome/browser/resources/predictors/predictors.html
@@ -17,6 +17,7 @@
   <script src="chrome://resources/js/cr/ui.js"></script>
   <script src="chrome://resources/js/cr/ui/focus_outline_manager.js"></script>
   <script src="chrome://resources/js/cr/ui/tabs.js"></script>
+  <script src="chrome://resources/js/assert.js"></script>
   <script src="chrome://resources/js/util.js"></script>
 </head>
 
diff --git a/chrome/browser/resources/sandbox_internals/sandbox_internals.html b/chrome/browser/resources/sandbox_internals/sandbox_internals.html
index 7aa201ed..f025889b 100644
--- a/chrome/browser/resources/sandbox_internals/sandbox_internals.html
+++ b/chrome/browser/resources/sandbox_internals/sandbox_internals.html
@@ -45,6 +45,7 @@
     <script src="chrome://resources/js/load_time_data.js"></script>
     <script src="chrome://sandbox/strings.js"></script>
 </if>
+    <script src="chrome://resources/js/assert.js"></script>
 <if expr="is_win">
     <script src="chrome://resources/js/promise_resolver.js"></script>
 </if>
diff --git a/chrome/browser/resources/settings/people_page/sync_browser_proxy.js b/chrome/browser/resources/settings/people_page/sync_browser_proxy.js
index 1524971..eb9e0ef99 100644
--- a/chrome/browser/resources/settings/people_page/sync_browser_proxy.js
+++ b/chrome/browser/resources/settings/people_page/sync_browser_proxy.js
@@ -57,7 +57,8 @@
   /**
    * The state of sync. This is the data structure sent back and forth between
    * C++ and JS. Its naming and structure is not optimal, but changing it would
-   * require changes to the C++ handler, which is already functional.
+   * require changes to the C++ handler, which is already functional. See
+   * PeopleHandler::PushSyncPrefs() for more details.
    * @typedef {{
    *   appsRegistered: boolean,
    *   appsSynced: boolean,
@@ -78,6 +79,8 @@
    *   paymentsIntegrationEnabled: boolean,
    *   preferencesRegistered: boolean,
    *   preferencesSynced: boolean,
+   *   readingListRegistered: boolean,
+   *   readingListSynced: boolean,
    *   setNewPassphrase: (boolean|undefined),
    *   syncAllDataTypes: boolean,
    *   tabsRegistered: boolean,
diff --git a/chrome/browser/resources/settings/people_page/sync_controls.html b/chrome/browser/resources/settings/people_page/sync_controls.html
index 6b4eaba..feecbaf6 100644
--- a/chrome/browser/resources/settings/people_page/sync_controls.html
+++ b/chrome/browser/resources/settings/people_page/sync_controls.html
@@ -117,6 +117,17 @@
         </cr-toggle>
       </div>
 
+      <div class="list-item" hidden="[[!syncPrefs.readingListRegistered]]">
+        <div id="readingListCheckboxLabel">
+          $i18n{readingListCheckboxLabel}
+        </div>
+        <cr-toggle checked="{{syncPrefs.readingListSynced}}"
+            on-change="onSingleSyncDataTypeChanged_"
+            disabled="[[syncPrefs.syncAllDataTypes]]"
+            aria-labelledby="readingListCheckboxLabel">
+        </cr-toggle>
+      </div>
+
       <div class="list-item" hidden="[[!syncPrefs.tabsRegistered]]">
         <div id="openTabsCheckboxLabel">
           $i18n{openTabsCheckboxLabel}
diff --git a/chrome/browser/resources/settings/people_page/sync_controls.js b/chrome/browser/resources/settings/people_page/sync_controls.js
index 8a60f0d3..663f8cda 100644
--- a/chrome/browser/resources/settings/people_page/sync_controls.js
+++ b/chrome/browser/resources/settings/people_page/sync_controls.js
@@ -17,6 +17,7 @@
   'typedUrlsSynced',
   'themesSynced',
   'bookmarksSynced',
+  'readingListSynced',
   'passwordsSynced',
   'tabsSynced',
   'paymentsIntegrationEnabled',
diff --git a/chrome/browser/resources/supervised_user_internals/supervised_user_internals.html b/chrome/browser/resources/supervised_user_internals/supervised_user_internals.html
index 809060b1..7fc662e 100644
--- a/chrome/browser/resources/supervised_user_internals/supervised_user_internals.html
+++ b/chrome/browser/resources/supervised_user_internals/supervised_user_internals.html
@@ -12,6 +12,7 @@
 <link rel="stylesheet" href="chrome://resources/css/list.css">
 <link rel="stylesheet" href="supervised_user_internals.css">
 <script src="chrome://resources/js/cr.js"></script>
+<script src="chrome://resources/js/assert.js"></script>
 <script src="chrome://resources/js/util.js"></script>
 </head>
 
diff --git a/chrome/browser/resources/sync_file_system_internals/main.html b/chrome/browser/resources/sync_file_system_internals/main.html
index f0c42da..e2fac40 100644
--- a/chrome/browser/resources/sync_file_system_internals/main.html
+++ b/chrome/browser/resources/sync_file_system_internals/main.html
@@ -10,6 +10,7 @@
 <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
 <link rel="stylesheet" href="main.css">
 
+<script src="chrome://resources/js/assert.js"></script>
 <script src="chrome://resources/js/util.js"></script>
 <script src="chrome://resources/js/cr.js"></script>
 <script src="chrome://resources/js/cr/event_target.js"></script>
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_reboot_dialog_controller_impl_browsertest_win.cc b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_reboot_dialog_controller_impl_browsertest_win.cc
index 926c41dc..d1951d9 100644
--- a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_reboot_dialog_controller_impl_browsertest_win.cc
+++ b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_reboot_dialog_controller_impl_browsertest_win.cc
@@ -78,7 +78,7 @@
   }
 
   Browser* CreateBrowserShowingUrl(const GURL& gurl) {
-    Browser* browser = new Browser(
+    Browser* browser = Browser::Create(
         Browser::CreateParams(ProfileManager::GetActiveUserProfile(), true));
     OpenPage(gurl, browser);
     browser->window()->Show();
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.cc b/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.cc
index 636701e..db6a166 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.cc
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.cc
@@ -431,8 +431,6 @@
   active_requests_.erase(request);
   active_timers_.erase(request);
   active_uploads_.erase(request);
-  received_malware_verdicts_.erase(request);
-  received_dlp_verdicts_.erase(request);
   received_connector_results_.erase(request);
 
   auto token_it = active_tokens_.find(request);
@@ -499,32 +497,6 @@
   }
 }
 
-void BinaryUploadService::RecordRequestMetrics(
-    Request* request,
-    Result result,
-    const DeepScanningClientResponse& response) {
-  RecordRequestMetrics(request, result);
-  if (response.has_malware_scan_verdict()) {
-    base::UmaHistogramBoolean("SafeBrowsingBinaryUploadRequest.MalwareResult",
-                              response.malware_scan_verdict().verdict() !=
-                                  MalwareDeepScanningVerdict::SCAN_FAILURE);
-    MalwareDeepScanningVerdict::Verdict verdict_count =
-        static_cast<MalwareDeepScanningVerdict::Verdict>(
-            MalwareDeepScanningVerdict_Verdict_Verdict_ARRAYSIZE);
-    base::UmaHistogramEnumeration(
-        IsAdvancedProtectionRequest(*request)
-            ? "SafeBrowsingBinaryUploadRequest.AdvancedProtectionScanVerdict"
-            : "SafeBrowsingBinaryUploadRequest.MalwareScanVerdict",
-        response.malware_scan_verdict().verdict(), verdict_count);
-  }
-
-  if (response.has_dlp_scan_verdict()) {
-    base::UmaHistogramBoolean("SafeBrowsingBinaryUploadRequest.DlpResult",
-                              response.dlp_scan_verdict().status() ==
-                                  DlpDeepScanningVerdict::SUCCESS);
-  }
-}
-
 BinaryUploadService::Request::Data::Data() = default;
 
 BinaryUploadService::Request::Request(ContentAnalysisCallback callback,
@@ -731,15 +703,6 @@
       (result == BinaryUploadService::Result::SUCCESS);
 }
 
-void BinaryUploadService::ValidateDataUploadRequestCallback(
-    enterprise_connectors::AnalysisConnector connector,
-    BinaryUploadService::Result result,
-    DeepScanningClientResponse response) {
-  pending_validate_data_upload_request_ = false;
-  can_upload_enterprise_data_[connector] =
-      (result == BinaryUploadService::Result::SUCCESS);
-}
-
 void BinaryUploadService::RunAuthorizationCallbacks(
     enterprise_connectors::AnalysisConnector connector) {
   DCHECK(can_upload_enterprise_data_.contains(connector));
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h b/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h
index d806304e..2ae27801 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h
@@ -84,13 +84,12 @@
 
   // Callbacks used to pass along the results of scanning. The response protos
   // will only be populated if the result is SUCCESS.
-  using Callback = base::OnceCallback<void(Result, DeepScanningClientResponse)>;
   using ContentAnalysisCallback =
       base::OnceCallback<void(Result,
                               enterprise_connectors::ContentAnalysisResponse)>;
 
   // A class to encapsulate the a request for upload. This class will provide
-  // all the functionality needed to generate a DeepScanningRequest, and
+  // all the functionality needed to generate a ContentAnalysisRequest, and
   // subclasses will provide different sources of data to upload (e.g. file or
   // string).
   class Request {
@@ -250,10 +249,6 @@
       enterprise_connectors::AnalysisConnector connector,
       BinaryUploadService::Result result,
       enterprise_connectors::ContentAnalysisResponse response);
-  void ValidateDataUploadRequestCallback(
-      enterprise_connectors::AnalysisConnector connector,
-      BinaryUploadService::Result result,
-      DeepScanningClientResponse response);
 
   // Callback once a request's instance ID is unregistered.
   void InstanceIDUnregisteredCallback(
@@ -265,9 +260,6 @@
       Request* request,
       Result result,
       const enterprise_connectors::ContentAnalysisResponse& response);
-  void RecordRequestMetrics(Request* request,
-                            Result result,
-                            const DeepScanningClientResponse& response);
 
   // Called at the end of the FinishRequest method.
   void FinishRequestCleanup(Request* request, const std::string& instance_id);
@@ -284,10 +276,6 @@
   base::flat_map<Request*, std::unique_ptr<MultipartUploadRequest>>
       active_uploads_;
   base::flat_map<Request*, std::string> active_tokens_;
-  base::flat_map<Request*, std::unique_ptr<MalwareDeepScanningVerdict>>
-      received_malware_verdicts_;
-  base::flat_map<Request*, std::unique_ptr<DlpDeepScanningVerdict>>
-      received_dlp_verdicts_;
 
   // Maps requests to each corresponding tag-result pairs.
   base::flat_map<
diff --git a/chrome/browser/search/recipe_tasks/recipe_tasks.mojom b/chrome/browser/search/recipe_tasks/recipe_tasks.mojom
deleted file mode 100644
index deb05eef..0000000
--- a/chrome/browser/search/recipe_tasks/recipe_tasks.mojom
+++ /dev/null
@@ -1,54 +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.
-
-module recipe_tasks.mojom;
-
-import "url/mojom/url.mojom";
-
-// A recipe of a recipe task.
-struct Recipe {
-  // Human-readable recipe name.
-  string name;
-  // URL to image of the recipe.
-  url.mojom.Url image_url;
-  // Human-readable recipe info.
-  string info;
-  // URL of the recipe target page.
-  url.mojom.Url target_url;
-};
-
-// A related search query.
-struct RelatedSearch {
-  // Text of the search query.
-  string text;
-  // URL of the query target page.
-  url.mojom.Url target_url;
-};
-
-// A recipe search journey that is currently active for the user.
-struct RecipeTask {
-  // Human-readable title.
-  string title;
-  // Human-readable name.
-  string name;
-  // Recipes associated with the task.
-  array<Recipe> recipes;
-  // Searches related to the task.
-  array<RelatedSearch> related_searches;
-};
-
-// Interface for handling requests from the recipe tasks module's JS code.
-// Bound to the NTP WebUI handler.
-interface RecipeTasksHandler {
-  // Returns the primary recipe task if available.
-  GetPrimaryRecipeTask() => (RecipeTask? recipe_task);
-  // Dismisses the task with the given name and remembers that setting.
-  DismissRecipeTask(string task_name);
-  // Restores the task with the given name and remembers that setting.
-  RestoreRecipeTask(string task_name);
-  // Logs that the recipe at position |index| has been clicked.
-  OnRecipeClicked(uint32 index);
-  // Logs that the related search pill at position |index| has been clicked.
-  OnRelatedSearchClicked(uint32 index);
-};
diff --git a/chrome/browser/search/recipe_tasks/recipe_tasks_handler.cc b/chrome/browser/search/recipe_tasks/recipe_tasks_handler.cc
deleted file mode 100644
index 1a8429b..0000000
--- a/chrome/browser/search/recipe_tasks/recipe_tasks_handler.cc
+++ /dev/null
@@ -1,43 +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 "chrome/browser/search/recipe_tasks/recipe_tasks_handler.h"
-
-#include "base/metrics/histogram_functions.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/search/recipe_tasks/recipe_tasks_service.h"
-#include "chrome/browser/search/recipe_tasks/recipe_tasks_service_factory.h"
-
-RecipeTasksHandler::RecipeTasksHandler(
-    mojo::PendingReceiver<recipe_tasks::mojom::RecipeTasksHandler>
-        pending_receiver,
-    Profile* profile)
-    : receiver_(this, std::move(pending_receiver)), profile_(profile) {}
-
-RecipeTasksHandler::~RecipeTasksHandler() = default;
-
-void RecipeTasksHandler::GetPrimaryRecipeTask(
-    GetPrimaryRecipeTaskCallback callback) {
-  RecipeTasksServiceFactory::GetForProfile(profile_)->GetPrimaryRecipeTask(
-      std::move(callback));
-}
-
-void RecipeTasksHandler::DismissRecipeTask(const std::string& task_name) {
-  RecipeTasksServiceFactory::GetForProfile(profile_)->DismissRecipeTask(
-      task_name);
-}
-
-void RecipeTasksHandler::RestoreRecipeTask(const std::string& task_name) {
-  RecipeTasksServiceFactory::GetForProfile(profile_)->RestoreRecipeTask(
-      task_name);
-}
-
-void RecipeTasksHandler::OnRecipeClicked(uint32_t index) {
-  base::UmaHistogramCounts100("NewTabPage.RecipeTasks.RecipeClick", index);
-}
-
-void RecipeTasksHandler::OnRelatedSearchClicked(uint32_t index) {
-  base::UmaHistogramCounts100("NewTabPage.RecipeTasks.RelatedSearchClick",
-                              index);
-}
diff --git a/chrome/browser/search/recipe_tasks/recipe_tasks_handler.h b/chrome/browser/search/recipe_tasks/recipe_tasks_handler.h
deleted file mode 100644
index 3962f7c..0000000
--- a/chrome/browser/search/recipe_tasks/recipe_tasks_handler.h
+++ /dev/null
@@ -1,37 +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 CHROME_BROWSER_SEARCH_RECIPE_TASKS_RECIPE_TASKS_HANDLER_H_
-#define CHROME_BROWSER_SEARCH_RECIPE_TASKS_RECIPE_TASKS_HANDLER_H_
-
-#include "chrome/browser/search/recipe_tasks/recipe_tasks.mojom.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-
-class Profile;
-
-// Implementation of the RecipeTasksHandler mojo interface that requests
-// recipe tasks from the RecipeTasksService. Instantiated by the NTP upon a
-// connection request by the recipe tasks module.
-class RecipeTasksHandler : public recipe_tasks::mojom::RecipeTasksHandler {
- public:
-  RecipeTasksHandler(
-      mojo::PendingReceiver<recipe_tasks::mojom::RecipeTasksHandler>
-          pending_receiver,
-      Profile* profile);
-  ~RecipeTasksHandler() override;
-
-  // recipe_tasks::mojom::RecipeTasksHandler:
-  void GetPrimaryRecipeTask(GetPrimaryRecipeTaskCallback callback) override;
-  void DismissRecipeTask(const std::string& task_name) override;
-  void RestoreRecipeTask(const std::string& task_name) override;
-  void OnRecipeClicked(uint32_t index) override;
-  void OnRelatedSearchClicked(uint32_t index) override;
-
- private:
-  mojo::Receiver<recipe_tasks::mojom::RecipeTasksHandler> receiver_;
-  Profile* profile_;
-};
-
-#endif  // CHROME_BROWSER_SEARCH_RECIPE_TASKS_RECIPE_TASKS_HANDLER_H_
diff --git a/chrome/browser/search/recipe_tasks/recipe_tasks_service.cc b/chrome/browser/search/recipe_tasks/recipe_tasks_service.cc
deleted file mode 100644
index 11b3283..0000000
--- a/chrome/browser/search/recipe_tasks/recipe_tasks_service.cc
+++ /dev/null
@@ -1,216 +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 "chrome/browser/search/recipe_tasks/recipe_tasks_service.h"
-
-#include "base/stl_util.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/common/webui_url_constants.h"
-#include "components/google/core/common/google_util.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/pref_service.h"
-#include "components/prefs/scoped_user_pref_update.h"
-#include "components/variations/net/variations_http_headers.h"
-#include "net/base/url_util.h"
-#include "services/network/public/cpp/resource_request.h"
-#include "services/network/public/cpp/shared_url_loader_factory.h"
-#include "services/network/public/cpp/simple_url_loader.h"
-
-namespace {
-const char kNewTabRecipeTasksApiPath[] = "/async/newtab_recipe_tasks";
-const char kXSSIResponsePreamble[] = ")]}'";
-const char kDismissedTasksPrefName[] = "NewTabPage.DismissedRecipeTasks";
-
-GURL GetApiUrl(const std::string& application_locale) {
-  GURL google_base_url = google_util::CommandLineGoogleBaseURL();
-  if (!google_base_url.is_valid()) {
-    google_base_url = GURL(google_util::kGoogleHomepageURL);
-  }
-  return net::AppendQueryParameter(
-      google_base_url.Resolve(kNewTabRecipeTasksApiPath), "hl",
-      application_locale);
-}
-}  // namespace
-
-RecipeTasksService::RecipeTasksService(
-    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-    Profile* profile,
-    const std::string& application_locale)
-    : profile_(profile),
-      url_loader_factory_(url_loader_factory),
-      application_locale_(application_locale) {}
-
-RecipeTasksService::~RecipeTasksService() = default;
-
-// static
-void RecipeTasksService::RegisterProfilePrefs(PrefRegistrySimple* registry) {
-  registry->RegisterListPref(kDismissedTasksPrefName);
-}
-
-void RecipeTasksService::Shutdown() {}
-
-void RecipeTasksService::GetPrimaryRecipeTask(RecipeTaskCallback callback) {
-  net::NetworkTrafficAnnotationTag traffic_annotation =
-      net::DefineNetworkTrafficAnnotation("recipe_tasks_service", R"(
-        semantics {
-          sender: "Recipe Tasks Service"
-          description: "This service downloads recipe tasks, which is "
-            "information related to the user's currently active recipe "
-            "search journeys such as visisted and recommended recipes. "
-            "Recipe tasks will be displayed on the new tab page to help the "
-            "user to continue their search journey. Recipe tasks are queried "
-            "on every new tab page load."
-          trigger:
-            "Displaying the new tab page on Desktop, if Google is the "
-            "configured search provider and the user is signed in."
-          data: "Credentials if user is signed in."
-          destination: GOOGLE_OWNED_SERVICE
-        }
-        policy {
-          cookies_allowed: YES
-          cookies_store: "user"
-          setting:
-            "Users can control this feature via selecting a non-Google default "
-            "search engine in Chrome settings under 'Search Engine' or by "
-            "signing out."
-          chrome_policy {
-            DefaultSearchProviderEnabled {
-              policy_options {mode: MANDATORY}
-              DefaultSearchProviderEnabled: false
-            }
-            BrowserSignin {
-              policy_options {mode: MANDATORY}
-              BrowserSignin: 0
-            }
-          }
-        })");
-
-  auto resource_request = std::make_unique<network::ResourceRequest>();
-  resource_request->url = GetApiUrl(application_locale_);
-  resource_request->credentials_mode =
-      network::mojom::CredentialsMode::kInclude;
-  resource_request->request_initiator =
-      url::Origin::Create(GURL(chrome::kChromeUINewTabURL));
-  variations::AppendVariationsHeaderUnknownSignedIn(
-      resource_request->url,
-      /* Modules are only shown in non-incognito. */
-      variations::InIncognito::kNo, resource_request.get());
-
-  loaders_.push_back(network::SimpleURLLoader::Create(
-      std::move(resource_request), traffic_annotation));
-  loaders_.back()->DownloadToString(
-      url_loader_factory_.get(),
-      base::BindOnce(&RecipeTasksService::OnDataLoaded,
-                     weak_ptr_factory_.GetWeakPtr(), loaders_.back().get(),
-                     std::move(callback)),
-      network::SimpleURLLoader::kMaxBoundedStringDownloadSize);
-}
-
-void RecipeTasksService::DismissRecipeTask(const std::string& task_name) {
-  ListPrefUpdate update(profile_->GetPrefs(), kDismissedTasksPrefName);
-  update->AppendIfNotPresent(std::make_unique<base::Value>(task_name));
-}
-
-void RecipeTasksService::RestoreRecipeTask(const std::string& task_name) {
-  ListPrefUpdate update(profile_->GetPrefs(), kDismissedTasksPrefName);
-  update->EraseListValue(base::Value(task_name));
-}
-
-void RecipeTasksService::OnDataLoaded(network::SimpleURLLoader* loader,
-                                      RecipeTaskCallback callback,
-                                      std::unique_ptr<std::string> response) {
-  auto net_error = loader->NetError();
-  base::EraseIf(loaders_, [loader](const auto& target) {
-    return loader == target.get();
-  });
-
-  if (net_error != net::OK || !response) {
-    std::move(callback).Run(nullptr);
-    return;
-  }
-
-  if (base::StartsWith(*response, kXSSIResponsePreamble,
-                       base::CompareCase::SENSITIVE)) {
-    *response = response->substr(strlen(kXSSIResponsePreamble));
-  }
-
-  data_decoder::DataDecoder::ParseJsonIsolated(
-      *response,
-      base::BindOnce(&RecipeTasksService::OnJsonParsed,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void RecipeTasksService::OnJsonParsed(
-    RecipeTaskCallback callback,
-    data_decoder::DataDecoder::ValueOrError result) {
-  if (!result.value) {
-    std::move(callback).Run(nullptr);
-    return;
-  }
-  // We receive a list of recipe tasks ordered from highest to lowest
-  // priority. We only support showing a single task though. Therefore, pick the
-  // first task.
-  auto* recipe_tasks = result.value->FindListPath("update.recipe_tasks");
-  if (!recipe_tasks || recipe_tasks->GetList().size() == 0) {
-    std::move(callback).Run(nullptr);
-    return;
-  }
-  for (const auto& recipe_task : recipe_tasks->GetList()) {
-    auto* title = recipe_task.FindStringPath("title");
-    auto* task_name = recipe_task.FindStringPath("task_name");
-    auto* recipes = recipe_task.FindListPath("recipes");
-    auto* related_searches = recipe_task.FindListPath("related_searches");
-    if (!title || !task_name || !recipes || !related_searches ||
-        recipes->GetList().size() == 0) {
-      continue;
-    }
-    if (IsRecipeTaskDismissed(*task_name)) {
-      continue;
-    }
-    std::vector<recipe_tasks::mojom::RecipePtr> mojo_recipes;
-    for (const auto& recipe : recipes->GetList()) {
-      auto* name = recipe.FindStringPath("name");
-      auto* image_url = recipe.FindStringPath("image_url");
-      auto* info = recipe.FindStringPath("info");
-      auto* target_url = recipe.FindStringPath("target_url");
-      if (!name || !image_url || !info || !target_url) {
-        continue;
-      }
-      auto mojo_recipe = recipe_tasks::mojom::Recipe::New();
-      mojo_recipe->name = *name;
-      mojo_recipe->image_url = GURL(*image_url);
-      mojo_recipe->info = *info;
-      mojo_recipe->target_url = GURL(*target_url);
-      mojo_recipes.push_back(std::move(mojo_recipe));
-    }
-    std::vector<recipe_tasks::mojom::RelatedSearchPtr> mojo_related_searches;
-    for (const auto& related_search : related_searches->GetList()) {
-      auto* text = related_search.FindStringPath("text");
-      auto* target_url = related_search.FindStringPath("target_url");
-      if (!text || !target_url) {
-        continue;
-      }
-      auto mojo_related_search = recipe_tasks::mojom::RelatedSearch::New();
-      mojo_related_search->text = *text;
-      mojo_related_search->target_url = GURL(*target_url);
-      mojo_related_searches.push_back(std::move(mojo_related_search));
-    }
-    auto mojo_recipe_task = recipe_tasks::mojom::RecipeTask::New();
-    mojo_recipe_task->title = *title;
-    mojo_recipe_task->name = *task_name;
-    mojo_recipe_task->recipes = std::move(mojo_recipes);
-    mojo_recipe_task->related_searches = std::move(mojo_related_searches);
-    std::move(callback).Run(std::move(mojo_recipe_task));
-    return;
-  }
-  std::move(callback).Run(nullptr);
-}
-
-bool RecipeTasksService::IsRecipeTaskDismissed(const std::string& task_name) {
-  const base::ListValue* dismissed_tasks =
-      profile_->GetPrefs()->GetList(kDismissedTasksPrefName);
-  DCHECK(dismissed_tasks);
-  return dismissed_tasks->Find(base::Value(task_name)) !=
-         dismissed_tasks->end();
-}
diff --git a/chrome/browser/search/recipe_tasks/recipe_tasks_service.h b/chrome/browser/search/recipe_tasks/recipe_tasks_service.h
deleted file mode 100644
index 1aad32b..0000000
--- a/chrome/browser/search/recipe_tasks/recipe_tasks_service.h
+++ /dev/null
@@ -1,70 +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 CHROME_BROWSER_SEARCH_RECIPE_TASKS_RECIPE_TASKS_SERVICE_H_
-#define CHROME_BROWSER_SEARCH_RECIPE_TASKS_RECIPE_TASKS_SERVICE_H_
-
-#include <list>
-#include <memory>
-
-#include "base/callback.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/memory/weak_ptr.h"
-#include "chrome/browser/search/recipe_tasks/recipe_tasks.mojom.h"
-#include "components/keyed_service/core/keyed_service.h"
-#include "services/data_decoder/public/cpp/data_decoder.h"
-
-class PrefRegistrySimple;
-class Profile;
-namespace network {
-class SharedURLLoaderFactory;
-class SimpleURLLoader;
-}  // namespace network
-
-// Downloads recipe tasks for current user from GWS.
-class RecipeTasksService : public KeyedService {
- public:
-  RecipeTasksService(
-      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-      Profile* profile,
-      const std::string& application_locale);
-  RecipeTasksService(const RecipeTasksService&) = delete;
-  ~RecipeTasksService() override;
-
-  static void RegisterProfilePrefs(PrefRegistrySimple* registry);
-
-  // KeyedService:
-  void Shutdown() override;
-
-  using RecipeTaskCallback =
-      base::OnceCallback<void(recipe_tasks::mojom::RecipeTaskPtr recipe_task)>;
-  // Downloads and parses recipe tasks and calls |callback| when done.
-  // On success |callback| is called with a populated |RecipeTasksData| object
-  // of the first recipe task which has not been dismissed. On failure, it is
-  // called with nullptr.
-  void GetPrimaryRecipeTask(RecipeTaskCallback callback);
-  // Dismisses the task with the given name and remembers that setting.
-  void DismissRecipeTask(const std::string& task_name);
-  // Restores the task with the given name and remembers that setting.
-  void RestoreRecipeTask(const std::string& task_name);
-
- private:
-  void OnDataLoaded(network::SimpleURLLoader* loader,
-                    RecipeTaskCallback callback,
-                    std::unique_ptr<std::string> response);
-  void OnJsonParsed(RecipeTaskCallback callback,
-                    data_decoder::DataDecoder::ValueOrError result);
-
-  // Returns whether a task with the given name has been dismissed.
-  bool IsRecipeTaskDismissed(const std::string& task_name);
-
-  Profile* profile_;
-  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
-  std::list<std::unique_ptr<network::SimpleURLLoader>> loaders_;
-  std::string application_locale_;
-
-  base::WeakPtrFactory<RecipeTasksService> weak_ptr_factory_{this};
-};
-
-#endif  // CHROME_BROWSER_SEARCH_RECIPE_TASKS_RECIPE_TASKS_SERVICE_H_
diff --git a/chrome/browser/search/recipe_tasks/recipe_tasks_service_factory.cc b/chrome/browser/search/recipe_tasks/recipe_tasks_service_factory.cc
deleted file mode 100644
index 2b3f6243..0000000
--- a/chrome/browser/search/recipe_tasks/recipe_tasks_service_factory.cc
+++ /dev/null
@@ -1,43 +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 "chrome/browser/search/recipe_tasks/recipe_tasks_service_factory.h"
-
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/content_settings/cookie_settings_factory.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/search/recipe_tasks/recipe_tasks_service.h"
-#include "components/keyed_service/content/browser_context_dependency_manager.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/storage_partition.h"
-
-// static
-RecipeTasksService* RecipeTasksServiceFactory::GetForProfile(Profile* profile) {
-  return static_cast<RecipeTasksService*>(
-      GetInstance()->GetServiceForBrowserContext(profile, true));
-}
-
-// static
-RecipeTasksServiceFactory* RecipeTasksServiceFactory::GetInstance() {
-  return base::Singleton<RecipeTasksServiceFactory>::get();
-}
-
-RecipeTasksServiceFactory::RecipeTasksServiceFactory()
-    : BrowserContextKeyedServiceFactory(
-          "RecipeTasksService",
-          BrowserContextDependencyManager::GetInstance()) {
-  DependsOn(CookieSettingsFactory::GetInstance());
-}
-
-RecipeTasksServiceFactory::~RecipeTasksServiceFactory() = default;
-
-KeyedService* RecipeTasksServiceFactory::BuildServiceInstanceFor(
-    content::BrowserContext* context) const {
-  auto url_loader_factory =
-      content::BrowserContext::GetDefaultStoragePartition(context)
-          ->GetURLLoaderFactoryForBrowserProcess();
-  return new RecipeTasksService(url_loader_factory,
-                                Profile::FromBrowserContext(context),
-                                g_browser_process->GetApplicationLocale());
-}
diff --git a/chrome/browser/search/recipe_tasks/recipe_tasks_service_factory.h b/chrome/browser/search/recipe_tasks/recipe_tasks_service_factory.h
deleted file mode 100644
index ff15a3b..0000000
--- a/chrome/browser/search/recipe_tasks/recipe_tasks_service_factory.h
+++ /dev/null
@@ -1,33 +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 CHROME_BROWSER_SEARCH_RECIPE_TASKS_RECIPE_TASKS_SERVICE_FACTORY_H_
-#define CHROME_BROWSER_SEARCH_RECIPE_TASKS_RECIPE_TASKS_SERVICE_FACTORY_H_
-
-#include "base/memory/singleton.h"
-#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
-
-class Profile;
-class RecipeTasksService;
-
-// Factory to access the recipe task service for the current profile.
-class RecipeTasksServiceFactory : public BrowserContextKeyedServiceFactory {
- public:
-  static RecipeTasksService* GetForProfile(Profile* profile);
-  static RecipeTasksServiceFactory* GetInstance();
-
-  RecipeTasksServiceFactory(const RecipeTasksServiceFactory&) = delete;
-
- private:
-  friend struct base::DefaultSingletonTraits<RecipeTasksServiceFactory>;
-
-  RecipeTasksServiceFactory();
-  ~RecipeTasksServiceFactory() override;
-
-  // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
-      content::BrowserContext* profile) const override;
-};
-
-#endif  // CHROME_BROWSER_SEARCH_RECIPE_TASKS_RECIPE_TASKS_SERVICE_FACTORY_H_
diff --git a/chrome/browser/search/recipe_tasks/recipe_tasks_service_unittest.cc b/chrome/browser/search/recipe_tasks/recipe_tasks_service_unittest.cc
deleted file mode 100644
index adfe25e..0000000
--- a/chrome/browser/search/recipe_tasks/recipe_tasks_service_unittest.cc
+++ /dev/null
@@ -1,377 +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 <memory>
-
-#include "base/memory/scoped_refptr.h"
-#include "base/test/bind_test_util.h"
-#include "base/test/mock_callback.h"
-#include "chrome/browser/search/recipe_tasks/recipe_tasks_service.h"
-#include "chrome/test/base/testing_profile.h"
-#include "content/public/test/browser_task_environment.h"
-#include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
-#include "services/network/public/cpp/shared_url_loader_factory.h"
-#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
-#include "services/network/test/test_url_loader_factory.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-class RecipeTasksServiceTest : public testing::Test {
- public:
-  RecipeTasksServiceTest()
-      : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP) {}
-
-  void SetUp() override {
-    testing::Test::SetUp();
-
-    service_ = std::make_unique<RecipeTasksService>(
-        base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
-            &test_url_loader_factory_),
-        &profile_, "en-US");
-  }
-
-  void TearDown() override {
-    service_.reset();
-    test_url_loader_factory_.ClearResponses();
-  }
-
- protected:
-  // Required to run tests from UI thread.
-  content::BrowserTaskEnvironment task_environment_;
-  TestingProfile profile_;
-  network::TestURLLoaderFactory test_url_loader_factory_;
-  data_decoder::test::InProcessDataDecoder in_process_data_decoder_;
-  scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_;
-  std::unique_ptr<RecipeTasksService> service_;
-};
-
-// Verifies correct parsing of well-formed JSON.
-TEST_F(RecipeTasksServiceTest, GoodResponse) {
-  test_url_loader_factory_.AddResponse(
-      "https://www.google.com/async/newtab_recipe_tasks?hl=en-US",
-      R"()]}'
-{
-  "update": {
-    "recipe_tasks": [
-      {
-        "title": "hello world",
-        "task_name": "hello world",
-        "recipes": [
-          {
-            "name": "foo",
-            "image_url": "https://foo.com",
-            "info": "visited 5 days ago",
-            "target_url": "https://google.com/foo"
-          },{
-            "name": "bar",
-            "image_url": "https://bar.com",
-            "info": "visited 1 day ago",
-            "target_url": "https://google.com/bar"
-          }
-        ],
-        "related_searches": [
-          {
-            "text": "baz",
-            "target_url": "https://google.com/baz"
-          },
-          {
-            "text": "blub",
-            "target_url": "https://google.com/blub"
-          }
-        ]
-      }
-    ]
-  }
-})");
-
-  recipe_tasks::mojom::RecipeTaskPtr result;
-  base::MockCallback<RecipeTasksService::RecipeTaskCallback> callback;
-  EXPECT_CALL(callback, Run(testing::_))
-      .Times(1)
-      .WillOnce(
-          testing::Invoke([&result](recipe_tasks::mojom::RecipeTaskPtr arg) {
-            result = std::move(arg);
-          }));
-
-  service_->GetPrimaryRecipeTask(callback.Get());
-  base::RunLoop().RunUntilIdle();
-
-  ASSERT_TRUE(result);
-  EXPECT_EQ("hello world", result->title);
-  EXPECT_EQ(2ul, result->recipes.size());
-  EXPECT_EQ(2ul, result->related_searches.size());
-  EXPECT_EQ("foo", result->recipes[0]->name);
-  EXPECT_EQ("https://foo.com/", result->recipes[0]->image_url.spec());
-  EXPECT_EQ("visited 5 days ago", result->recipes[0]->info);
-  EXPECT_EQ("https://google.com/bar", result->recipes[1]->target_url.spec());
-  EXPECT_EQ("bar", result->recipes[1]->name);
-  EXPECT_EQ("https://bar.com/", result->recipes[1]->image_url.spec());
-  EXPECT_EQ("visited 1 day ago", result->recipes[1]->info);
-  EXPECT_EQ("https://google.com/bar", result->recipes[1]->target_url.spec());
-  EXPECT_EQ("baz", result->related_searches[0]->text);
-  EXPECT_EQ("https://google.com/baz",
-            result->related_searches[0]->target_url.spec());
-  EXPECT_EQ("blub", result->related_searches[1]->text);
-  EXPECT_EQ("https://google.com/blub",
-            result->related_searches[1]->target_url.spec());
-}
-
-// Verifies service can handle multiple in flight requests.
-TEST_F(RecipeTasksServiceTest, MultiRequest) {
-  test_url_loader_factory_.AddResponse(
-      "https://www.google.com/async/newtab_recipe_tasks?hl=en-US",
-      R"()]}'
-{
-  "update": {
-    "recipe_tasks": [
-      {
-        "title": "hello world",
-        "task_name": "hello world",
-        "recipes": [
-          {
-            "name": "foo",
-            "image_url": "https://foo.com",
-            "info": "visited 5 days ago",
-            "target_url": "https://google.com/foo"
-          }
-        ],
-        "related_searches": [
-          {
-            "text": "baz",
-            "target_url": "https://google.com/baz"
-          }
-        ]
-      }
-    ]
-  }
-})");
-
-  recipe_tasks::mojom::RecipeTaskPtr result1;
-  base::MockCallback<RecipeTasksService::RecipeTaskCallback> callback1;
-  EXPECT_CALL(callback1, Run(testing::_))
-      .Times(1)
-      .WillOnce(
-          testing::Invoke([&result1](recipe_tasks::mojom::RecipeTaskPtr arg) {
-            result1 = std::move(arg);
-          }));
-  service_->GetPrimaryRecipeTask(callback1.Get());
-
-  recipe_tasks::mojom::RecipeTaskPtr result2;
-  base::MockCallback<RecipeTasksService::RecipeTaskCallback> callback2;
-  EXPECT_CALL(callback2, Run(testing::_))
-      .Times(1)
-      .WillOnce(
-          testing::Invoke([&result2](recipe_tasks::mojom::RecipeTaskPtr arg) {
-            result2 = std::move(arg);
-          }));
-  service_->GetPrimaryRecipeTask(callback2.Get());
-
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_TRUE(result1);
-  EXPECT_TRUE(result2);
-}
-
-// Verifies error if JSON is malformed.
-TEST_F(RecipeTasksServiceTest, BadResponse) {
-  test_url_loader_factory_.AddResponse(
-      "https://www.google.com/async/newtab_recipe_tasks?hl=en-US",
-      ")]}'{\"update\":{\"promotions\":{}}}");
-
-  recipe_tasks::mojom::RecipeTaskPtr result;
-  base::MockCallback<RecipeTasksService::RecipeTaskCallback> callback;
-  EXPECT_CALL(callback, Run(testing::_))
-      .Times(1)
-      .WillOnce(
-          testing::Invoke([&result](recipe_tasks::mojom::RecipeTaskPtr arg) {
-            result = std::move(arg);
-          }));
-
-  service_->GetPrimaryRecipeTask(callback.Get());
-  base::RunLoop().RunUntilIdle();
-
-  ASSERT_FALSE(result);
-}
-
-// Verifies error if no recipes.
-TEST_F(RecipeTasksServiceTest, NoRecipes) {
-  test_url_loader_factory_.AddResponse(
-      "https://www.google.com/async/newtab_recipe_tasks?hl=en-US",
-      R"()]}'
-{
-  "update": {
-    "recipe_tasks": [
-      {
-        "title": "hello world",
-        "task_name": "hello world",
-        "recipes": [],
-        "related_searches": [
-          {
-            "text": "baz",
-            "target_url": "https://google.com/baz"
-          }
-        ]
-      }
-    ]
-  }
-})");
-
-  recipe_tasks::mojom::RecipeTaskPtr result;
-  base::MockCallback<RecipeTasksService::RecipeTaskCallback> callback;
-  EXPECT_CALL(callback, Run(testing::_))
-      .Times(1)
-      .WillOnce(
-          testing::Invoke([&result](recipe_tasks::mojom::RecipeTaskPtr arg) {
-            result = std::move(arg);
-          }));
-
-  service_->GetPrimaryRecipeTask(callback.Get());
-  base::RunLoop().RunUntilIdle();
-
-  ASSERT_FALSE(result);
-}
-
-// Verifies error if download fails.
-TEST_F(RecipeTasksServiceTest, ErrorResponse) {
-  test_url_loader_factory_.AddResponse(
-      GURL("https://www.google.com/async/newtab_recipe_tasks?hl=en-US"),
-      network::mojom::URLResponseHead::New(), std::string(),
-      network::URLLoaderCompletionStatus(net::HTTP_NOT_FOUND));
-
-  recipe_tasks::mojom::RecipeTaskPtr result;
-  base::MockCallback<RecipeTasksService::RecipeTaskCallback> callback;
-  EXPECT_CALL(callback, Run(testing::_))
-      .Times(1)
-      .WillOnce(
-          testing::Invoke([&result](recipe_tasks::mojom::RecipeTaskPtr arg) {
-            result = std::move(arg);
-          }));
-
-  service_->GetPrimaryRecipeTask(callback.Get());
-  base::RunLoop().RunUntilIdle();
-
-  ASSERT_FALSE(result);
-}
-
-// Verifies recipe tasks can be dismissed and restored and that the service
-// remembers not to return dismissed tasks.
-TEST_F(RecipeTasksServiceTest, DismissTasks) {
-  test_url_loader_factory_.AddResponse(
-      "https://www.google.com/async/newtab_recipe_tasks?hl=en-US",
-      R"()]}'
-{
-  "update": {
-    "recipe_tasks": [
-      {
-        "title": "task 1 title",
-        "task_name": "task 1 name",
-        "recipes": [
-          {
-            "name": "foo",
-            "image_url": "https://foo.com",
-            "info": "visited 5 days ago",
-            "target_url": "https://google.com/foo"
-          }
-        ],
-        "related_searches": [
-          {
-            "text": "baz",
-            "target_url": "https://google.com/baz"
-          }
-        ]
-      },
-      {
-        "title": "task 2 title",
-        "task_name": "task 2 name",
-        "recipes": [
-          {
-            "name": "foo",
-            "image_url": "https://foo.com",
-            "info": "visited 5 days ago",
-            "target_url": "https://google.com/foo"
-          }
-        ],
-        "related_searches": [
-          {
-            "text": "baz",
-            "target_url": "https://google.com/baz"
-          }
-        ]
-      }
-    ]
-  }
-})");
-
-  recipe_tasks::mojom::RecipeTaskPtr result1;
-  base::MockCallback<RecipeTasksService::RecipeTaskCallback> callback1;
-  EXPECT_CALL(callback1, Run(testing::_))
-      .Times(1)
-      .WillOnce(
-          testing::Invoke([&result1](recipe_tasks::mojom::RecipeTaskPtr arg) {
-            result1 = std::move(arg);
-          }));
-  service_->GetPrimaryRecipeTask(callback1.Get());
-  base::RunLoop().RunUntilIdle();
-  ASSERT_TRUE(result1);
-  EXPECT_EQ("task 1 name", result1->name);
-
-  service_->DismissRecipeTask("task 1 name");
-
-  recipe_tasks::mojom::RecipeTaskPtr result2;
-  base::MockCallback<RecipeTasksService::RecipeTaskCallback> callback2;
-  EXPECT_CALL(callback2, Run(testing::_))
-      .Times(1)
-      .WillOnce(
-          testing::Invoke([&result2](recipe_tasks::mojom::RecipeTaskPtr arg) {
-            result2 = std::move(arg);
-          }));
-  service_->GetPrimaryRecipeTask(callback2.Get());
-  base::RunLoop().RunUntilIdle();
-  ASSERT_TRUE(result2);
-  EXPECT_EQ("task 2 name", result2->name);
-
-  service_->DismissRecipeTask("task 2 name");
-
-  recipe_tasks::mojom::RecipeTaskPtr result3;
-  base::MockCallback<RecipeTasksService::RecipeTaskCallback> callback3;
-  EXPECT_CALL(callback3, Run(testing::_))
-      .Times(1)
-      .WillOnce(
-          testing::Invoke([&result3](recipe_tasks::mojom::RecipeTaskPtr arg) {
-            result3 = std::move(arg);
-          }));
-  service_->GetPrimaryRecipeTask(callback3.Get());
-  base::RunLoop().RunUntilIdle();
-  ASSERT_FALSE(result3);
-
-  service_->RestoreRecipeTask("task 2 name");
-
-  recipe_tasks::mojom::RecipeTaskPtr result4;
-  base::MockCallback<RecipeTasksService::RecipeTaskCallback> callback4;
-  EXPECT_CALL(callback4, Run(testing::_))
-      .Times(1)
-      .WillOnce(
-          testing::Invoke([&result4](recipe_tasks::mojom::RecipeTaskPtr arg) {
-            result4 = std::move(arg);
-          }));
-  service_->GetPrimaryRecipeTask(callback4.Get());
-  base::RunLoop().RunUntilIdle();
-  ASSERT_TRUE(result4);
-  EXPECT_EQ("task 2 name", result4->name);
-
-  service_->RestoreRecipeTask("task 1 name");
-
-  recipe_tasks::mojom::RecipeTaskPtr result5;
-  base::MockCallback<RecipeTasksService::RecipeTaskCallback> callback5;
-  EXPECT_CALL(callback5, Run(testing::_))
-      .Times(1)
-      .WillOnce(
-          testing::Invoke([&result5](recipe_tasks::mojom::RecipeTaskPtr arg) {
-            result5 = std::move(arg);
-          }));
-  service_->GetPrimaryRecipeTask(callback5.Get());
-  base::RunLoop().RunUntilIdle();
-  ASSERT_TRUE(result5);
-  EXPECT_EQ("task 1 name", result5->name);
-}
diff --git a/chrome/browser/search/shopping_tasks/BUILD.gn b/chrome/browser/search/shopping_tasks/BUILD.gn
deleted file mode 100644
index 8448abe..0000000
--- a/chrome/browser/search/shopping_tasks/BUILD.gn
+++ /dev/null
@@ -1,10 +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.
-
-import("//mojo/public/tools/bindings/mojom.gni")
-
-mojom("mojo_bindings") {
-  sources = [ "shopping_tasks.mojom" ]
-  public_deps = [ "//url/mojom:url_mojom_gurl" ]
-}
diff --git a/chrome/browser/search/shopping_tasks/OWNERS b/chrome/browser/search/shopping_tasks/OWNERS
deleted file mode 100644
index 08850f4..0000000
--- a/chrome/browser/search/shopping_tasks/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chrome/browser/search/shopping_tasks/shopping_tasks.mojom b/chrome/browser/search/shopping_tasks/shopping_tasks.mojom
deleted file mode 100644
index fb708bc..0000000
--- a/chrome/browser/search/shopping_tasks/shopping_tasks.mojom
+++ /dev/null
@@ -1,56 +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.
-
-module shopping_tasks.mojom;
-
-import "url/mojom/url.mojom";
-
-// A product of a shopping task.
-struct Product {
-  // Human-readable product name.
-  string name;
-  // URL to image of the product.
-  url.mojom.Url image_url;
-  // Human-readable product price.
-  string price;
-  // Human-readable product info.
-  string info;
-  // URL of the product target page.
-  url.mojom.Url target_url;
-};
-
-// A related search query.
-struct RelatedSearch {
-  // Text of the search query.
-  string text;
-  // URL of the query target page.
-  url.mojom.Url target_url;
-};
-
-// A shopping search journey that is currently active for the user.
-struct ShoppingTask {
-  // Human-readable title.
-  string title;
-  // Human-readable name.
-  string name;
-  // Products associated with the task.
-  array<Product> products;
-  // Searches related to the task.
-  array<RelatedSearch> related_searches;
-};
-
-// Interface for handling requests from the shopping tasks module's JS code.
-// Bound to the NTP WebUI handler.
-interface ShoppingTasksHandler {
-  // Returns the primary shopping task if available.
-  GetPrimaryShoppingTask() => (ShoppingTask? shopping_task);
-  // Dismisses the task with the given name and remembers that setting.
-  DismissShoppingTask(string task_name);
-  // Restores the task with the given name and remembers that setting.
-  RestoreShoppingTask(string task_name);
-  // Logs that the product at position |index| has been clicked.
-  OnProductClicked(uint32 index);
-  // Logs that the related search pill at position |index| has been clicked.
-  OnRelatedSearchClicked(uint32 index);
-};
diff --git a/chrome/browser/search/shopping_tasks/shopping_tasks_handler.cc b/chrome/browser/search/shopping_tasks/shopping_tasks_handler.cc
deleted file mode 100644
index bcb18ce..0000000
--- a/chrome/browser/search/shopping_tasks/shopping_tasks_handler.cc
+++ /dev/null
@@ -1,43 +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 "chrome/browser/search/shopping_tasks/shopping_tasks_handler.h"
-
-#include "base/metrics/histogram_functions.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/search/shopping_tasks/shopping_tasks_service.h"
-#include "chrome/browser/search/shopping_tasks/shopping_tasks_service_factory.h"
-
-ShoppingTasksHandler::ShoppingTasksHandler(
-    mojo::PendingReceiver<shopping_tasks::mojom::ShoppingTasksHandler>
-        pending_receiver,
-    Profile* profile)
-    : receiver_(this, std::move(pending_receiver)), profile_(profile) {}
-
-ShoppingTasksHandler::~ShoppingTasksHandler() = default;
-
-void ShoppingTasksHandler::GetPrimaryShoppingTask(
-    GetPrimaryShoppingTaskCallback callback) {
-  ShoppingTasksServiceFactory::GetForProfile(profile_)->GetPrimaryShoppingTask(
-      std::move(callback));
-}
-
-void ShoppingTasksHandler::DismissShoppingTask(const std::string& task_name) {
-  ShoppingTasksServiceFactory::GetForProfile(profile_)->DismissShoppingTask(
-      task_name);
-}
-
-void ShoppingTasksHandler::RestoreShoppingTask(const std::string& task_name) {
-  ShoppingTasksServiceFactory::GetForProfile(profile_)->RestoreShoppingTask(
-      task_name);
-}
-
-void ShoppingTasksHandler::OnProductClicked(uint32_t index) {
-  base::UmaHistogramCounts100("NewTabPage.ShoppingTasks.ProductClick", index);
-}
-
-void ShoppingTasksHandler::OnRelatedSearchClicked(uint32_t index) {
-  base::UmaHistogramCounts100("NewTabPage.ShoppingTasks.RelatedSearchClick",
-                              index);
-}
diff --git a/chrome/browser/search/shopping_tasks/shopping_tasks_handler.h b/chrome/browser/search/shopping_tasks/shopping_tasks_handler.h
deleted file mode 100644
index 843bf7ec..0000000
--- a/chrome/browser/search/shopping_tasks/shopping_tasks_handler.h
+++ /dev/null
@@ -1,38 +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 CHROME_BROWSER_SEARCH_SHOPPING_TASKS_SHOPPING_TASKS_HANDLER_H_
-#define CHROME_BROWSER_SEARCH_SHOPPING_TASKS_SHOPPING_TASKS_HANDLER_H_
-
-#include "chrome/browser/search/shopping_tasks/shopping_tasks.mojom.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-
-class Profile;
-
-// Implementation of the ShoppingTasksHandler mojo interface that requests
-// shopping tasks from the ShoppingTasksService. Instantiated by the NTP upon a
-// connection request by the shopping tasks module.
-class ShoppingTasksHandler
-    : public shopping_tasks::mojom::ShoppingTasksHandler {
- public:
-  ShoppingTasksHandler(
-      mojo::PendingReceiver<shopping_tasks::mojom::ShoppingTasksHandler>
-          pending_receiver,
-      Profile* profile);
-  ~ShoppingTasksHandler() override;
-
-  // shopping_tasks::mojom::ShoppingTasksHandler:
-  void GetPrimaryShoppingTask(GetPrimaryShoppingTaskCallback callback) override;
-  void DismissShoppingTask(const std::string& task_name) override;
-  void RestoreShoppingTask(const std::string& task_name) override;
-  void OnProductClicked(uint32_t index) override;
-  void OnRelatedSearchClicked(uint32_t index) override;
-
- private:
-  mojo::Receiver<shopping_tasks::mojom::ShoppingTasksHandler> receiver_;
-  Profile* profile_;
-};
-
-#endif  // CHROME_BROWSER_SEARCH_SHOPPING_TASKS_SHOPPING_TASKS_HANDLER_H_
diff --git a/chrome/browser/search/shopping_tasks/shopping_tasks_service.cc b/chrome/browser/search/shopping_tasks/shopping_tasks_service.cc
deleted file mode 100644
index 9ec5d65..0000000
--- a/chrome/browser/search/shopping_tasks/shopping_tasks_service.cc
+++ /dev/null
@@ -1,220 +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 "chrome/browser/search/shopping_tasks/shopping_tasks_service.h"
-
-#include "base/stl_util.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/common/webui_url_constants.h"
-#include "components/google/core/common/google_util.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/pref_service.h"
-#include "components/prefs/scoped_user_pref_update.h"
-#include "components/variations/net/variations_http_headers.h"
-#include "net/base/url_util.h"
-#include "services/network/public/cpp/resource_request.h"
-#include "services/network/public/cpp/shared_url_loader_factory.h"
-#include "services/network/public/cpp/simple_url_loader.h"
-
-namespace {
-const char kNewTabShoppingTasksApiPath[] = "/async/newtab_shopping_tasks";
-const char kXSSIResponsePreamble[] = ")]}'";
-const char kDismissedTasksPrefName[] = "NewTabPage.DismissedShoppingTasks";
-
-GURL GetApiUrl(const std::string& application_locale) {
-  GURL google_base_url = google_util::CommandLineGoogleBaseURL();
-  if (!google_base_url.is_valid()) {
-    google_base_url = GURL(google_util::kGoogleHomepageURL);
-  }
-  return net::AppendQueryParameter(
-      google_base_url.Resolve(kNewTabShoppingTasksApiPath), "hl",
-      application_locale);
-}
-}  // namespace
-
-ShoppingTasksService::ShoppingTasksService(
-    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-    Profile* profile,
-    const std::string& application_locale)
-    : profile_(profile),
-      url_loader_factory_(url_loader_factory),
-      application_locale_(application_locale) {}
-
-ShoppingTasksService::~ShoppingTasksService() = default;
-
-// static
-void ShoppingTasksService::RegisterProfilePrefs(PrefRegistrySimple* registry) {
-  registry->RegisterListPref(kDismissedTasksPrefName);
-}
-
-void ShoppingTasksService::Shutdown() {}
-
-void ShoppingTasksService::GetPrimaryShoppingTask(
-    ShoppingTaskCallback callback) {
-  net::NetworkTrafficAnnotationTag traffic_annotation =
-      net::DefineNetworkTrafficAnnotation("shopping_tasks_service", R"(
-        semantics {
-          sender: "Shopping Tasks Service"
-          description: "This service downloads shopping tasks, which is "
-            "information related to the user's currently active shopping "
-            "search journeys such as visisted and recommended products. "
-            "Shopping tasks will be displayed on the new tab page to help the "
-            "user to continue their search journey. Shopping tasks are queried "
-            "on every new tab page load."
-          trigger:
-            "Displaying the new tab page on Desktop, if Google is the "
-            "configured search provider and the user is signed in."
-          data: "Credentials if user is signed in."
-          destination: GOOGLE_OWNED_SERVICE
-        }
-        policy {
-          cookies_allowed: YES
-          cookies_store: "user"
-          setting:
-            "Users can control this feature via selecting a non-Google default "
-            "search engine in Chrome settings under 'Search Engine' or by "
-            "signing out."
-          chrome_policy {
-            DefaultSearchProviderEnabled {
-              policy_options {mode: MANDATORY}
-              DefaultSearchProviderEnabled: false
-            }
-            BrowserSignin {
-              policy_options {mode: MANDATORY}
-              BrowserSignin: 0
-            }
-          }
-        })");
-
-  auto resource_request = std::make_unique<network::ResourceRequest>();
-  resource_request->url = GetApiUrl(application_locale_);
-  resource_request->credentials_mode =
-      network::mojom::CredentialsMode::kInclude;
-  resource_request->request_initiator =
-      url::Origin::Create(GURL(chrome::kChromeUINewTabURL));
-  variations::AppendVariationsHeaderUnknownSignedIn(
-      resource_request->url,
-      /* Modules are only shown in non-incognito. */
-      variations::InIncognito::kNo, resource_request.get());
-
-  loaders_.push_back(network::SimpleURLLoader::Create(
-      std::move(resource_request), traffic_annotation));
-  loaders_.back()->DownloadToString(
-      url_loader_factory_.get(),
-      base::BindOnce(&ShoppingTasksService::OnDataLoaded,
-                     weak_ptr_factory_.GetWeakPtr(), loaders_.back().get(),
-                     std::move(callback)),
-      network::SimpleURLLoader::kMaxBoundedStringDownloadSize);
-}
-
-void ShoppingTasksService::DismissShoppingTask(const std::string& task_name) {
-  ListPrefUpdate update(profile_->GetPrefs(), kDismissedTasksPrefName);
-  update->AppendIfNotPresent(std::make_unique<base::Value>(task_name));
-}
-
-void ShoppingTasksService::RestoreShoppingTask(const std::string& task_name) {
-  ListPrefUpdate update(profile_->GetPrefs(), kDismissedTasksPrefName);
-  update->EraseListValue(base::Value(task_name));
-}
-
-void ShoppingTasksService::OnDataLoaded(network::SimpleURLLoader* loader,
-                                        ShoppingTaskCallback callback,
-                                        std::unique_ptr<std::string> response) {
-  auto net_error = loader->NetError();
-  base::EraseIf(loaders_, [loader](const auto& target) {
-    return loader == target.get();
-  });
-
-  if (net_error != net::OK || !response) {
-    std::move(callback).Run(nullptr);
-    return;
-  }
-
-  if (base::StartsWith(*response, kXSSIResponsePreamble,
-                       base::CompareCase::SENSITIVE)) {
-    *response = response->substr(strlen(kXSSIResponsePreamble));
-  }
-
-  data_decoder::DataDecoder::ParseJsonIsolated(
-      *response,
-      base::BindOnce(&ShoppingTasksService::OnJsonParsed,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void ShoppingTasksService::OnJsonParsed(
-    ShoppingTaskCallback callback,
-    data_decoder::DataDecoder::ValueOrError result) {
-  if (!result.value) {
-    std::move(callback).Run(nullptr);
-    return;
-  }
-  // We receive a list of shopping tasks ordered from highest to lowest
-  // priority. We only support showing a single task though. Therefore, pick the
-  // first task.
-  auto* shopping_tasks = result.value->FindListPath("update.shopping_tasks");
-  if (!shopping_tasks || shopping_tasks->GetList().size() == 0) {
-    std::move(callback).Run(nullptr);
-    return;
-  }
-  for (const auto& shopping_task : shopping_tasks->GetList()) {
-    auto* title = shopping_task.FindStringPath("title");
-    auto* task_name = shopping_task.FindStringPath("task_name");
-    auto* products = shopping_task.FindListPath("products");
-    auto* related_searches = shopping_task.FindListPath("related_searches");
-    if (!title || !task_name || !products || !related_searches ||
-        products->GetList().size() == 0) {
-      continue;
-    }
-    if (IsShoppingTaskDismissed(*task_name)) {
-      continue;
-    }
-    std::vector<shopping_tasks::mojom::ProductPtr> mojo_products;
-    for (const auto& product : products->GetList()) {
-      auto* name = product.FindStringPath("name");
-      auto* image_url = product.FindStringPath("image_url");
-      auto* price = product.FindStringPath("price");
-      auto* info = product.FindStringPath("info");
-      auto* target_url = product.FindStringPath("target_url");
-      if (!name || !image_url || !price || !info || !target_url) {
-        continue;
-      }
-      auto mojo_product = shopping_tasks::mojom::Product::New();
-      mojo_product->name = *name;
-      mojo_product->image_url = GURL(*image_url);
-      mojo_product->price = *price;
-      mojo_product->info = *info;
-      mojo_product->target_url = GURL(*target_url);
-      mojo_products.push_back(std::move(mojo_product));
-    }
-    std::vector<shopping_tasks::mojom::RelatedSearchPtr> mojo_related_searches;
-    for (const auto& related_search : related_searches->GetList()) {
-      auto* text = related_search.FindStringPath("text");
-      auto* target_url = related_search.FindStringPath("target_url");
-      if (!text || !target_url) {
-        continue;
-      }
-      auto mojo_related_search = shopping_tasks::mojom::RelatedSearch::New();
-      mojo_related_search->text = *text;
-      mojo_related_search->target_url = GURL(*target_url);
-      mojo_related_searches.push_back(std::move(mojo_related_search));
-    }
-    auto mojo_shopping_task = shopping_tasks::mojom::ShoppingTask::New();
-    mojo_shopping_task->title = *title;
-    mojo_shopping_task->name = *task_name;
-    mojo_shopping_task->products = std::move(mojo_products);
-    mojo_shopping_task->related_searches = std::move(mojo_related_searches);
-    std::move(callback).Run(std::move(mojo_shopping_task));
-    return;
-  }
-  std::move(callback).Run(nullptr);
-}
-
-bool ShoppingTasksService::IsShoppingTaskDismissed(
-    const std::string& task_name) {
-  const base::ListValue* dismissed_tasks =
-      profile_->GetPrefs()->GetList(kDismissedTasksPrefName);
-  DCHECK(dismissed_tasks);
-  return dismissed_tasks->Find(base::Value(task_name)) !=
-         dismissed_tasks->end();
-}
diff --git a/chrome/browser/search/shopping_tasks/shopping_tasks_service.h b/chrome/browser/search/shopping_tasks/shopping_tasks_service.h
deleted file mode 100644
index 14468297..0000000
--- a/chrome/browser/search/shopping_tasks/shopping_tasks_service.h
+++ /dev/null
@@ -1,70 +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 CHROME_BROWSER_SEARCH_SHOPPING_TASKS_SHOPPING_TASKS_SERVICE_H_
-#define CHROME_BROWSER_SEARCH_SHOPPING_TASKS_SHOPPING_TASKS_SERVICE_H_
-
-#include <list>
-#include <memory>
-
-#include "base/callback.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/memory/weak_ptr.h"
-#include "chrome/browser/search/shopping_tasks/shopping_tasks.mojom.h"
-#include "components/keyed_service/core/keyed_service.h"
-#include "services/data_decoder/public/cpp/data_decoder.h"
-
-class PrefRegistrySimple;
-class Profile;
-namespace network {
-class SharedURLLoaderFactory;
-class SimpleURLLoader;
-}  // namespace network
-
-// Downloads shopping tasks for current user from GWS.
-class ShoppingTasksService : public KeyedService {
- public:
-  ShoppingTasksService(
-      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-      Profile* profile,
-      const std::string& application_locale);
-  ShoppingTasksService(const ShoppingTasksService&) = delete;
-  ~ShoppingTasksService() override;
-
-  static void RegisterProfilePrefs(PrefRegistrySimple* registry);
-
-  // KeyedService:
-  void Shutdown() override;
-
-  using ShoppingTaskCallback = base::OnceCallback<void(
-      shopping_tasks::mojom::ShoppingTaskPtr shopping_task)>;
-  // Downloads and parses shopping tasks and calls |callback| when done.
-  // On success |callback| is called with a populated |ShoppingTasksData| object
-  // of the first shopping task which has not been dismissed. On failure, it is
-  // called with nullptr.
-  void GetPrimaryShoppingTask(ShoppingTaskCallback callback);
-  // Dismisses the task with the given name and remembers that setting.
-  void DismissShoppingTask(const std::string& task_name);
-  // Restores the task with the given name and remembers that setting.
-  void RestoreShoppingTask(const std::string& task_name);
-
- private:
-  void OnDataLoaded(network::SimpleURLLoader* loader,
-                    ShoppingTaskCallback callback,
-                    std::unique_ptr<std::string> response);
-  void OnJsonParsed(ShoppingTaskCallback callback,
-                    data_decoder::DataDecoder::ValueOrError result);
-
-  // Returns whether a task with the given name has been dismissed.
-  bool IsShoppingTaskDismissed(const std::string& task_name);
-
-  Profile* profile_;
-  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
-  std::list<std::unique_ptr<network::SimpleURLLoader>> loaders_;
-  std::string application_locale_;
-
-  base::WeakPtrFactory<ShoppingTasksService> weak_ptr_factory_{this};
-};
-
-#endif  // CHROME_BROWSER_SEARCH_SHOPPING_TASKS_SHOPPING_TASKS_SERVICE_H_
diff --git a/chrome/browser/search/shopping_tasks/shopping_tasks_service_factory.cc b/chrome/browser/search/shopping_tasks/shopping_tasks_service_factory.cc
deleted file mode 100644
index d5d4877..0000000
--- a/chrome/browser/search/shopping_tasks/shopping_tasks_service_factory.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/search/shopping_tasks/shopping_tasks_service_factory.h"
-
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/content_settings/cookie_settings_factory.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/search/shopping_tasks/shopping_tasks_service.h"
-#include "components/keyed_service/content/browser_context_dependency_manager.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/storage_partition.h"
-
-// static
-ShoppingTasksService* ShoppingTasksServiceFactory::GetForProfile(
-    Profile* profile) {
-  return static_cast<ShoppingTasksService*>(
-      GetInstance()->GetServiceForBrowserContext(profile, true));
-}
-
-// static
-ShoppingTasksServiceFactory* ShoppingTasksServiceFactory::GetInstance() {
-  return base::Singleton<ShoppingTasksServiceFactory>::get();
-}
-
-ShoppingTasksServiceFactory::ShoppingTasksServiceFactory()
-    : BrowserContextKeyedServiceFactory(
-          "ShoppingTasksService",
-          BrowserContextDependencyManager::GetInstance()) {
-  DependsOn(CookieSettingsFactory::GetInstance());
-}
-
-ShoppingTasksServiceFactory::~ShoppingTasksServiceFactory() = default;
-
-KeyedService* ShoppingTasksServiceFactory::BuildServiceInstanceFor(
-    content::BrowserContext* context) const {
-  auto url_loader_factory =
-      content::BrowserContext::GetDefaultStoragePartition(context)
-          ->GetURLLoaderFactoryForBrowserProcess();
-  return new ShoppingTasksService(url_loader_factory,
-                                  Profile::FromBrowserContext(context),
-                                  g_browser_process->GetApplicationLocale());
-}
diff --git a/chrome/browser/search/shopping_tasks/shopping_tasks_service_factory.h b/chrome/browser/search/shopping_tasks/shopping_tasks_service_factory.h
deleted file mode 100644
index 8f10f20..0000000
--- a/chrome/browser/search/shopping_tasks/shopping_tasks_service_factory.h
+++ /dev/null
@@ -1,33 +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 CHROME_BROWSER_SEARCH_SHOPPING_TASKS_SHOPPING_TASKS_SERVICE_FACTORY_H_
-#define CHROME_BROWSER_SEARCH_SHOPPING_TASKS_SHOPPING_TASKS_SERVICE_FACTORY_H_
-
-#include "base/memory/singleton.h"
-#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
-
-class Profile;
-class ShoppingTasksService;
-
-// Factory to access the shopping task service for the current profile.
-class ShoppingTasksServiceFactory : public BrowserContextKeyedServiceFactory {
- public:
-  static ShoppingTasksService* GetForProfile(Profile* profile);
-  static ShoppingTasksServiceFactory* GetInstance();
-
-  ShoppingTasksServiceFactory(const ShoppingTasksServiceFactory&) = delete;
-
- private:
-  friend struct base::DefaultSingletonTraits<ShoppingTasksServiceFactory>;
-
-  ShoppingTasksServiceFactory();
-  ~ShoppingTasksServiceFactory() override;
-
-  // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
-      content::BrowserContext* profile) const override;
-};
-
-#endif  // CHROME_BROWSER_SEARCH_SHOPPING_TASKS_SHOPPING_TASKS_SERVICE_FACTORY_H_
diff --git a/chrome/browser/search/shopping_tasks/shopping_tasks_service_unittest.cc b/chrome/browser/search/shopping_tasks/shopping_tasks_service_unittest.cc
deleted file mode 100644
index 8c76385..0000000
--- a/chrome/browser/search/shopping_tasks/shopping_tasks_service_unittest.cc
+++ /dev/null
@@ -1,384 +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 <memory>
-
-#include "base/memory/scoped_refptr.h"
-#include "base/test/bind_test_util.h"
-#include "base/test/mock_callback.h"
-#include "chrome/browser/search/shopping_tasks/shopping_tasks_service.h"
-#include "chrome/test/base/testing_profile.h"
-#include "content/public/test/browser_task_environment.h"
-#include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
-#include "services/network/public/cpp/shared_url_loader_factory.h"
-#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
-#include "services/network/test/test_url_loader_factory.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-class ShoppingTasksServiceTest : public testing::Test {
- public:
-  ShoppingTasksServiceTest()
-      : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP) {}
-
-  void SetUp() override {
-    testing::Test::SetUp();
-
-    service_ = std::make_unique<ShoppingTasksService>(
-        base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
-            &test_url_loader_factory_),
-        &profile_, "en-US");
-  }
-
-  void TearDown() override {
-    service_.reset();
-    test_url_loader_factory_.ClearResponses();
-  }
-
- protected:
-  // Required to run tests from UI thread.
-  content::BrowserTaskEnvironment task_environment_;
-  TestingProfile profile_;
-  network::TestURLLoaderFactory test_url_loader_factory_;
-  data_decoder::test::InProcessDataDecoder in_process_data_decoder_;
-  scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_;
-  std::unique_ptr<ShoppingTasksService> service_;
-};
-
-// Verifies correct parsing of well-formed JSON.
-TEST_F(ShoppingTasksServiceTest, GoodResponse) {
-  test_url_loader_factory_.AddResponse(
-      "https://www.google.com/async/newtab_shopping_tasks?hl=en-US",
-      R"()]}'
-{
-  "update": {
-    "shopping_tasks": [
-      {
-        "title": "hello world",
-        "task_name": "hello world",
-        "products": [
-          {
-            "name": "foo",
-            "image_url": "https://foo.com",
-            "price": "$500",
-            "info": "visited 5 days ago",
-            "target_url": "https://google.com/foo"
-          },{
-            "name": "bar",
-            "image_url": "https://bar.com",
-            "price": "$400",
-            "info": "visited 1 day ago",
-            "target_url": "https://google.com/bar"
-          }
-        ],
-        "related_searches": [
-          {
-            "text": "baz",
-            "target_url": "https://google.com/baz"
-          },
-          {
-            "text": "blub",
-            "target_url": "https://google.com/blub"
-          }
-        ]
-      }
-    ]
-  }
-})");
-
-  shopping_tasks::mojom::ShoppingTaskPtr result;
-  base::MockCallback<ShoppingTasksService::ShoppingTaskCallback> callback;
-  EXPECT_CALL(callback, Run(testing::_))
-      .Times(1)
-      .WillOnce(testing::Invoke(
-          [&result](shopping_tasks::mojom::ShoppingTaskPtr arg) {
-            result = std::move(arg);
-          }));
-
-  service_->GetPrimaryShoppingTask(callback.Get());
-  base::RunLoop().RunUntilIdle();
-
-  ASSERT_TRUE(result);
-  EXPECT_EQ("hello world", result->title);
-  EXPECT_EQ(2ul, result->products.size());
-  EXPECT_EQ(2ul, result->related_searches.size());
-  EXPECT_EQ("foo", result->products[0]->name);
-  EXPECT_EQ("https://foo.com/", result->products[0]->image_url.spec());
-  EXPECT_EQ("$500", result->products[0]->price);
-  EXPECT_EQ("visited 5 days ago", result->products[0]->info);
-  EXPECT_EQ("https://google.com/bar", result->products[1]->target_url.spec());
-  EXPECT_EQ("bar", result->products[1]->name);
-  EXPECT_EQ("https://bar.com/", result->products[1]->image_url.spec());
-  EXPECT_EQ("$400", result->products[1]->price);
-  EXPECT_EQ("visited 1 day ago", result->products[1]->info);
-  EXPECT_EQ("https://google.com/bar", result->products[1]->target_url.spec());
-  EXPECT_EQ("baz", result->related_searches[0]->text);
-  EXPECT_EQ("https://google.com/baz",
-            result->related_searches[0]->target_url.spec());
-  EXPECT_EQ("blub", result->related_searches[1]->text);
-  EXPECT_EQ("https://google.com/blub",
-            result->related_searches[1]->target_url.spec());
-}
-
-// Verifies service can handle multiple in flight requests.
-TEST_F(ShoppingTasksServiceTest, MultiRequest) {
-  test_url_loader_factory_.AddResponse(
-      "https://www.google.com/async/newtab_shopping_tasks?hl=en-US",
-      R"()]}'
-{
-  "update": {
-    "shopping_tasks": [
-      {
-        "title": "hello world",
-        "task_name": "hello world",
-        "products": [
-          {
-            "name": "foo",
-            "image_url": "https://foo.com",
-            "price": "$500",
-            "info": "visited 5 days ago",
-            "target_url": "https://google.com/foo"
-          }
-        ],
-        "related_searches": [
-          {
-            "text": "baz",
-            "target_url": "https://google.com/baz"
-          }
-        ]
-      }
-    ]
-  }
-})");
-
-  shopping_tasks::mojom::ShoppingTaskPtr result1;
-  base::MockCallback<ShoppingTasksService::ShoppingTaskCallback> callback1;
-  EXPECT_CALL(callback1, Run(testing::_))
-      .Times(1)
-      .WillOnce(testing::Invoke(
-          [&result1](shopping_tasks::mojom::ShoppingTaskPtr arg) {
-            result1 = std::move(arg);
-          }));
-  service_->GetPrimaryShoppingTask(callback1.Get());
-
-  shopping_tasks::mojom::ShoppingTaskPtr result2;
-  base::MockCallback<ShoppingTasksService::ShoppingTaskCallback> callback2;
-  EXPECT_CALL(callback2, Run(testing::_))
-      .Times(1)
-      .WillOnce(testing::Invoke(
-          [&result2](shopping_tasks::mojom::ShoppingTaskPtr arg) {
-            result2 = std::move(arg);
-          }));
-  service_->GetPrimaryShoppingTask(callback2.Get());
-
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_TRUE(result1);
-  EXPECT_TRUE(result2);
-}
-
-// Verifies error if JSON is malformed.
-TEST_F(ShoppingTasksServiceTest, BadResponse) {
-  test_url_loader_factory_.AddResponse(
-      "https://www.google.com/async/newtab_shopping_tasks?hl=en-US",
-      ")]}'{\"update\":{\"promotions\":{}}}");
-
-  shopping_tasks::mojom::ShoppingTaskPtr result;
-  base::MockCallback<ShoppingTasksService::ShoppingTaskCallback> callback;
-  EXPECT_CALL(callback, Run(testing::_))
-      .Times(1)
-      .WillOnce(testing::Invoke(
-          [&result](shopping_tasks::mojom::ShoppingTaskPtr arg) {
-            result = std::move(arg);
-          }));
-
-  service_->GetPrimaryShoppingTask(callback.Get());
-  base::RunLoop().RunUntilIdle();
-
-  ASSERT_FALSE(result);
-}
-
-// Verifies error if no products.
-TEST_F(ShoppingTasksServiceTest, NoProducts) {
-  test_url_loader_factory_.AddResponse(
-      "https://www.google.com/async/newtab_shopping_tasks?hl=en-US",
-      R"()]}'
-{
-  "update": {
-    "shopping_tasks": [
-      {
-        "title": "hello world",
-        "task_name": "hello world",
-        "products": [],
-        "related_searches": [
-          {
-            "text": "baz",
-            "target_url": "https://google.com/baz"
-          }
-        ]
-      }
-    ]
-  }
-})");
-
-  shopping_tasks::mojom::ShoppingTaskPtr result;
-  base::MockCallback<ShoppingTasksService::ShoppingTaskCallback> callback;
-  EXPECT_CALL(callback, Run(testing::_))
-      .Times(1)
-      .WillOnce(testing::Invoke(
-          [&result](shopping_tasks::mojom::ShoppingTaskPtr arg) {
-            result = std::move(arg);
-          }));
-
-  service_->GetPrimaryShoppingTask(callback.Get());
-  base::RunLoop().RunUntilIdle();
-
-  ASSERT_FALSE(result);
-}
-
-// Verifies error if download fails.
-TEST_F(ShoppingTasksServiceTest, ErrorResponse) {
-  test_url_loader_factory_.AddResponse(
-      GURL("https://www.google.com/async/newtab_shopping_tasks?hl=en-US"),
-      network::mojom::URLResponseHead::New(), std::string(),
-      network::URLLoaderCompletionStatus(net::HTTP_NOT_FOUND));
-
-  shopping_tasks::mojom::ShoppingTaskPtr result;
-  base::MockCallback<ShoppingTasksService::ShoppingTaskCallback> callback;
-  EXPECT_CALL(callback, Run(testing::_))
-      .Times(1)
-      .WillOnce(testing::Invoke(
-          [&result](shopping_tasks::mojom::ShoppingTaskPtr arg) {
-            result = std::move(arg);
-          }));
-
-  service_->GetPrimaryShoppingTask(callback.Get());
-  base::RunLoop().RunUntilIdle();
-
-  ASSERT_FALSE(result);
-}
-
-// Verifies shopping tasks can be dismissed and restored and that the service
-// remembers not to return dismissed tasks.
-TEST_F(ShoppingTasksServiceTest, DismissTasks) {
-  test_url_loader_factory_.AddResponse(
-      "https://www.google.com/async/newtab_shopping_tasks?hl=en-US",
-      R"()]}'
-{
-  "update": {
-    "shopping_tasks": [
-      {
-        "title": "task 1 title",
-        "task_name": "task 1 name",
-        "products": [
-          {
-            "name": "foo",
-            "image_url": "https://foo.com",
-            "price": "$500",
-            "info": "visited 5 days ago",
-            "target_url": "https://google.com/foo"
-          }
-        ],
-        "related_searches": [
-          {
-            "text": "baz",
-            "target_url": "https://google.com/baz"
-          }
-        ]
-      },
-      {
-        "title": "task 2 title",
-        "task_name": "task 2 name",
-        "products": [
-          {
-            "name": "foo",
-            "image_url": "https://foo.com",
-            "price": "$500",
-            "info": "visited 5 days ago",
-            "target_url": "https://google.com/foo"
-          }
-        ],
-        "related_searches": [
-          {
-            "text": "baz",
-            "target_url": "https://google.com/baz"
-          }
-        ]
-      }
-    ]
-  }
-})");
-
-  shopping_tasks::mojom::ShoppingTaskPtr result1;
-  base::MockCallback<ShoppingTasksService::ShoppingTaskCallback> callback1;
-  EXPECT_CALL(callback1, Run(testing::_))
-      .Times(1)
-      .WillOnce(testing::Invoke(
-          [&result1](shopping_tasks::mojom::ShoppingTaskPtr arg) {
-            result1 = std::move(arg);
-          }));
-  service_->GetPrimaryShoppingTask(callback1.Get());
-  base::RunLoop().RunUntilIdle();
-  ASSERT_TRUE(result1);
-  EXPECT_EQ("task 1 name", result1->name);
-
-  service_->DismissShoppingTask("task 1 name");
-
-  shopping_tasks::mojom::ShoppingTaskPtr result2;
-  base::MockCallback<ShoppingTasksService::ShoppingTaskCallback> callback2;
-  EXPECT_CALL(callback2, Run(testing::_))
-      .Times(1)
-      .WillOnce(testing::Invoke(
-          [&result2](shopping_tasks::mojom::ShoppingTaskPtr arg) {
-            result2 = std::move(arg);
-          }));
-  service_->GetPrimaryShoppingTask(callback2.Get());
-  base::RunLoop().RunUntilIdle();
-  ASSERT_TRUE(result2);
-  EXPECT_EQ("task 2 name", result2->name);
-
-  service_->DismissShoppingTask("task 2 name");
-
-  shopping_tasks::mojom::ShoppingTaskPtr result3;
-  base::MockCallback<ShoppingTasksService::ShoppingTaskCallback> callback3;
-  EXPECT_CALL(callback3, Run(testing::_))
-      .Times(1)
-      .WillOnce(testing::Invoke(
-          [&result3](shopping_tasks::mojom::ShoppingTaskPtr arg) {
-            result3 = std::move(arg);
-          }));
-  service_->GetPrimaryShoppingTask(callback3.Get());
-  base::RunLoop().RunUntilIdle();
-  ASSERT_FALSE(result3);
-
-  service_->RestoreShoppingTask("task 2 name");
-
-  shopping_tasks::mojom::ShoppingTaskPtr result4;
-  base::MockCallback<ShoppingTasksService::ShoppingTaskCallback> callback4;
-  EXPECT_CALL(callback4, Run(testing::_))
-      .Times(1)
-      .WillOnce(testing::Invoke(
-          [&result4](shopping_tasks::mojom::ShoppingTaskPtr arg) {
-            result4 = std::move(arg);
-          }));
-  service_->GetPrimaryShoppingTask(callback4.Get());
-  base::RunLoop().RunUntilIdle();
-  ASSERT_TRUE(result4);
-  EXPECT_EQ("task 2 name", result4->name);
-
-  service_->RestoreShoppingTask("task 1 name");
-
-  shopping_tasks::mojom::ShoppingTaskPtr result5;
-  base::MockCallback<ShoppingTasksService::ShoppingTaskCallback> callback5;
-  EXPECT_CALL(callback5, Run(testing::_))
-      .Times(1)
-      .WillOnce(testing::Invoke(
-          [&result5](shopping_tasks::mojom::ShoppingTaskPtr arg) {
-            result5 = std::move(arg);
-          }));
-  service_->GetPrimaryShoppingTask(callback5.Get());
-  base::RunLoop().RunUntilIdle();
-  ASSERT_TRUE(result5);
-  EXPECT_EQ("task 1 name", result5->name);
-}
diff --git a/chrome/browser/search/recipe_tasks/BUILD.gn b/chrome/browser/search/task_module/BUILD.gn
similarity index 88%
rename from chrome/browser/search/recipe_tasks/BUILD.gn
rename to chrome/browser/search/task_module/BUILD.gn
index 8fbb688..d21ea57 100644
--- a/chrome/browser/search/recipe_tasks/BUILD.gn
+++ b/chrome/browser/search/task_module/BUILD.gn
@@ -5,6 +5,6 @@
 import("//mojo/public/tools/bindings/mojom.gni")
 
 mojom("mojo_bindings") {
-  sources = [ "recipe_tasks.mojom" ]
+  sources = [ "task_module.mojom" ]
   public_deps = [ "//url/mojom:url_mojom_gurl" ]
 }
diff --git a/chrome/browser/search/recipe_tasks/OWNERS b/chrome/browser/search/task_module/OWNERS
similarity index 100%
rename from chrome/browser/search/recipe_tasks/OWNERS
rename to chrome/browser/search/task_module/OWNERS
diff --git a/chrome/browser/search/task_module/task_module.mojom b/chrome/browser/search/task_module/task_module.mojom
new file mode 100644
index 0000000..ad520b4
--- /dev/null
+++ b/chrome/browser/search/task_module/task_module.mojom
@@ -0,0 +1,62 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module task_module.mojom;
+
+import "url/mojom/url.mojom";
+
+// Available task modules.
+enum TaskModuleType {
+  kRecipe,
+  kShopping,
+};
+
+// A task item such as recipe or product.
+struct TaskItem {
+  // Human-readable name.
+  string name;
+  // URL to image associated with the task item.
+  url.mojom.Url image_url;
+  // Human-readable product price. Not applicable to recipes.
+  string? price;
+  // Human-readable info.
+  string info;
+  // URL of the target page.
+  url.mojom.Url target_url;
+};
+
+// A related search query.
+struct RelatedSearch {
+  // Text of the search query.
+  string text;
+  // URL of the query target page.
+  url.mojom.Url target_url;
+};
+
+// A task search journey that is currently active for the user.
+struct Task {
+  // Human-readable title.
+  string title;
+  // Human-readable name.
+  string name;
+  // Task item associated with the task.
+  array<TaskItem> task_items;
+  // Searches related to the task.
+  array<RelatedSearch> related_searches;
+};
+
+// Interface for handling requests from a task module's JS code.
+// Bound to the NTP WebUI handler.
+interface TaskModuleHandler {
+  // Returns the primary task if available.
+  GetPrimaryTask(TaskModuleType task_module_type) => (Task? task);
+  // Dismisses the task with the given name and remembers that setting.
+  DismissTask(TaskModuleType task_module_type, string task_name);
+  // Restores the task with the given name and remembers that setting.
+  RestoreTask(TaskModuleType task_module_type, string task_name);
+  // Logs that the task item at position |index| has been clicked.
+  OnTaskItemClicked(TaskModuleType task_module_type, uint32 index);
+  // Logs that the related search pill at position |index| has been clicked.
+  OnRelatedSearchClicked(TaskModuleType task_module_type, uint32 index);
+};
diff --git a/chrome/browser/search/task_module/task_module_handler.cc b/chrome/browser/search/task_module/task_module_handler.cc
new file mode 100644
index 0000000..defa83d7
--- /dev/null
+++ b/chrome/browser/search/task_module/task_module_handler.cc
@@ -0,0 +1,83 @@
+// 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/search/task_module/task_module_handler.h"
+
+#include "base/metrics/histogram_functions.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/search/task_module/task_module_service.h"
+#include "chrome/browser/search/task_module/task_module_service_factory.h"
+
+namespace {
+const char* GetModuleName(task_module::mojom::TaskModuleType task_module_type) {
+  switch (task_module_type) {
+    case task_module::mojom::TaskModuleType::kRecipe:
+      return "RecipeTasks";
+    case task_module::mojom::TaskModuleType::kShopping:
+      return "ShoppingTasks";
+    default:
+      NOTREACHED();
+  }
+}
+}  // namespace
+
+TaskModuleHandler::TaskModuleHandler(
+    mojo::PendingReceiver<task_module::mojom::TaskModuleHandler>
+        pending_receiver,
+    Profile* profile)
+    : receiver_(this, std::move(pending_receiver)), profile_(profile) {}
+
+TaskModuleHandler::~TaskModuleHandler() = default;
+
+void TaskModuleHandler::GetPrimaryTask(
+    task_module::mojom::TaskModuleType task_module_type,
+    GetPrimaryTaskCallback callback) {
+  TaskModuleServiceFactory::GetForProfile(profile_)->GetPrimaryTask(
+      task_module_type, std::move(callback));
+}
+
+void TaskModuleHandler::DismissTask(
+    task_module::mojom::TaskModuleType task_module_type,
+    const std::string& task_name) {
+  TaskModuleServiceFactory::GetForProfile(profile_)->DismissTask(
+      task_module_type, task_name);
+}
+
+void TaskModuleHandler::RestoreTask(
+    task_module::mojom::TaskModuleType task_module_type,
+    const std::string& task_name) {
+  TaskModuleServiceFactory::GetForProfile(profile_)->RestoreTask(
+      task_module_type, task_name);
+}
+
+void TaskModuleHandler::OnTaskItemClicked(
+    task_module::mojom::TaskModuleType task_module_type,
+    uint32_t index) {
+  std::string task_item_name;
+  switch (task_module_type) {
+    case task_module::mojom::TaskModuleType::kRecipe:
+      task_item_name = "Recipe";
+      break;
+    case task_module::mojom::TaskModuleType::kShopping:
+      task_item_name = "Product";
+      break;
+    default:
+      NOTREACHED();
+  }
+  base::UmaHistogramCounts100(
+      base::StringPrintf("NewTabPage.%s.%sClick",
+                         GetModuleName(task_module_type),
+                         task_item_name.c_str()),
+      index);
+}
+
+void TaskModuleHandler::OnRelatedSearchClicked(
+    task_module::mojom::TaskModuleType task_module_type,
+    uint32_t index) {
+  base::UmaHistogramCounts100(
+      base::StringPrintf("NewTabPage.%s.RelatedSearchClick",
+                         GetModuleName(task_module_type)),
+      index);
+}
diff --git a/chrome/browser/search/task_module/task_module_handler.h b/chrome/browser/search/task_module/task_module_handler.h
new file mode 100644
index 0000000..b85b7b3
--- /dev/null
+++ b/chrome/browser/search/task_module/task_module_handler.h
@@ -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.
+
+#ifndef CHROME_BROWSER_SEARCH_TASK_MODULE_TASK_MODULE_HANDLER_H_
+#define CHROME_BROWSER_SEARCH_TASK_MODULE_TASK_MODULE_HANDLER_H_
+
+#include "chrome/browser/search/task_module/task_module.mojom.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+
+class Profile;
+
+// Implementation of the TaskModuleHandler mojo interface that requests tasks
+// from the TaskModuleService. Instantiated by the NTP upon a connection request
+// by a task module.
+class TaskModuleHandler : public task_module::mojom::TaskModuleHandler {
+ public:
+  TaskModuleHandler(mojo::PendingReceiver<task_module::mojom::TaskModuleHandler>
+                        pending_receiver,
+                    Profile* profile);
+  ~TaskModuleHandler() override;
+
+  // task_module::mojom::TaskModuleHandler:
+  void GetPrimaryTask(task_module::mojom::TaskModuleType task_module_type,
+                      GetPrimaryTaskCallback callback) override;
+  void DismissTask(task_module::mojom::TaskModuleType task_module_type,
+                   const std::string& task_name) override;
+  void RestoreTask(task_module::mojom::TaskModuleType task_module_type,
+                   const std::string& task_name) override;
+  void OnTaskItemClicked(task_module::mojom::TaskModuleType task_module_type,
+                         uint32_t index) override;
+  void OnRelatedSearchClicked(
+      task_module::mojom::TaskModuleType task_module_type,
+      uint32_t index) override;
+
+ private:
+  mojo::Receiver<task_module::mojom::TaskModuleHandler> receiver_;
+  Profile* profile_;
+};
+
+#endif  // CHROME_BROWSER_SEARCH_TASK_MODULE_TASK_MODULE_HANDLER_H_
diff --git a/chrome/browser/search/task_module/task_module_service.cc b/chrome/browser/search/task_module/task_module_service.cc
new file mode 100644
index 0000000..e50b22c
--- /dev/null
+++ b/chrome/browser/search/task_module/task_module_service.cc
@@ -0,0 +1,291 @@
+// 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/search/task_module/task_module_service.h"
+
+#include "base/stl_util.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/webui_url_constants.h"
+#include "components/google/core/common/google_util.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "components/prefs/scoped_user_pref_update.h"
+#include "components/variations/net/variations_http_headers.h"
+#include "net/base/url_util.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+
+namespace {
+const char kXSSIResponsePreamble[] = ")]}'";
+
+const char* GetPath(task_module::mojom::TaskModuleType task_module_type) {
+  switch (task_module_type) {
+    case task_module::mojom::TaskModuleType::kRecipe:
+      return "/async/newtab_recipe_tasks";
+    case task_module::mojom::TaskModuleType::kShopping:
+      return "/async/newtab_shopping_tasks";
+    default:
+      NOTREACHED();
+  }
+  return nullptr;
+}
+
+GURL GetApiUrl(task_module::mojom::TaskModuleType task_module_type,
+               const std::string& application_locale) {
+  GURL google_base_url = google_util::CommandLineGoogleBaseURL();
+  if (!google_base_url.is_valid()) {
+    google_base_url = GURL(google_util::kGoogleHomepageURL);
+  }
+  return net::AppendQueryParameter(
+      google_base_url.Resolve(GetPath(task_module_type)), "hl",
+      application_locale);
+}
+
+const char* GetTasksKey(task_module::mojom::TaskModuleType task_module_type) {
+  switch (task_module_type) {
+    case task_module::mojom::TaskModuleType::kRecipe:
+      return "recipe_tasks";
+    case task_module::mojom::TaskModuleType::kShopping:
+      return "shopping_tasks";
+    default:
+      NOTREACHED();
+  }
+  return nullptr;
+}
+
+const char* GetTaskItemsKey(
+    task_module::mojom::TaskModuleType task_module_type) {
+  switch (task_module_type) {
+    case task_module::mojom::TaskModuleType::kRecipe:
+      return "recipes";
+    case task_module::mojom::TaskModuleType::kShopping:
+      return "products";
+    default:
+      NOTREACHED();
+  }
+  return nullptr;
+}
+
+const char* GetDismissedTasksPrefName(
+    task_module::mojom::TaskModuleType task_module_type) {
+  switch (task_module_type) {
+    case task_module::mojom::TaskModuleType::kRecipe:
+      return "NewTabPage.DismissedRecipeTasks";
+    case task_module::mojom::TaskModuleType::kShopping:
+      return "NewTabPage.DismissedShoppingTasks";
+    default:
+      NOTREACHED();
+  }
+  return nullptr;
+}
+}  // namespace
+
+TaskModuleService::TaskModuleService(
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+    Profile* profile,
+    const std::string& application_locale)
+    : profile_(profile),
+      url_loader_factory_(url_loader_factory),
+      application_locale_(application_locale) {}
+
+TaskModuleService::~TaskModuleService() = default;
+
+// static
+void TaskModuleService::RegisterProfilePrefs(PrefRegistrySimple* registry) {
+  registry->RegisterListPref(
+      GetDismissedTasksPrefName(task_module::mojom::TaskModuleType::kRecipe));
+  registry->RegisterListPref(
+      GetDismissedTasksPrefName(task_module::mojom::TaskModuleType::kShopping));
+}
+
+void TaskModuleService::Shutdown() {}
+
+void TaskModuleService::GetPrimaryTask(
+    task_module::mojom::TaskModuleType task_module_type,
+    TaskModuleCallback callback) {
+  net::NetworkTrafficAnnotationTag traffic_annotation =
+      net::DefineNetworkTrafficAnnotation("task_module_service", R"(
+        semantics {
+          sender: "Task Module Service"
+          description: "This service downloads tasks, which is information "
+            "related to the user's currently active search journeys such as "
+            "visited and recommended task items, such as products to purchase "
+            "or recipes. "
+            "Tasks will be displayed on the new tab page to help the  user to "
+            "continue their search journey. Tasks are queried on every new tab "
+            "page load."
+          trigger:
+            "Displaying the new tab page on Desktop, if Google is the "
+            "configured search provider and the user is signed in."
+          data: "Credentials if user is signed in."
+          destination: GOOGLE_OWNED_SERVICE
+        }
+        policy {
+          cookies_allowed: YES
+          cookies_store: "user"
+          setting:
+            "Users can control this feature via selecting a non-Google default "
+            "search engine in Chrome settings under 'Search Engine' or by "
+            "signing out."
+          chrome_policy {
+            DefaultSearchProviderEnabled {
+              policy_options {mode: MANDATORY}
+              DefaultSearchProviderEnabled: false
+            }
+            BrowserSignin {
+              policy_options {mode: MANDATORY}
+              BrowserSignin: 0
+            }
+          }
+        })");
+
+  auto resource_request = std::make_unique<network::ResourceRequest>();
+  resource_request->url = GetApiUrl(task_module_type, application_locale_);
+  resource_request->credentials_mode =
+      network::mojom::CredentialsMode::kInclude;
+  resource_request->request_initiator =
+      url::Origin::Create(GURL(chrome::kChromeUINewTabURL));
+  variations::AppendVariationsHeaderUnknownSignedIn(
+      resource_request->url,
+      /* Modules are only shown in non-incognito. */
+      variations::InIncognito::kNo, resource_request.get());
+
+  loaders_.push_back(network::SimpleURLLoader::Create(
+      std::move(resource_request), traffic_annotation));
+  loaders_.back()->DownloadToString(
+      url_loader_factory_.get(),
+      base::BindOnce(&TaskModuleService::OnDataLoaded,
+                     weak_ptr_factory_.GetWeakPtr(), task_module_type,
+                     loaders_.back().get(), std::move(callback)),
+      network::SimpleURLLoader::kMaxBoundedStringDownloadSize);
+}
+
+void TaskModuleService::DismissTask(
+    task_module::mojom::TaskModuleType task_module_type,
+    const std::string& task_name) {
+  ListPrefUpdate update(profile_->GetPrefs(),
+                        GetDismissedTasksPrefName(task_module_type));
+  update->AppendIfNotPresent(std::make_unique<base::Value>(task_name));
+}
+
+void TaskModuleService::RestoreTask(
+    task_module::mojom::TaskModuleType task_module_type,
+    const std::string& task_name) {
+  ListPrefUpdate update(profile_->GetPrefs(),
+                        GetDismissedTasksPrefName(task_module_type));
+  update->EraseListValue(base::Value(task_name));
+}
+
+void TaskModuleService::OnDataLoaded(
+    task_module::mojom::TaskModuleType task_module_type,
+    network::SimpleURLLoader* loader,
+    TaskModuleCallback callback,
+    std::unique_ptr<std::string> response) {
+  auto net_error = loader->NetError();
+  base::EraseIf(loaders_, [loader](const auto& target) {
+    return loader == target.get();
+  });
+
+  if (net_error != net::OK || !response) {
+    std::move(callback).Run(nullptr);
+    return;
+  }
+
+  if (base::StartsWith(*response, kXSSIResponsePreamble,
+                       base::CompareCase::SENSITIVE)) {
+    *response = response->substr(strlen(kXSSIResponsePreamble));
+  }
+
+  data_decoder::DataDecoder::ParseJsonIsolated(
+      *response, base::BindOnce(&TaskModuleService::OnJsonParsed,
+                                weak_ptr_factory_.GetWeakPtr(),
+                                task_module_type, std::move(callback)));
+}
+
+void TaskModuleService::OnJsonParsed(
+    task_module::mojom::TaskModuleType task_module_type,
+    TaskModuleCallback callback,
+    data_decoder::DataDecoder::ValueOrError result) {
+  if (!result.value) {
+    std::move(callback).Run(nullptr);
+    return;
+  }
+  // We receive a list of tasks ordered from highest to lowest priority. We only
+  // support showing a single task though. Therefore, pick the first task.
+  auto* tasks = result.value->FindListPath(
+      base::StringPrintf("update.%s", GetTasksKey(task_module_type)));
+  if (!tasks || tasks->GetList().size() == 0) {
+    std::move(callback).Run(nullptr);
+    return;
+  }
+  for (const auto& task : tasks->GetList()) {
+    auto* title = task.FindStringPath("title");
+    auto* task_name = task.FindStringPath("task_name");
+    auto* task_items = task.FindListPath(GetTaskItemsKey(task_module_type));
+    auto* related_searches = task.FindListPath("related_searches");
+    if (!title || !task_name || !task_items || !related_searches ||
+        task_items->GetList().size() == 0) {
+      continue;
+    }
+    if (IsTaskDismissed(task_module_type, *task_name)) {
+      continue;
+    }
+    std::vector<task_module::mojom::TaskItemPtr> mojo_task_items;
+    for (const auto& task_item : task_items->GetList()) {
+      auto* name = task_item.FindStringPath("name");
+      auto* image_url = task_item.FindStringPath("image_url");
+      auto* price = task_item.FindStringPath("price");
+      auto* info = task_item.FindStringPath("info");
+      auto* target_url = task_item.FindStringPath("target_url");
+      if (!name || !image_url || !info || !target_url) {
+        continue;
+      }
+      if (task_module::mojom::TaskModuleType::kShopping == task_module_type &&
+          !price) {
+        continue;
+      }
+      auto mojom_task_item = task_module::mojom::TaskItem::New();
+      mojom_task_item->name = *name;
+      mojom_task_item->image_url = GURL(*image_url);
+      mojom_task_item->info = *info;
+      mojom_task_item->target_url = GURL(*target_url);
+      if (task_module_type == task_module::mojom::TaskModuleType::kShopping) {
+        mojom_task_item->price = *price;
+      }
+      mojo_task_items.push_back(std::move(mojom_task_item));
+    }
+    std::vector<task_module::mojom::RelatedSearchPtr> mojo_related_searches;
+    for (const auto& related_search : related_searches->GetList()) {
+      auto* text = related_search.FindStringPath("text");
+      auto* target_url = related_search.FindStringPath("target_url");
+      if (!text || !target_url) {
+        continue;
+      }
+      auto mojo_related_search = task_module::mojom::RelatedSearch::New();
+      mojo_related_search->text = *text;
+      mojo_related_search->target_url = GURL(*target_url);
+      mojo_related_searches.push_back(std::move(mojo_related_search));
+    }
+    auto mojo_task = task_module::mojom::Task::New();
+    mojo_task->title = *title;
+    mojo_task->name = *task_name;
+    mojo_task->task_items = std::move(mojo_task_items);
+    mojo_task->related_searches = std::move(mojo_related_searches);
+    std::move(callback).Run(std::move(mojo_task));
+    return;
+  }
+  std::move(callback).Run(nullptr);
+}
+
+bool TaskModuleService::IsTaskDismissed(
+    task_module::mojom::TaskModuleType task_module_type,
+    const std::string& task_name) {
+  const base::ListValue* dismissed_tasks = profile_->GetPrefs()->GetList(
+      GetDismissedTasksPrefName(task_module_type));
+  DCHECK(dismissed_tasks);
+  return dismissed_tasks->Find(base::Value(task_name)) !=
+         dismissed_tasks->end();
+}
diff --git a/chrome/browser/search/task_module/task_module_service.h b/chrome/browser/search/task_module/task_module_service.h
new file mode 100644
index 0000000..839257e
--- /dev/null
+++ b/chrome/browser/search/task_module/task_module_service.h
@@ -0,0 +1,76 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SEARCH_TASK_MODULE_TASK_MODULE_SERVICE_H_
+#define CHROME_BROWSER_SEARCH_TASK_MODULE_TASK_MODULE_SERVICE_H_
+
+#include <list>
+#include <memory>
+
+#include "base/callback.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/search/task_module/task_module.mojom.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "services/data_decoder/public/cpp/data_decoder.h"
+
+class PrefRegistrySimple;
+class Profile;
+namespace network {
+class SharedURLLoaderFactory;
+class SimpleURLLoader;
+}  // namespace network
+
+// Downloads tasks for current user from GWS.
+class TaskModuleService : public KeyedService {
+ public:
+  TaskModuleService(
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+      Profile* profile,
+      const std::string& application_locale);
+  TaskModuleService(const TaskModuleService&) = delete;
+  ~TaskModuleService() override;
+
+  static void RegisterProfilePrefs(PrefRegistrySimple* registry);
+
+  // KeyedService:
+  void Shutdown() override;
+
+  using TaskModuleCallback =
+      base::OnceCallback<void(task_module::mojom::TaskPtr task)>;
+  // Downloads and parses tasks and calls |callback| when done.
+  // On success |callback| is called with a populated |TaskModuleData| object
+  // of the first task which has not been dismissed. On failure, it is called
+  // with nullptr.
+  void GetPrimaryTask(task_module::mojom::TaskModuleType task_module_type,
+                      TaskModuleCallback callback);
+  // Dismisses the task with the given name and remembers that setting.
+  void DismissTask(task_module::mojom::TaskModuleType task_module_type,
+                   const std::string& task_name);
+  // Restores the task with the given name and remembers that setting.
+  void RestoreTask(task_module::mojom::TaskModuleType task_module_type,
+                   const std::string& task_name);
+
+ private:
+  void OnDataLoaded(task_module::mojom::TaskModuleType task_module_type,
+                    network::SimpleURLLoader* loader,
+                    TaskModuleCallback callback,
+                    std::unique_ptr<std::string> response);
+  void OnJsonParsed(task_module::mojom::TaskModuleType task_module_type,
+                    TaskModuleCallback callback,
+                    data_decoder::DataDecoder::ValueOrError result);
+
+  // Returns whether a task with the given name has been dismissed.
+  bool IsTaskDismissed(task_module::mojom::TaskModuleType task_module_type,
+                       const std::string& task_name);
+
+  Profile* profile_;
+  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
+  std::list<std::unique_ptr<network::SimpleURLLoader>> loaders_;
+  std::string application_locale_;
+
+  base::WeakPtrFactory<TaskModuleService> weak_ptr_factory_{this};
+};
+
+#endif  // CHROME_BROWSER_SEARCH_TASK_MODULE_TASK_MODULE_SERVICE_H_
diff --git a/chrome/browser/search/task_module/task_module_service_factory.cc b/chrome/browser/search/task_module/task_module_service_factory.cc
new file mode 100644
index 0000000..9aeb4e6c
--- /dev/null
+++ b/chrome/browser/search/task_module/task_module_service_factory.cc
@@ -0,0 +1,43 @@
+// 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/search/task_module/task_module_service_factory.h"
+
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/content_settings/cookie_settings_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/search/task_module/task_module_service.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/storage_partition.h"
+
+// static
+TaskModuleService* TaskModuleServiceFactory::GetForProfile(Profile* profile) {
+  return static_cast<TaskModuleService*>(
+      GetInstance()->GetServiceForBrowserContext(profile, true));
+}
+
+// static
+TaskModuleServiceFactory* TaskModuleServiceFactory::GetInstance() {
+  return base::Singleton<TaskModuleServiceFactory>::get();
+}
+
+TaskModuleServiceFactory::TaskModuleServiceFactory()
+    : BrowserContextKeyedServiceFactory(
+          "TaskModuleService",
+          BrowserContextDependencyManager::GetInstance()) {
+  DependsOn(CookieSettingsFactory::GetInstance());
+}
+
+TaskModuleServiceFactory::~TaskModuleServiceFactory() = default;
+
+KeyedService* TaskModuleServiceFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  auto url_loader_factory =
+      content::BrowserContext::GetDefaultStoragePartition(context)
+          ->GetURLLoaderFactoryForBrowserProcess();
+  return new TaskModuleService(url_loader_factory,
+                               Profile::FromBrowserContext(context),
+                               g_browser_process->GetApplicationLocale());
+}
diff --git a/chrome/browser/search/task_module/task_module_service_factory.h b/chrome/browser/search/task_module/task_module_service_factory.h
new file mode 100644
index 0000000..c84e13a9
--- /dev/null
+++ b/chrome/browser/search/task_module/task_module_service_factory.h
@@ -0,0 +1,33 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SEARCH_TASK_MODULE_TASK_MODULE_SERVICE_FACTORY_H_
+#define CHROME_BROWSER_SEARCH_TASK_MODULE_TASK_MODULE_SERVICE_FACTORY_H_
+
+#include "base/memory/singleton.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+class Profile;
+class TaskModuleService;
+
+// Factory to access the task module service for the current profile.
+class TaskModuleServiceFactory : public BrowserContextKeyedServiceFactory {
+ public:
+  static TaskModuleService* GetForProfile(Profile* profile);
+  static TaskModuleServiceFactory* GetInstance();
+
+  TaskModuleServiceFactory(const TaskModuleServiceFactory&) = delete;
+
+ private:
+  friend struct base::DefaultSingletonTraits<TaskModuleServiceFactory>;
+
+  TaskModuleServiceFactory();
+  ~TaskModuleServiceFactory() override;
+
+  // BrowserContextKeyedServiceFactory:
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* profile) const override;
+};
+
+#endif  // CHROME_BROWSER_SEARCH_TASK_MODULE_TASK_MODULE_SERVICE_FACTORY_H_
diff --git a/chrome/browser/search/task_module/task_module_service_unittest.cc b/chrome/browser/search/task_module/task_module_service_unittest.cc
new file mode 100644
index 0000000..40e7399
--- /dev/null
+++ b/chrome/browser/search/task_module/task_module_service_unittest.cc
@@ -0,0 +1,388 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+
+#include "base/memory/scoped_refptr.h"
+#include "base/test/bind_test_util.h"
+#include "base/test/mock_callback.h"
+#include "chrome/browser/search/task_module/task_module_service.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/test/browser_task_environment.h"
+#include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class TaskModuleServiceTest : public testing::Test {
+ public:
+  TaskModuleServiceTest()
+      : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP) {}
+
+  void SetUp() override {
+    testing::Test::SetUp();
+
+    service_ = std::make_unique<TaskModuleService>(
+        base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+            &test_url_loader_factory_),
+        &profile_, "en-US");
+  }
+
+  void TearDown() override {
+    service_.reset();
+    test_url_loader_factory_.ClearResponses();
+  }
+
+ protected:
+  // Required to run tests from UI thread.
+  content::BrowserTaskEnvironment task_environment_;
+  TestingProfile profile_;
+  network::TestURLLoaderFactory test_url_loader_factory_;
+  data_decoder::test::InProcessDataDecoder in_process_data_decoder_;
+  scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_;
+  std::unique_ptr<TaskModuleService> service_;
+};
+
+// Verifies correct parsing of well-formed JSON.
+TEST_F(TaskModuleServiceTest, GoodShoppingResponse) {
+  test_url_loader_factory_.AddResponse(
+      "https://www.google.com/async/newtab_shopping_tasks?hl=en-US",
+      R"()]}'
+{
+  "update": {
+    "shopping_tasks": [
+      {
+        "title": "hello world",
+        "task_name": "hello world",
+        "products": [
+          {
+            "name": "foo",
+            "image_url": "https://foo.com",
+            "price": "$500",
+            "info": "visited 5 days ago",
+            "target_url": "https://google.com/foo"
+          },{
+            "name": "bar",
+            "image_url": "https://bar.com",
+            "price": "$400",
+            "info": "visited 1 day ago",
+            "target_url": "https://google.com/bar"
+          }
+        ],
+        "related_searches": [
+          {
+            "text": "baz",
+            "target_url": "https://google.com/baz"
+          },
+          {
+            "text": "blub",
+            "target_url": "https://google.com/blub"
+          }
+        ]
+      }
+    ]
+  }
+})");
+
+  task_module::mojom::TaskPtr result;
+  base::MockCallback<TaskModuleService::TaskModuleCallback> callback;
+  EXPECT_CALL(callback, Run(testing::_))
+      .Times(1)
+      .WillOnce(testing::Invoke([&result](task_module::mojom::TaskPtr arg) {
+        result = std::move(arg);
+      }));
+
+  service_->GetPrimaryTask(task_module::mojom::TaskModuleType::kShopping,
+                           callback.Get());
+  base::RunLoop().RunUntilIdle();
+
+  ASSERT_TRUE(result);
+  EXPECT_EQ("hello world", result->title);
+  EXPECT_EQ(2ul, result->task_items.size());
+  EXPECT_EQ(2ul, result->related_searches.size());
+  EXPECT_EQ("foo", result->task_items[0]->name);
+  EXPECT_EQ("https://foo.com/", result->task_items[0]->image_url.spec());
+  EXPECT_EQ("$500", result->task_items[0]->price);
+  EXPECT_EQ("visited 5 days ago", result->task_items[0]->info);
+  EXPECT_EQ("https://google.com/foo", result->task_items[0]->target_url.spec());
+  EXPECT_EQ("bar", result->task_items[1]->name);
+  EXPECT_EQ("https://bar.com/", result->task_items[1]->image_url.spec());
+  EXPECT_EQ("$400", result->task_items[1]->price);
+  EXPECT_EQ("visited 1 day ago", result->task_items[1]->info);
+  EXPECT_EQ("https://google.com/bar", result->task_items[1]->target_url.spec());
+  EXPECT_EQ("baz", result->related_searches[0]->text);
+  EXPECT_EQ("https://google.com/baz",
+            result->related_searches[0]->target_url.spec());
+  EXPECT_EQ("blub", result->related_searches[1]->text);
+  EXPECT_EQ("https://google.com/blub",
+            result->related_searches[1]->target_url.spec());
+}
+
+// Verifies service can handle multiple in flight requests.
+TEST_F(TaskModuleServiceTest, MultiRequest) {
+  test_url_loader_factory_.AddResponse(
+      "https://www.google.com/async/newtab_shopping_tasks?hl=en-US",
+      R"()]}'
+{
+  "update": {
+    "shopping_tasks": [
+      {
+        "title": "hello world",
+        "task_name": "hello world",
+        "products": [
+          {
+            "name": "foo",
+            "image_url": "https://foo.com",
+            "price": "$500",
+            "info": "visited 5 days ago",
+            "target_url": "https://google.com/foo"
+          }
+        ],
+        "related_searches": [
+          {
+            "text": "baz",
+            "target_url": "https://google.com/baz"
+          }
+        ]
+      }
+    ]
+  }
+})");
+
+  task_module::mojom::TaskPtr result1;
+  base::MockCallback<TaskModuleService::TaskModuleCallback> callback1;
+  EXPECT_CALL(callback1, Run(testing::_))
+      .Times(1)
+      .WillOnce(testing::Invoke([&result1](task_module::mojom::TaskPtr arg) {
+        result1 = std::move(arg);
+      }));
+  service_->GetPrimaryTask(task_module::mojom::TaskModuleType::kShopping,
+                           callback1.Get());
+
+  task_module::mojom::TaskPtr result2;
+  base::MockCallback<TaskModuleService::TaskModuleCallback> callback2;
+  EXPECT_CALL(callback2, Run(testing::_))
+      .Times(1)
+      .WillOnce(testing::Invoke([&result2](task_module::mojom::TaskPtr arg) {
+        result2 = std::move(arg);
+      }));
+  service_->GetPrimaryTask(task_module::mojom::TaskModuleType::kShopping,
+                           callback2.Get());
+
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(result1);
+  EXPECT_TRUE(result2);
+}
+
+// Verifies error if JSON is malformed.
+TEST_F(TaskModuleServiceTest, BadShoppingResponse) {
+  test_url_loader_factory_.AddResponse(
+      "https://www.google.com/async/newtab_shopping_tasks?hl=en-US",
+      ")]}'{\"update\":{\"promotions\":{}}}");
+
+  task_module::mojom::TaskPtr result;
+  base::MockCallback<TaskModuleService::TaskModuleCallback> callback;
+  EXPECT_CALL(callback, Run(testing::_))
+      .Times(1)
+      .WillOnce(testing::Invoke([&result](task_module::mojom::TaskPtr arg) {
+        result = std::move(arg);
+      }));
+
+  service_->GetPrimaryTask(task_module::mojom::TaskModuleType::kShopping,
+                           callback.Get());
+  base::RunLoop().RunUntilIdle();
+
+  ASSERT_FALSE(result);
+}
+
+// Verifies error if no products.
+TEST_F(TaskModuleServiceTest, NoTaskItems) {
+  test_url_loader_factory_.AddResponse(
+      "https://www.google.com/async/newtab_shopping_tasks?hl=en-US",
+      R"()]}'
+{
+  "update": {
+    "shopping_tasks": [
+      {
+        "title": "hello world",
+        "task_name": "hello world",
+        "products": [],
+        "related_searches": [
+          {
+            "text": "baz",
+            "target_url": "https://google.com/baz"
+          }
+        ]
+      }
+    ]
+  }
+})");
+
+  task_module::mojom::TaskPtr result;
+  base::MockCallback<TaskModuleService::TaskModuleCallback> callback;
+  EXPECT_CALL(callback, Run(testing::_))
+      .Times(1)
+      .WillOnce(testing::Invoke([&result](task_module::mojom::TaskPtr arg) {
+        result = std::move(arg);
+      }));
+
+  service_->GetPrimaryTask(task_module::mojom::TaskModuleType::kShopping,
+                           callback.Get());
+  base::RunLoop().RunUntilIdle();
+
+  ASSERT_FALSE(result);
+}
+
+// Verifies error if download fails.
+TEST_F(TaskModuleServiceTest, ErrorResponse) {
+  test_url_loader_factory_.AddResponse(
+      GURL("https://www.google.com/async/newtab_shopping_tasks?hl=en-US"),
+      network::mojom::URLResponseHead::New(), std::string(),
+      network::URLLoaderCompletionStatus(net::HTTP_NOT_FOUND));
+
+  task_module::mojom::TaskPtr result;
+  base::MockCallback<TaskModuleService::TaskModuleCallback> callback;
+  EXPECT_CALL(callback, Run(testing::_))
+      .Times(1)
+      .WillOnce(testing::Invoke([&result](task_module::mojom::TaskPtr arg) {
+        result = std::move(arg);
+      }));
+
+  service_->GetPrimaryTask(task_module::mojom::TaskModuleType::kShopping,
+                           callback.Get());
+  base::RunLoop().RunUntilIdle();
+
+  ASSERT_FALSE(result);
+}
+
+// Verifies shopping tasks can be dismissed and restored and that the service
+// remembers not to return dismissed tasks.
+TEST_F(TaskModuleServiceTest, DismissTasks) {
+  test_url_loader_factory_.AddResponse(
+      "https://www.google.com/async/newtab_shopping_tasks?hl=en-US",
+      R"()]}'
+{
+  "update": {
+    "shopping_tasks": [
+      {
+        "title": "task 1 title",
+        "task_name": "task 1 name",
+        "products": [
+          {
+            "name": "foo",
+            "image_url": "https://foo.com",
+            "price": "$500",
+            "info": "visited 5 days ago",
+            "target_url": "https://google.com/foo"
+          }
+        ],
+        "related_searches": [
+          {
+            "text": "baz",
+            "target_url": "https://google.com/baz"
+          }
+        ]
+      },
+      {
+        "title": "task 2 title",
+        "task_name": "task 2 name",
+        "products": [
+          {
+            "name": "foo",
+            "image_url": "https://foo.com",
+            "price": "$500",
+            "info": "visited 5 days ago",
+            "target_url": "https://google.com/foo"
+          }
+        ],
+        "related_searches": [
+          {
+            "text": "baz",
+            "target_url": "https://google.com/baz"
+          }
+        ]
+      }
+    ]
+  }
+})");
+
+  task_module::mojom::TaskPtr result1;
+  base::MockCallback<TaskModuleService::TaskModuleCallback> callback1;
+  EXPECT_CALL(callback1, Run(testing::_))
+      .Times(1)
+      .WillOnce(testing::Invoke([&result1](task_module::mojom::TaskPtr arg) {
+        result1 = std::move(arg);
+      }));
+  service_->GetPrimaryTask(task_module::mojom::TaskModuleType::kShopping,
+                           callback1.Get());
+  base::RunLoop().RunUntilIdle();
+  ASSERT_TRUE(result1);
+  EXPECT_EQ("task 1 name", result1->name);
+
+  service_->DismissTask(task_module::mojom::TaskModuleType::kShopping,
+                        "task 1 name");
+
+  task_module::mojom::TaskPtr result2;
+  base::MockCallback<TaskModuleService::TaskModuleCallback> callback2;
+  EXPECT_CALL(callback2, Run(testing::_))
+      .Times(1)
+      .WillOnce(testing::Invoke([&result2](task_module::mojom::TaskPtr arg) {
+        result2 = std::move(arg);
+      }));
+  service_->GetPrimaryTask(task_module::mojom::TaskModuleType::kShopping,
+                           callback2.Get());
+  base::RunLoop().RunUntilIdle();
+  ASSERT_TRUE(result2);
+  EXPECT_EQ("task 2 name", result2->name);
+
+  service_->DismissTask(task_module::mojom::TaskModuleType::kShopping,
+                        "task 2 name");
+
+  task_module::mojom::TaskPtr result3;
+  base::MockCallback<TaskModuleService::TaskModuleCallback> callback3;
+  EXPECT_CALL(callback3, Run(testing::_))
+      .Times(1)
+      .WillOnce(testing::Invoke([&result3](task_module::mojom::TaskPtr arg) {
+        result3 = std::move(arg);
+      }));
+  service_->GetPrimaryTask(task_module::mojom::TaskModuleType::kShopping,
+                           callback3.Get());
+  base::RunLoop().RunUntilIdle();
+  ASSERT_FALSE(result3);
+
+  service_->RestoreTask(task_module::mojom::TaskModuleType::kShopping,
+                        "task 2 name");
+
+  task_module::mojom::TaskPtr result4;
+  base::MockCallback<TaskModuleService::TaskModuleCallback> callback4;
+  EXPECT_CALL(callback4, Run(testing::_))
+      .Times(1)
+      .WillOnce(testing::Invoke([&result4](task_module::mojom::TaskPtr arg) {
+        result4 = std::move(arg);
+      }));
+  service_->GetPrimaryTask(task_module::mojom::TaskModuleType::kShopping,
+                           callback4.Get());
+  base::RunLoop().RunUntilIdle();
+  ASSERT_TRUE(result4);
+  EXPECT_EQ("task 2 name", result4->name);
+
+  service_->RestoreTask(task_module::mojom::TaskModuleType::kShopping,
+                        "task 1 name");
+
+  task_module::mojom::TaskPtr result5;
+  base::MockCallback<TaskModuleService::TaskModuleCallback> callback5;
+  EXPECT_CALL(callback5, Run(testing::_))
+      .Times(1)
+      .WillOnce(testing::Invoke([&result5](task_module::mojom::TaskPtr arg) {
+        result5 = std::move(arg);
+      }));
+  service_->GetPrimaryTask(task_module::mojom::TaskModuleType::kShopping,
+                           callback5.Get());
+  base::RunLoop().RunUntilIdle();
+  ASSERT_TRUE(result5);
+  EXPECT_EQ("task 1 name", result5->name);
+}
diff --git a/chrome/browser/sessions/better_session_restore_browsertest.cc b/chrome/browser/sessions/better_session_restore_browsertest.cc
index 8ad5ca7..2ee4767c 100644
--- a/chrome/browser/sessions/better_session_restore_browsertest.cc
+++ b/chrome/browser/sessions/better_session_restore_browsertest.cc
@@ -742,7 +742,7 @@
 IN_PROC_BROWSER_TEST_F(NoSessionRestoreTest,
                        SessionCookiesBrowserCloseWithPopupOpen) {
   StoreDataWithPage("session_cookies.html");
-  Browser* popup = new Browser(
+  Browser* popup = Browser::Create(
       Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile(), true));
   popup->window()->Show();
   Browser* new_browser = QuitBrowserAndRestore(browser(), false);
@@ -754,7 +754,7 @@
 IN_PROC_BROWSER_TEST_F(NoSessionRestoreTest,
                        SessionCookiesBrowserClosePopupLast) {
   StoreDataWithPage("session_cookies.html");
-  Browser* popup = new Browser(
+  Browser* popup = Browser::Create(
       Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile(), true));
   popup->window()->Show();
   CloseBrowserSynchronously(browser());
diff --git a/chrome/browser/sessions/session_restore.cc b/chrome/browser/sessions/session_restore.cc
index 8c926ec..25522c7 100644
--- a/chrome/browser/sessions/session_restore.cc
+++ b/chrome/browser/sessions/session_restore.cc
@@ -208,9 +208,9 @@
 
     bool use_new_window = disposition == WindowOpenDisposition::NEW_WINDOW;
 
-    Browser* browser = use_new_window
-                           ? new Browser(Browser::CreateParams(profile_, true))
-                           : browser_;
+    Browser* browser =
+        use_new_window ? Browser::Create(Browser::CreateParams(profile_, true))
+                       : browser_;
 
     RecordAppLaunchForTab(browser, tab, selected_index);
 
@@ -282,7 +282,7 @@
                                std::vector<RestoredTab>* contents_created) {
     Browser* browser = nullptr;
     if (!created_tabbed_browser && always_create_tabbed_browser_) {
-      browser = new Browser(Browser::CreateParams(profile_, false));
+      browser = Browser::Create(Browser::CreateParams(profile_, false));
       if (urls_to_open_.empty()) {
         // No tab browsers were created and no URLs were supplied on the command
         // line. Open the new tab page.
@@ -662,7 +662,7 @@
     params.initial_show_state = show_state;
     params.initial_workspace = workspace;
     params.is_session_restore = true;
-    return new Browser(params);
+    return Browser::Create(params);
   }
 
   void ShowBrowser(Browser* browser, int selected_tab_index) {
diff --git a/chrome/browser/sessions/session_restore_browsertest_chromeos.cc b/chrome/browser/sessions/session_restore_browsertest_chromeos.cc
index 5279be7..7115bfe 100644
--- a/chrome/browser/sessions/session_restore_browsertest_chromeos.cc
+++ b/chrome/browser/sessions/session_restore_browsertest_chromeos.cc
@@ -54,7 +54,7 @@
   }
 
   Browser* CreateBrowserWithParams(Browser::CreateParams params) {
-    Browser* browser = new Browser(params);
+    Browser* browser = Browser::Create(params);
     AddBlankTabAndShow(browser);
     return browser;
   }
@@ -315,7 +315,7 @@
 
   auto app_params = Browser::CreateParams::CreateForApp(
       test_app_name1, true, gfx::Rect(), browser()->profile(), true);
-  Browser* app_browser = new Browser(app_params);
+  Browser* app_browser = Browser::Create(app_params);
   AddBlankTabAndShow(app_browser);
 
   // There should be three browsers:
diff --git a/chrome/browser/signin/chromeos_mirror_account_consistency_browsertest.cc b/chrome/browser/signin/chromeos_mirror_account_consistency_browsertest.cc
index 4f7552f..c7d626c 100644
--- a/chrome/browser/signin/chromeos_mirror_account_consistency_browsertest.cc
+++ b/chrome/browser/signin/chromeos_mirror_account_consistency_browsertest.cc
@@ -46,7 +46,7 @@
   replace_host.SetHostStr(kGaiaDomain);
   gaia_url = gaia_url.ReplaceComponents(replace_host);
 
-  Browser* browser = new Browser(Browser::CreateParams(profile, true));
+  Browser* browser = Browser::Create(Browser::CreateParams(profile, true));
   ui_test_utils::NavigateToURLWithDisposition(
       browser, gaia_url, WindowOpenDisposition::SINGLETON_TAB,
       ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
diff --git a/chrome/browser/signin/dice_browsertest.cc b/chrome/browser/signin/dice_browsertest.cc
index bb00997..e19249a0 100644
--- a/chrome/browser/signin/dice_browsertest.cc
+++ b/chrome/browser/signin/dice_browsertest.cc
@@ -1061,7 +1061,7 @@
 
 // Checks that Dice is disabled in incognito mode.
 IN_PROC_BROWSER_TEST_F(DiceBrowserTest, Incognito) {
-  Browser* incognito_browser = new Browser(Browser::CreateParams(
+  Browser* incognito_browser = Browser::Create(Browser::CreateParams(
       browser()->profile()->GetPrimaryOTRProfile(), true));
 
   // Check that Dice is disabled.
diff --git a/chrome/browser/site_isolation/chrome_site_per_process_browsertest.cc b/chrome/browser/site_isolation/chrome_site_per_process_browsertest.cc
index d91d2cf5..d8c4ffd7 100644
--- a/chrome/browser/site_isolation/chrome_site_per_process_browsertest.cc
+++ b/chrome/browser/site_isolation/chrome_site_per_process_browsertest.cc
@@ -488,18 +488,15 @@
 // This test is not run on ChromeOS because it registers a custom handler (see
 // ProtocolHandlerRegistry::InstallDefaultsForChromeOS), and handles mailto:
 // navigations before getting to external protocol code.
-// Flaky on Windows. See https://crbug.com/980446
-#if defined(OS_CHROMEOS) || defined(OS_WIN)
-#define MAYBE_LaunchExternalProtocolFromSubframe \
-  DISABLED_LaunchExternalProtocolFromSubframe
-#else
-#define MAYBE_LaunchExternalProtocolFromSubframe \
-  LaunchExternalProtocolFromSubframe
-#endif
+
 // This test verifies that external protocol requests succeed when made from an
 // OOPIF (https://crbug.com/668289).
+
+// Disabled due to flakiness. If enabled, still skip for ChromeOS based on
+// comment above.
+// See https://crbug.com/980446
 IN_PROC_BROWSER_TEST_F(ChromeSitePerProcessTest,
-                       MAYBE_LaunchExternalProtocolFromSubframe) {
+                       DISABLED_LaunchExternalProtocolFromSubframe) {
   GURL start_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
 
   ui_test_utils::NavigateToURL(browser(), start_url);
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc
index afb5beb7..0a06b33 100644
--- a/chrome/browser/sync/chrome_sync_client.cc
+++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -41,6 +41,7 @@
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/themes/theme_syncable_service.h"
+#include "chrome/browser/ui/read_later/reading_list_model_factory.h"
 #include "chrome/browser/undo/bookmark_undo_service_factory.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/browser/web_applications/web_app_sync_bridge.h"
@@ -67,6 +68,8 @@
 #include "components/metrics/demographics/user_demographics.h"
 #include "components/password_manager/core/browser/password_store.h"
 #include "components/prefs/pref_service.h"
+#include "components/reading_list/core/reading_list_model.h"
+#include "components/reading_list/features/reading_list_switches.h"
 #include "components/search_engines/template_url_service.h"
 #include "components/send_tab_to_self/send_tab_to_self_sync_service.h"
 #include "components/spellcheck/spellcheck_buildflags.h"
@@ -629,10 +632,13 @@
 base::WeakPtr<syncer::ModelTypeControllerDelegate>
 ChromeSyncClient::GetControllerDelegateForModelType(syncer::ModelType type) {
   switch (type) {
-    case syncer::READING_LIST:
-      // Reading List is only supported on iOS at the moment.
-      NOTREACHED();
-      return base::WeakPtr<syncer::ModelTypeControllerDelegate>();
+    case syncer::READING_LIST: {
+      DCHECK(reading_list::switches::IsReadingListEnabled());
+      return ReadingListModelFactory::GetForBrowserContext(profile_)
+          ->GetModelTypeSyncBridge()
+          ->change_processor()
+          ->GetControllerDelegate();
+    }
 #if defined(OS_CHROMEOS)
     case syncer::PRINTERS:
       return chromeos::SyncedPrintersManagerFactory::GetForBrowserContext(
diff --git a/chrome/browser/sync/test/integration/sync_test.cc b/chrome/browser/sync/test/integration/sync_test.cc
index 8532c05..1b762c2 100644
--- a/chrome/browser/sync/test/integration/sync_test.cc
+++ b/chrome/browser/sync/test/integration/sync_test.cc
@@ -525,7 +525,7 @@
 
 Browser* SyncTest::AddBrowser(int profile_index) {
   Profile* profile = GetProfile(profile_index);
-  browsers_.push_back(new Browser(Browser::CreateParams(profile, true)));
+  browsers_.push_back(Browser::Create(Browser::CreateParams(profile, true)));
   profiles_.push_back(profile);
 
   return browsers_[browsers_.size() - 1];
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 99d5d95e..1f18795 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1507,8 +1507,7 @@
       "//chrome/browser/resource_coordinator:tab_metrics_event_proto",
       "//chrome/browser/resource_coordinator/tab_ranker",
       "//chrome/browser/safe_browsing:advanced_protection",
-      "//chrome/browser/search/recipe_tasks:mojo_bindings",
-      "//chrome/browser/search/shopping_tasks:mojo_bindings",
+      "//chrome/browser/search/task_module:mojo_bindings",
       "//chrome/browser/ui/color:color_headers",
       "//chrome/browser/ui/color:mixers",
       "//chrome/browser/ui/webui/app_management:mojo_bindings",
diff --git a/chrome/browser/ui/ash/accelerator_commands_browsertest.cc b/chrome/browser/ui/ash/accelerator_commands_browsertest.cc
index 540dad32..6827210 100644
--- a/chrome/browser/ui/ash/accelerator_commands_browsertest.cc
+++ b/chrome/browser/ui/ash/accelerator_commands_browsertest.cc
@@ -102,7 +102,7 @@
                                           gfx::Rect(), browser()->profile(),
                                           true));
 
-  Browser* app_host_browser = new Browser(browser_create_params);
+  Browser* app_host_browser = Browser::Create(browser_create_params);
   ASSERT_FALSE(app_host_browser->is_type_popup());
   ASSERT_TRUE(app_host_browser->is_type_app());
   AddBlankTabAndShow(app_host_browser);
@@ -122,7 +122,7 @@
   // 4) Popup browser windows.
   browser_create_params =
       Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile(), true);
-  Browser* popup_browser = new Browser(browser_create_params);
+  Browser* popup_browser = Browser::Create(browser_create_params);
   ASSERT_TRUE(popup_browser->is_type_popup());
   ASSERT_FALSE(popup_browser->is_type_app());
   AddBlankTabAndShow(popup_browser);
diff --git a/chrome/browser/ui/ash/chrome_new_window_client.cc b/chrome/browser/ui/ash/chrome_new_window_client.cc
index 257515d..9d2ed3e 100644
--- a/chrome/browser/ui/ash/chrome_new_window_client.cc
+++ b/chrome/browser/ui/ash/chrome_new_window_client.cc
@@ -574,7 +574,7 @@
   // |custom_tab_browser| will be destroyed when its tab strip becomes empty,
   // either due to the user opening the custom tab page in a tabbed browser or
   // because of the CustomTabSessionImpl object getting destroyed.
-  auto* custom_tab_browser = new Browser(Browser::CreateParams(
+  auto* custom_tab_browser = Browser::Create(Browser::CreateParams(
       Browser::TYPE_CUSTOM_TAB, profile, /* user_gesture= */ true));
 
   custom_tab_browser->tab_strip_model()->AppendWebContents(
diff --git a/chrome/browser/ui/ash/clipboard_history_browsertest.cc b/chrome/browser/ui/ash/clipboard_history_browsertest.cc
index 951d33dd..cb9d571b 100644
--- a/chrome/browser/ui/ash/clipboard_history_browsertest.cc
+++ b/chrome/browser/ui/ash/clipboard_history_browsertest.cc
@@ -26,9 +26,9 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
-#include "ui/base/clipboard/data_transfer_policy_controller.h"
 #include "ui/base/clipboard/scoped_clipboard_writer.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_policy_controller.h"
 #include "ui/events/test/event_generator.h"
 #include "ui/views/controls/menu/menu_config.h"
 #include "ui/views/controls/menu/menu_item_view.h"
diff --git a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller_browsertest.cc b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller_browsertest.cc
index 05a4b66..2294b0e 100644
--- a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller_browsertest.cc
+++ b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller_browsertest.cc
@@ -45,7 +45,7 @@
 
   // Browsers are not listed in the menu if their windows have not been shown.
   Browser* browser1 =
-      new Browser(Browser::CreateParams(browser()->profile(), true));
+      Browser::Create(Browser::CreateParams(browser()->profile(), true));
   EXPECT_FALSE(browser1->window()->IsVisible());
   EXPECT_EQ(2U, browser_list->size());
   EXPECT_EQ(1U, GetAppMenuItems(controller, ui::EF_NONE).size());
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
index 93aabdb..6d65e45b 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
@@ -2038,7 +2038,7 @@
   // Create a new browser - without activating it - and load an "app" into it.
   Browser::CreateParams params = Browser::CreateParams(profile(), true);
   params.initial_show_state = ui::SHOW_STATE_INACTIVE;
-  Browser* browser2 = new Browser(params);
+  Browser* browser2 = Browser::Create(params);
   controller_->SetRefocusURLPatternForTest(
       shortcut_id, GURL("http://www.example.com/path/*"));
   std::string url = "http://www.example.com/path/bla";
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
index edd297d..9bc528e6 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
@@ -4833,7 +4833,7 @@
       true /* user_gesture */);
   params.window = browser()->window();
   params.type = Browser::TYPE_NORMAL;
-  Browser* b = new Browser(params);
+  Browser* b = Browser::Create(params);
   set_browser(b);
   chrome::NewTab(browser());
   browser()->window()->Show();
diff --git a/chrome/browser/ui/ash/tablet_mode_page_behavior_browsertest.cc b/chrome/browser/ui/ash/tablet_mode_page_behavior_browsertest.cc
index 65534b28..b0e30fdc 100644
--- a/chrome/browser/ui/ash/tablet_mode_page_behavior_browsertest.cc
+++ b/chrome/browser/ui/ash/tablet_mode_page_behavior_browsertest.cc
@@ -139,7 +139,7 @@
       "test_browser_app", true /* trusted_source */, gfx::Rect(),
       browser()->profile(), true);
   params.initial_show_state = ui::SHOW_STATE_DEFAULT;
-  Browser* browser = new Browser(params);
+  Browser* browser = Browser::Create(params);
   AddBlankTabAndShow(browser);
 
   ASSERT_TRUE(browser->is_type_app());
diff --git a/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.cc b/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.cc
index d06cd8d..fad189c 100644
--- a/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.cc
+++ b/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.cc
@@ -45,6 +45,6 @@
   if (!browser_) {
     browser_ = chrome::FindLastActiveWithProfile(profile_);
     if (!browser_)
-      browser_ = new Browser(Browser::CreateParams(profile_, true));
+      browser_ = Browser::Create(Browser::CreateParams(profile_, true));
   }
 }
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index f7cd37d..50f91ea 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -73,6 +73,7 @@
 #include "chrome/browser/printing/background_printing_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_destroyer.h"
+#include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/profiles/profile_metrics.h"
 #include "chrome/browser/profiles/profiles_state.h"
 #include "chrome/browser/repost_form_warning_controller.h"
@@ -326,7 +327,9 @@
 bool CanCreateBrowserForProfile(Profile* profile) {
   return IncognitoModePrefs::CanOpenBrowser(profile) &&
          (!profile->IsGuestSession() || profile->IsOffTheRecord()) &&
-         profile->AllowsBrowserWindows();
+         profile->AllowsBrowserWindows() &&
+         !ProfileManager::IsProfileDirectoryMarkedForDeletion(
+             profile->GetPath());
 }
 bool IsOnKioskSplashScreen() {
 #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc
index f587e352a..9bab58c1 100644
--- a/chrome/browser/ui/browser_browsertest.cc
+++ b/chrome/browser/ui/browser_browsertest.cc
@@ -1350,7 +1350,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(BrowserTest, OverscrollEnabledInPopups) {
-  Browser* popup_browser = new Browser(
+  Browser* popup_browser = Browser::Create(
       Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile(), true));
   ASSERT_TRUE(popup_browser->is_type_popup());
   EXPECT_TRUE(popup_browser->CanOverscrollContent());
@@ -1601,7 +1601,7 @@
                                                browser()->profile(), true)};
   for (size_t i = 0; i < base::size(params); ++i) {
     params[i].initial_show_state = ui::SHOW_STATE_MAXIMIZED;
-    AddBlankTabAndShow(new Browser(params[i]));
+    AddBlankTabAndShow(Browser::Create(params[i]));
   }
 }
 
@@ -1618,7 +1618,7 @@
                                                browser()->profile(), true)};
   for (size_t i = 0; i < base::size(params); ++i) {
     params[i].initial_show_state = ui::SHOW_STATE_MINIMIZED;
-    AddBlankTabAndShow(new Browser(params[i]));
+    AddBlankTabAndShow(Browser::Create(params[i]));
   }
 }
 
@@ -1681,7 +1681,7 @@
   EXPECT_TRUE(command_updater->IsCommandEnabled(IDC_NEW_INCOGNITO_WINDOW));
 
   // Create a new browser.
-  Browser* new_browser = new Browser(Browser::CreateParams(
+  Browser* new_browser = Browser::Create(Browser::CreateParams(
       browser()->profile()->GetPrimaryOTRProfile(), true));
   CommandUpdater* new_command_updater = new_browser->command_controller();
   // It should have Bookmarks & Settings commands disabled by default.
@@ -1696,7 +1696,7 @@
 
 #if defined(OS_CHROMEOS)
 IN_PROC_BROWSER_TEST_F(BrowserTest, ArcBrowserWindowFeaturesSetCorrectly) {
-  Browser* new_browser = new Browser(
+  Browser* new_browser = Browser::Create(
       Browser::CreateParams(Browser::TYPE_CUSTOM_TAB, browser()->profile(),
                             /* user_gesture= */ true));
   ASSERT_TRUE(new_browser);
@@ -1736,7 +1736,7 @@
 
   // Create a new browser.
   Browser* new_browser =
-      new Browser(Browser::CreateParams(browser()->profile(), true));
+      Browser::Create(Browser::CreateParams(browser()->profile(), true));
   CommandUpdater* new_command_updater = new_browser->command_controller();
   EXPECT_FALSE(new_command_updater->IsCommandEnabled(IDC_NEW_INCOGNITO_WINDOW));
   EXPECT_TRUE(new_command_updater->IsCommandEnabled(IDC_NEW_WINDOW));
@@ -1782,7 +1782,7 @@
 
   // Create a popup (non-main-UI-type) browser. Settings command as well
   // as Extensions should be disabled.
-  Browser* popup_browser = new Browser(
+  Browser* popup_browser = Browser::Create(
       Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile(), true));
   CommandUpdater* popup_command_updater = popup_browser->command_controller();
   EXPECT_FALSE(popup_command_updater->IsCommandEnabled(IDC_MANAGE_EXTENSIONS));
@@ -1797,7 +1797,7 @@
 IN_PROC_BROWSER_TEST_F(BrowserTest,
                        DisableOptionsAndImportMenuItemsConsistently) {
   // Create a popup browser.
-  Browser* popup_browser = new Browser(
+  Browser* popup_browser = Browser::Create(
       Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile(), true));
   CommandUpdater* command_updater = popup_browser->command_controller();
   // OPTIONS and IMPORT_SETTINGS are disabled for a non-normal UI.
@@ -1921,7 +1921,7 @@
   EXPECT_EQ(1, browser()->tab_strip_model()->count());
 
   // Open a popup browser with a single blank foreground tab.
-  Browser* popup_browser = new Browser(
+  Browser* popup_browser = Browser::Create(
       Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile()));
   chrome::AddTabAt(popup_browser, GURL(), -1, true);
   EXPECT_EQ(1, popup_browser->tab_strip_model()->count());
@@ -1938,7 +1938,7 @@
   EXPECT_EQ(2, browser()->tab_strip_model()->count());
 
   // Open an app frame browser with a single blank foreground tab.
-  Browser* app_browser = new Browser(Browser::CreateParams::CreateForApp(
+  Browser* app_browser = Browser::Create(Browser::CreateParams::CreateForApp(
       L"Test", browser()->profile(), false));
   chrome::AddTabAt(app_browser, GURL(), -1, true);
   EXPECT_EQ(1, app_browser->tab_strip_model()->count());
@@ -1956,8 +1956,9 @@
   EXPECT_EQ(3, browser()->tab_strip_model()->count());
 
   // Open an app frame popup browser with a single blank foreground tab.
-  Browser* app_popup_browser = new Browser(Browser::CreateParams::CreateForApp(
-      L"Test", browser()->profile(), false));
+  Browser* app_popup_browser = Browser::Create(
+      Browser::CreateParams::CreateForApp(
+          L"Test", browser()->profile(), false));
   chrome::AddTabAt(app_popup_browser, GURL(), -1, true);
   EXPECT_EQ(1, app_popup_browser->tab_strip_model()->count());
 
@@ -2697,7 +2698,7 @@
     Browser::CreateParams params(Browser::TYPE_POPUP, browser()->profile(),
                                  true);
     params.initial_bounds = gfx::Rect(0, 0, 100, 122);
-    Browser* browser = new Browser(params);
+    Browser* browser = Browser::Create(params);
     gfx::Rect bounds = browser->window()->GetBounds();
 
     // Should be EXPECT_EQ, but this width is inconsistent across platforms.
@@ -2716,7 +2717,7 @@
                                  true);
     params.initial_bounds = gfx::Rect(0, 0, 100, 122);
     params.trusted_source = true;
-    Browser* browser = new Browser(params);
+    Browser* browser = Browser::Create(params);
     gfx::Rect bounds = browser->window()->GetBounds();
 
     // Should be EXPECT_EQ, but this width is inconsistent across platforms.
@@ -2732,7 +2733,7 @@
     Browser::CreateParams params = Browser::CreateParams::CreateForApp(
         "app-name", false, gfx::Rect(0, 0, 100, 122), browser()->profile(),
         true);
-    Browser* browser = new Browser(params);
+    Browser* browser = Browser::Create(params);
     gfx::Rect bounds = browser->window()->GetBounds();
 
     // Should be EXPECT_EQ, but this width is inconsistent across platforms.
@@ -2748,7 +2749,7 @@
     Browser::CreateParams params = Browser::CreateParams::CreateForApp(
         "app-name", true, gfx::Rect(0, 0, 100, 122), browser()->profile(),
         true);
-    Browser* browser = new Browser(params);
+    Browser* browser = Browser::Create(params);
     gfx::Rect bounds = browser->window()->GetBounds();
 
     // Should be EXPECT_EQ, but this width is inconsistent across platforms.
@@ -2764,7 +2765,7 @@
     Browser::CreateParams params =
         Browser::CreateParams::CreateForDevTools(browser()->profile());
     params.initial_bounds = gfx::Rect(0, 0, 100, 122);
-    Browser* browser = new Browser(params);
+    Browser* browser = Browser::Create(params);
     gfx::Rect bounds = browser->window()->GetBounds();
 
     // Should be EXPECT_EQ, but this width is inconsistent across platforms.
diff --git a/chrome/browser/ui/browser_close_unittest.cc b/chrome/browser/ui/browser_close_unittest.cc
index 61b4dbb..b32f536 100644
--- a/chrome/browser/ui/browser_close_unittest.cc
+++ b/chrome/browser/ui/browser_close_unittest.cc
@@ -167,7 +167,7 @@
       Browser::CreateParams params(profile, true);
       params.type = Browser::TYPE_NORMAL;
       params.window = window;
-      Browser* browser = new Browser(params);
+      Browser* browser = Browser::Create(params);
 
       windows.push_back(window);
       browsers.push_back(browser);
diff --git a/chrome/browser/ui/browser_command_controller_unittest.cc b/chrome/browser/ui/browser_command_controller_unittest.cc
index 9abe0c4..9a1435e 100644
--- a/chrome/browser/ui/browser_command_controller_unittest.cc
+++ b/chrome/browser/ui/browser_command_controller_unittest.cc
@@ -119,7 +119,7 @@
       /*trusted_source=*/true, browser()->window()->GetBounds(), profile(),
       /*user_gesture=*/true);
   params.window = browser()->window();
-  set_browser(new Browser(params));
+  set_browser(Browser::Create(params));
 
   ASSERT_TRUE(browser()->is_type_app());
 
@@ -193,7 +193,7 @@
       /*trusted_source=*/true, browser()->window()->GetBounds(), profile(),
       /*user_gesture=*/true);
   params.window = browser()->window();
-  set_browser(new Browser(params));
+  set_browser(Browser::Create(params));
   ASSERT_TRUE(browser()->is_type_app());
   browser()->command_controller()->FullscreenStateChanged();
   EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_FULLSCREEN));
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc
index 3268845f..af6d4156 100644
--- a/chrome/browser/ui/browser_commands.cc
+++ b/chrome/browser/ui/browser_commands.cc
@@ -185,11 +185,11 @@
     const Browser* original_browser) {
   Browser* new_browser = nullptr;
   if (original_browser->deprecated_is_app()) {
-    new_browser = new Browser(Browser::CreateParams::CreateForApp(
+    new_browser = Browser::Create(Browser::CreateParams::CreateForApp(
         original_browser->app_name(), original_browser->is_trusted_source(),
         gfx::Rect(), original_browser->profile(), true));
   } else {
-    new_browser = new Browser(Browser::CreateParams(
+    new_browser = Browser::Create(Browser::CreateParams(
         original_browser->type(), original_browser->profile(), true));
   }
   // Preserve the size of the original window. The new window has already
@@ -281,7 +281,7 @@
       std::unique_ptr<WebContents> new_tab = current_tab->Clone();
       WebContents* raw_new_tab = new_tab.get();
       Browser* new_browser =
-          new Browser(Browser::CreateParams(browser->profile(), true));
+          Browser::Create(Browser::CreateParams(browser->profile(), true));
       new_browser->tab_strip_model()->AddWebContents(std::move(new_tab), -1,
                                                      ui::PAGE_TRANSITION_LINK,
                                                      TabStripModel::ADD_ACTIVE);
@@ -447,8 +447,8 @@
 }
 
 Browser* OpenEmptyWindow(Profile* profile) {
-  Browser* browser =
-      new Browser(Browser::CreateParams(Browser::TYPE_NORMAL, profile, true));
+  Browser* browser = Browser::Create(
+      Browser::CreateParams(Browser::TYPE_NORMAL, profile, true));
   AddTabAt(browser, GURL(), -1, true);
   browser->window()->Show();
   return browser;
@@ -780,7 +780,7 @@
     return;
 
   Browser* new_browser =
-      new Browser(Browser::CreateParams(browser->profile(), true));
+      Browser::Create(Browser::CreateParams(browser->profile(), true));
 
   if (group.has_value()) {
     const tab_groups::TabGroupVisualData* old_visual_data =
@@ -944,7 +944,7 @@
   TabStripModel* tab_strip = browser->tab_strip_model();
   std::unique_ptr<content::WebContents> contents =
       tab_strip->DetachWebContentsAt(tab_strip->active_index());
-  Browser* b = new Browser(Browser::CreateParams(browser->profile(), true));
+  Browser* b = Browser::Create(Browser::CreateParams(browser->profile(), true));
   b->tab_strip_model()->AppendWebContents(std::move(contents), true);
   b->window()->Show();
 }
@@ -1514,8 +1514,8 @@
       chrome::FindTabbedBrowser(hosted_app_browser->profile(), false);
 
   if (!target_browser) {
-    target_browser =
-        new Browser(Browser::CreateParams(hosted_app_browser->profile(), true));
+    target_browser = Browser::Create(
+        Browser::CreateParams(hosted_app_browser->profile(), true));
   }
 
   TabStripModel* source_tabstrip = hosted_app_browser->tab_strip_model();
diff --git a/chrome/browser/ui/browser_focus_uitest.cc b/chrome/browser/ui/browser_focus_uitest.cc
index 2ab155bb..6cf49c6 100644
--- a/chrome/browser/ui/browser_focus_uitest.cc
+++ b/chrome/browser/ui/browser_focus_uitest.cc
@@ -335,7 +335,7 @@
 
   // Open a new browser window.
   Browser* background_browser =
-      new Browser(Browser::CreateParams(browser()->profile(), true));
+      Browser::Create(Browser::CreateParams(browser()->profile(), true));
   chrome::AddTabAt(background_browser, GURL(), -1, true);
   background_browser->window()->Show();
 
diff --git a/chrome/browser/ui/browser_live_tab_context.cc b/chrome/browser/ui/browser_live_tab_context.cc
index 0d8d967..dcfb292 100644
--- a/chrome/browser/ui/browser_live_tab_context.cc
+++ b/chrome/browser/ui/browser_live_tab_context.cc
@@ -241,7 +241,7 @@
   create_params->initial_show_state = show_state;
   create_params->initial_workspace = workspace;
   create_params->user_title = user_title;
-  Browser* browser = new Browser(*create_params.get());
+  Browser* browser = Browser::Create(*create_params.get());
   return browser->live_tab_context();
 }
 
diff --git a/chrome/browser/ui/browser_mac.cc b/chrome/browser/ui/browser_mac.cc
index 9719eba..cb9af29 100644
--- a/chrome/browser/ui/browser_mac.cc
+++ b/chrome/browser/ui/browser_mac.cc
@@ -11,55 +11,55 @@
 namespace chrome {
 
 void OpenAboutWindow(Profile* profile) {
-  Browser* browser = new Browser(Browser::CreateParams(profile, true));
+  Browser* browser = Browser::Create(Browser::CreateParams(profile, true));
   ShowAboutChrome(browser);
   browser->window()->Show();
 }
 
 void OpenHistoryWindow(Profile* profile) {
-  Browser* browser = new Browser(Browser::CreateParams(profile, true));
+  Browser* browser = Browser::Create(Browser::CreateParams(profile, true));
   ShowHistory(browser);
   browser->window()->Show();
 }
 
 void OpenDownloadsWindow(Profile* profile) {
-  Browser* browser = new Browser(Browser::CreateParams(profile, true));
+  Browser* browser = Browser::Create(Browser::CreateParams(profile, true));
   ShowDownloads(browser);
   browser->window()->Show();
 }
 
 void OpenHelpWindow(Profile* profile, HelpSource source) {
-  Browser* browser = new Browser(Browser::CreateParams(profile, true));
+  Browser* browser = Browser::Create(Browser::CreateParams(profile, true));
   ShowHelp(browser, source);
   browser->window()->Show();
 }
 
 void OpenOptionsWindow(Profile* profile) {
-  Browser* browser = new Browser(Browser::CreateParams(profile, true));
+  Browser* browser = Browser::Create(Browser::CreateParams(profile, true));
   ShowSettings(browser);
   browser->window()->Show();
 }
 
 void OpenClearBrowsingDataDialogWindow(Profile* profile) {
-  Browser* browser = new Browser(Browser::CreateParams(profile, true));
+  Browser* browser = Browser::Create(Browser::CreateParams(profile, true));
   ShowClearBrowsingDataDialog(browser);
   browser->window()->Show();
 }
 
 void OpenImportSettingsDialogWindow(Profile* profile) {
-  Browser* browser = new Browser(Browser::CreateParams(profile, true));
+  Browser* browser = Browser::Create(Browser::CreateParams(profile, true));
   ShowImportDialog(browser);
   browser->window()->Show();
 }
 
 void OpenBookmarkManagerWindow(Profile* profile) {
-  Browser* browser = new Browser(Browser::CreateParams(profile, true));
+  Browser* browser = Browser::Create(Browser::CreateParams(profile, true));
   ShowBookmarkManager(browser);
   browser->window()->Show();
 }
 
 void OpenExtensionsWindow(Profile* profile) {
-  Browser* browser = new Browser(Browser::CreateParams(profile, true));
+  Browser* browser = Browser::Create(Browser::CreateParams(profile, true));
   ShowExtensions(browser, std::string());
   browser->window()->Show();
 }
diff --git a/chrome/browser/ui/browser_navigator.cc b/chrome/browser/ui/browser_navigator.cc
index b81376c..15e4aa9d 100644
--- a/chrome/browser/ui/browser_navigator.cc
+++ b/chrome/browser/ui/browser_navigator.cc
@@ -165,7 +165,7 @@
     if (app_id) {
       std::string app_name = web_app::GenerateApplicationNameFromAppId(*app_id);
       return {
-          new Browser(Browser::CreateParams::CreateForApp(
+          Browser::Create(Browser::CreateParams::CreateForApp(
               app_name,
               true,  // trusted_source. Installed PWAs are considered trusted.
               params.window_bounds, profile, params.user_gesture)),
@@ -235,17 +235,18 @@
                                              params.user_gesture);
         browser_params.trusted_source = params.trusted_source;
         browser_params.initial_bounds = params.window_bounds;
-        return {new Browser(browser_params), -1};
+        return {Browser::Create(browser_params), -1};
       }
-      return {new Browser(Browser::CreateParams::CreateForAppPopup(
+      return {Browser::Create(Browser::CreateParams::CreateForAppPopup(
                   app_name, params.trusted_source, params.window_bounds,
                   profile, params.user_gesture)),
               -1};
     }
     case WindowOpenDisposition::NEW_WINDOW:
       // Make a new normal browser window.
-      return {new Browser(Browser::CreateParams(profile, params.user_gesture)),
-              -1};
+      return {
+          Browser::Create(Browser::CreateParams(profile, params.user_gesture)),
+          -1};
     case WindowOpenDisposition::OFF_THE_RECORD:
       // Make or find an incognito window.
       return {GetOrCreateBrowser(profile->GetPrimaryOTRProfile(),
diff --git a/chrome/browser/ui/browser_navigator_browsertest.cc b/chrome/browser/ui/browser_navigator_browsertest.cc
index 8170d79..50cc161 100644
--- a/chrome/browser/ui/browser_navigator_browsertest.cc
+++ b/chrome/browser/ui/browser_navigator_browsertest.cc
@@ -134,13 +134,14 @@
 
 Browser* BrowserNavigatorTest::CreateEmptyBrowserForType(Browser::Type type,
                                                          Profile* profile) {
-  Browser* browser = new Browser(Browser::CreateParams(type, profile, true));
+  Browser* browser =
+      Browser::Create(Browser::CreateParams(type, profile, true));
   chrome::AddTabAt(browser, GURL(), -1, true);
   return browser;
 }
 
 Browser* BrowserNavigatorTest::CreateEmptyBrowserForApp(Profile* profile) {
-  Browser* browser = new Browser(Browser::CreateParams::CreateForApp(
+  Browser* browser = Browser::Create(Browser::CreateParams::CreateForApp(
       "Test", false /* trusted_source */, gfx::Rect(), profile, true));
   chrome::AddTabAt(browser, GURL(), -1, true);
   return browser;
diff --git a/chrome/browser/ui/browser_tab_strip_model_delegate.cc b/chrome/browser/ui/browser_tab_strip_model_delegate.cc
index a24863c..aeb0575b 100644
--- a/chrome/browser/ui/browser_tab_strip_model_delegate.cc
+++ b/chrome/browser/ui/browser_tab_strip_model_delegate.cc
@@ -61,7 +61,7 @@
   params.initial_bounds = window_bounds;
   params.initial_show_state =
       maximize ? ui::SHOW_STATE_MAXIMIZED : ui::SHOW_STATE_NORMAL;
-  Browser* browser = new Browser(params);
+  Browser* browser = Browser::Create(params);
   TabStripModel* new_model = browser->tab_strip_model();
 
   for (size_t i = 0; i < contentses.size(); ++i) {
diff --git a/chrome/browser/ui/chrome_pages.cc b/chrome/browser/ui/chrome_pages.cc
index fd344be..6683c0e6 100644
--- a/chrome/browser/ui/chrome_pages.cc
+++ b/chrome/browser/ui/chrome_pages.cc
@@ -338,7 +338,7 @@
 #endif
   Browser* browser = chrome::FindTabbedBrowser(profile, false);
   if (!browser)
-    browser = new Browser(Browser::CreateParams(profile, true));
+    browser = Browser::Create(Browser::CreateParams(profile, true));
   ShowSettingsSubPageInTabbedBrowser(browser, sub_page);
 }
 
diff --git a/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript_test.mm b/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript_test.mm
index 7b6727da..09e5c6bc 100644
--- a/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript_test.mm
+++ b/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript_test.mm
@@ -27,9 +27,9 @@
 IN_PROC_BROWSER_TEST_F(BrowserCrApplicationAppleScriptTest, Creation) {
   // Create additional |Browser*| objects of different type.
   Profile* profile = browser()->profile();
-  Browser* b1 =
-      new Browser(Browser::CreateParams(Browser::TYPE_POPUP, profile, true));
-  Browser* b2 = new Browser(Browser::CreateParams::CreateForApp(
+  Browser* b1 = Browser::Create(
+      Browser::CreateParams(Browser::TYPE_POPUP, profile, true));
+  Browser* b2 = Browser::Create(Browser::CreateParams::CreateForApp(
       "Test", true /* trusted_source */, gfx::Rect(), profile, true));
 
   EXPECT_EQ(3U, [[NSApp appleScriptWindows] count]);
diff --git a/chrome/browser/ui/cocoa/applescript/window_applescript.mm b/chrome/browser/ui/cocoa/applescript/window_applescript.mm
index 939813d..7ddb678 100644
--- a/chrome/browser/ui/cocoa/applescript/window_applescript.mm
+++ b/chrome/browser/ui/cocoa/applescript/window_applescript.mm
@@ -77,7 +77,7 @@
   }
 
   if ((self = [super init])) {
-    _browser = new Browser(Browser::CreateParams(aProfile, false));
+    _browser = Browser::Create(Browser::CreateParams(aProfile, false));
     chrome::NewTab(_browser);
     _browser->window()->Show();
     base::scoped_nsobject<NSNumber> numID(
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.mm
index db13f0e..c0e9905 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.mm
@@ -96,7 +96,8 @@
 - (void)openURLForNode:(const BookmarkNode*)node {
   Browser* browser = chrome::FindTabbedBrowser(_bridge->GetProfile(), true);
   if (!browser) {
-    browser = new Browser(Browser::CreateParams(_bridge->GetProfile(), true));
+    browser =
+        Browser::Create(Browser::CreateParams(_bridge->GetProfile(), true));
   }
   WindowOpenDisposition disposition =
       ui::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
diff --git a/chrome/browser/ui/cocoa/notifications/BUILD.gn b/chrome/browser/ui/cocoa/notifications/BUILD.gn
index be88b8a..722621ed 100644
--- a/chrome/browser/ui/cocoa/notifications/BUILD.gn
+++ b/chrome/browser/ui/cocoa/notifications/BUILD.gn
@@ -15,8 +15,10 @@
   sources = [
     "alert_notification_service.h",
     "alert_notification_service.mm",
-    "notification_service_delegate.h",
-    "notification_service_delegate.mm",
+    "alert_nsnotification_service.h",
+    "alert_nsnotification_service.mm",
+    "service_delegate.h",
+    "service_delegate.mm",
     "xpc_service_main.mm",
     "xpc_transaction_handler.h",
     "xpc_transaction_handler.mm",
diff --git a/chrome/browser/ui/cocoa/notifications/alert_notification_service.h b/chrome/browser/ui/cocoa/notifications/alert_notification_service.h
index 0037643..999b5ee 100644
--- a/chrome/browser/ui/cocoa/notifications/alert_notification_service.h
+++ b/chrome/browser/ui/cocoa/notifications/alert_notification_service.h
@@ -13,8 +13,10 @@
 
 // Implementation of the NotificationDelivery protocol that can display
 // notifications of type alert.
-@interface AlertNotificationService : NSObject<NotificationDelivery>
-- (instancetype)initWithTransactionHandler:(XPCTransactionHandler*)handler;
+@interface AlertNotificationService : NSObject <NotificationDelivery>
+- (instancetype)initWithTransactionHandler:(XPCTransactionHandler*)handler
+                             xpcConnection:(NSXPCConnection*)connection;
+
 @end
 
 #endif  // CHROME_BROWSER_UI_COCOA_NOTIFICATIONS_ALERT_NOTIFICATION_SERVICE_H_
diff --git a/chrome/browser/ui/cocoa/notifications/alert_notification_service.mm b/chrome/browser/ui/cocoa/notifications/alert_notification_service.mm
index 3df0614..2a9282d 100644
--- a/chrome/browser/ui/cocoa/notifications/alert_notification_service.mm
+++ b/chrome/browser/ui/cocoa/notifications/alert_notification_service.mm
@@ -4,20 +4,15 @@
 
 #import "chrome/browser/ui/cocoa/notifications/alert_notification_service.h"
 
-#include <unistd.h>
-
-#import "base/mac/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/notreached.h"
 #include "base/strings/string_number_conversions.h"
-#import "chrome/browser/ui/cocoa/notifications/notification_builder_mac.h"
-#include "chrome/browser/ui/cocoa/notifications/notification_constants_mac.h"
+#import "chrome/browser/ui/cocoa/notifications/alert_nsnotification_service.h"
 #import "chrome/browser/ui/cocoa/notifications/xpc_transaction_handler.h"
 #include "third_party/crashpad/crashpad/client/crashpad_client.h"
 #include "third_party/crashpad/crashpad/client/crashpad_info.h"
 #include "third_party/crashpad/crashpad/client/simple_string_dictionary.h"
 
-@class NSUserNotificationCenter;
-
 namespace {
 
 crashpad::SimpleStringDictionary* GetCrashpadAnnotations() {
@@ -33,7 +28,9 @@
 }  // namespace
 
 @implementation AlertNotificationService {
-  XPCTransactionHandler* _transactionHandler;
+  base::scoped_nsobject<XPCTransactionHandler> _transactionHandler;
+  base::scoped_nsobject<NSXPCConnection> _connection;
+  base::scoped_nsobject<NSObject<NotificationDelivery>> _notificationDelivery;
 
   // Ensures that the XPC service has been configured for crash reporting.
   // Other messages should not be sent to a new instance of the service
@@ -43,14 +40,17 @@
   BOOL _didSetExceptionPort;
 }
 
-- (instancetype)initWithTransactionHandler:(XPCTransactionHandler*)handler {
+- (instancetype)initWithTransactionHandler:(XPCTransactionHandler*)handler
+                             xpcConnection:(NSXPCConnection*)connection {
   if ((self = [super init])) {
-    _transactionHandler = handler;
+    _transactionHandler.reset([handler retain]);
+    _connection.reset([connection retain]);
   }
   return self;
 }
 
-- (void)setMachExceptionPort:(CrXPCMachPort*)port {
+- (void)setUseUNNotification:(BOOL)useUNNotification
+           machExceptionPort:(CrXPCMachPort*)port {
   base::mac::ScopedMachSendRight sendRight([port takeRight]);
   if (!sendRight.is_valid()) {
     NOTREACHED();
@@ -62,6 +62,11 @@
       return;
     }
 
+    [_transactionHandler setUseUNNotification:useUNNotification];
+    _notificationDelivery.reset([[AlertNSNotificationService alloc]
+        initWithTransactionHandler:_transactionHandler
+                     xpcConnection:_connection]);
+
     crashpad::CrashpadClient client;
     _didSetExceptionPort = client.SetHandlerMachPort(std::move(sendRight));
     DCHECK(_didSetExceptionPort);
@@ -73,68 +78,35 @@
 
 - (void)deliverNotification:(NSDictionary*)notificationData {
   DCHECK(_didSetExceptionPort);
+  DCHECK(_notificationDelivery);
 
-  base::scoped_nsobject<NotificationBuilder> builder(
-      [[NotificationBuilder alloc] initWithDictionary:notificationData]);
-
-  NSUserNotification* toast = [builder buildUserNotification];
-  [[NSUserNotificationCenter defaultUserNotificationCenter]
-      deliverNotification:toast];
-  [_transactionHandler openTransactionIfNeeded];
+  [_notificationDelivery deliverNotification:notificationData];
 }
 
 - (void)closeNotificationWithId:(NSString*)notificationId
                   withProfileId:(NSString*)profileId {
   DCHECK(_didSetExceptionPort);
+  DCHECK(_notificationDelivery);
 
-  NSUserNotificationCenter* notificationCenter =
-      [NSUserNotificationCenter defaultUserNotificationCenter];
-  for (NSUserNotification* candidate in
-       [notificationCenter deliveredNotifications]) {
-    NSString* candidateId = [candidate.userInfo
-        objectForKey:notification_constants::kNotificationId];
-
-    NSString* candidateProfileId = [candidate.userInfo
-        objectForKey:notification_constants::kNotificationProfileId];
-
-    if ([candidateId isEqualToString:notificationId] &&
-        [profileId isEqualToString:candidateProfileId]) {
-      [notificationCenter removeDeliveredNotification:candidate];
-      [_transactionHandler closeTransactionIfNeeded];
-      break;
-    }
-  }
+  [_notificationDelivery closeNotificationWithId:notificationId
+                                   withProfileId:profileId];
 }
 
 - (void)closeAllNotifications {
   DCHECK(_didSetExceptionPort);
+  DCHECK(_notificationDelivery);
 
-  [[NSUserNotificationCenter defaultUserNotificationCenter]
-      removeAllDeliveredNotifications];
-  [_transactionHandler closeTransactionIfNeeded];
+  [_notificationDelivery closeAllNotifications];
 }
 
 - (void)getDisplayedAlertsForProfileId:(NSString*)profileId
                           andIncognito:(BOOL)incognito
                              withReply:(void (^)(NSArray*))reply {
-  NSUserNotificationCenter* notificationCenter =
-      [NSUserNotificationCenter defaultUserNotificationCenter];
-  NSMutableArray* notificationIds = [NSMutableArray
-      arrayWithCapacity:[[notificationCenter deliveredNotifications] count]];
-  for (NSUserNotification* toast in
-       [notificationCenter deliveredNotifications]) {
-    NSString* candidateProfileId = [toast.userInfo
-        objectForKey:notification_constants::kNotificationProfileId];
-    BOOL incognitoNotification = [[toast.userInfo
-        objectForKey:notification_constants::kNotificationIncognito] boolValue];
-    if ([candidateProfileId isEqualToString:profileId] &&
-        incognito == incognitoNotification) {
-      [notificationIds
-          addObject:[toast.userInfo
-                        objectForKey:notification_constants::kNotificationId]];
-    }
-  }
-  reply(notificationIds);
+  DCHECK(_notificationDelivery);
+
+  [_notificationDelivery getDisplayedAlertsForProfileId:profileId
+                                           andIncognito:incognito
+                                              withReply:reply];
 }
 
 @end
diff --git a/chrome/browser/ui/cocoa/notifications/alert_nsnotification_service.h b/chrome/browser/ui/cocoa/notifications/alert_nsnotification_service.h
new file mode 100644
index 0000000..058ff958
--- /dev/null
+++ b/chrome/browser/ui/cocoa/notifications/alert_nsnotification_service.h
@@ -0,0 +1,24 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_COCOA_NOTIFICATIONS_ALERT_NSNOTIFICATION_SERVICE_H_
+#define CHROME_BROWSER_UI_COCOA_NOTIFICATIONS_ALERT_NSNOTIFICATION_SERVICE_H_
+
+#import <Foundation/Foundation.h>
+
+#import "chrome/browser/ui/cocoa/notifications/notification_delivery.h"
+
+@class XPCTransactionHandler;
+
+// Implementation of the NotificationDelivery protocol that can display
+// notifications of type alert. This uses the legacy NSUserNotificationCenter
+// API and is meant for use on macOS versions 10.10 - 10.14. Versions 10.14 and
+// above are meant to be supported using UNUserNotificationCenter.
+@interface AlertNSNotificationService
+    : NSObject <NotificationDelivery, NSUserNotificationCenterDelegate>
+- (instancetype)initWithTransactionHandler:(XPCTransactionHandler*)handler
+                             xpcConnection:(NSXPCConnection*)connection;
+@end
+
+#endif  // CHROME_BROWSER_UI_COCOA_NOTIFICATIONS_ALERT_NSNOTIFICATION_SERVICE_H_
diff --git a/chrome/browser/ui/cocoa/notifications/alert_nsnotification_service.mm b/chrome/browser/ui/cocoa/notifications/alert_nsnotification_service.mm
new file mode 100644
index 0000000..33c3aaf
--- /dev/null
+++ b/chrome/browser/ui/cocoa/notifications/alert_nsnotification_service.mm
@@ -0,0 +1,128 @@
+// 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/browser/ui/cocoa/notifications/alert_nsnotification_service.h"
+
+#import "base/mac/scoped_nsobject.h"
+#include "base/notreached.h"
+#import "chrome/browser/ui/cocoa/notifications/notification_builder_mac.h"
+#include "chrome/browser/ui/cocoa/notifications/notification_constants_mac.h"
+#import "chrome/browser/ui/cocoa/notifications/notification_response_builder_mac.h"
+#import "chrome/browser/ui/cocoa/notifications/xpc_transaction_handler.h"
+
+@class NSUserNotificationCenter;
+
+@implementation AlertNSNotificationService {
+  base::scoped_nsobject<XPCTransactionHandler> _transactionHandler;
+  base::scoped_nsobject<NSXPCConnection> _connection;
+}
+
+- (instancetype)initWithTransactionHandler:(XPCTransactionHandler*)handler
+                             xpcConnection:(NSXPCConnection*)connection {
+  if ((self = [super init])) {
+    [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:self];
+    _transactionHandler.reset([handler retain]);
+    _connection.reset([connection retain]);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:nil];
+  [super dealloc];
+}
+
+- (void)setUseUNNotification:(BOOL)useUNNotification
+           machExceptionPort:(CrXPCMachPort*)port {
+  NOTREACHED();
+}
+
+- (void)deliverNotification:(NSDictionary*)notificationData {
+  base::scoped_nsobject<NotificationBuilder> builder(
+      [[NotificationBuilder alloc] initWithDictionary:notificationData]);
+
+  NSUserNotification* toast = [builder buildUserNotification];
+  [[NSUserNotificationCenter defaultUserNotificationCenter]
+      deliverNotification:toast];
+  [_transactionHandler openTransactionIfNeeded];
+}
+
+- (void)closeNotificationWithId:(NSString*)notificationId
+                  withProfileId:(NSString*)profileId {
+  NSUserNotificationCenter* notificationCenter =
+      [NSUserNotificationCenter defaultUserNotificationCenter];
+  for (NSUserNotification* candidate in
+       [notificationCenter deliveredNotifications]) {
+    NSString* candidateId = [candidate.userInfo
+        objectForKey:notification_constants::kNotificationId];
+
+    NSString* candidateProfileId = [candidate.userInfo
+        objectForKey:notification_constants::kNotificationProfileId];
+
+    if ([candidateId isEqualToString:notificationId] &&
+        [profileId isEqualToString:candidateProfileId]) {
+      [notificationCenter removeDeliveredNotification:candidate];
+      [_transactionHandler closeTransactionIfNeeded];
+      break;
+    }
+  }
+}
+
+- (void)closeAllNotifications {
+  [[NSUserNotificationCenter defaultUserNotificationCenter]
+      removeAllDeliveredNotifications];
+  [_transactionHandler closeTransactionIfNeeded];
+}
+
+- (void)getDisplayedAlertsForProfileId:(NSString*)profileId
+                          andIncognito:(BOOL)incognito
+                             withReply:(void (^)(NSArray*))reply {
+  NSUserNotificationCenter* notificationCenter =
+      [NSUserNotificationCenter defaultUserNotificationCenter];
+  NSArray* deliveredNotifications = [notificationCenter deliveredNotifications];
+  NSMutableArray* notificationIds =
+      [NSMutableArray arrayWithCapacity:[deliveredNotifications count]];
+  for (NSUserNotification* toast in deliveredNotifications) {
+    NSString* candidateProfileId = [toast.userInfo
+        objectForKey:notification_constants::kNotificationProfileId];
+    BOOL incognitoNotification = [[toast.userInfo
+        objectForKey:notification_constants::kNotificationIncognito] boolValue];
+    if ([candidateProfileId isEqualToString:profileId] &&
+        incognito == incognitoNotification) {
+      [notificationIds
+          addObject:[toast.userInfo
+                        objectForKey:notification_constants::kNotificationId]];
+    }
+  }
+  reply(notificationIds);
+}
+
+- (void)userNotificationCenter:(NSUserNotificationCenter*)center
+       didActivateNotification:(NSUserNotification*)notification {
+  NSDictionary* response =
+      [NotificationResponseBuilder buildActivatedDictionary:notification];
+  [[_connection remoteObjectProxy] notificationClick:response];
+}
+
+// _NSUserNotificationCenterDelegatePrivate:
+- (void)userNotificationCenter:(NSUserNotificationCenter*)center
+               didDismissAlert:(NSUserNotification*)notification {
+  NSDictionary* response =
+      [NotificationResponseBuilder buildDismissedDictionary:notification];
+  [[_connection remoteObjectProxy] notificationClick:response];
+  [_transactionHandler closeTransactionIfNeeded];
+}
+
+// _NSUserNotificationCenterDelegatePrivate:
+- (void)userNotificationCenter:(NSUserNotificationCenter*)center
+    didRemoveDeliveredNotifications:(NSArray*)notifications {
+  for (NSUserNotification* notification in notifications) {
+    NSDictionary* response =
+        [NotificationResponseBuilder buildDismissedDictionary:notification];
+    [[_connection remoteObjectProxy] notificationClick:response];
+  }
+  [_transactionHandler closeTransactionIfNeeded];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/notifications/notification_delivery.h b/chrome/browser/ui/cocoa/notifications/notification_delivery.h
index dd3e9a17..9c67be0 100644
--- a/chrome/browser/ui/cocoa/notifications/notification_delivery.h
+++ b/chrome/browser/ui/cocoa/notifications/notification_delivery.h
@@ -15,8 +15,11 @@
 // Protocol for the XPC notification service.
 @protocol NotificationDelivery
 
-// Sets the Mach exception handler port to use for the XPCService.
-- (void)setMachExceptionPort:(CrXPCMachPort*)port;
+// Sets the Mach exception handler port to use for the XPCService, and sets
+// which notification API to be used. This method must be called first before
+// using the other methods in this protocol.
+- (void)setUseUNNotification:(BOOL)useUNNotification
+           machExceptionPort:(CrXPCMachPort*)port;
 
 // |notificationData| is generated using a NofiticationBuilder object.
 - (void)deliverNotification:(NSDictionary*)notificationData;
diff --git a/chrome/browser/ui/cocoa/notifications/notification_service_delegate.h b/chrome/browser/ui/cocoa/notifications/notification_service_delegate.h
deleted file mode 100644
index ad12f31..0000000
--- a/chrome/browser/ui/cocoa/notifications/notification_service_delegate.h
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_NOTIFICATIONS_NOTIFICATION_SERVICE_DELEGATE_H_
-#define CHROME_BROWSER_UI_COCOA_NOTIFICATIONS_NOTIFICATION_SERVICE_DELEGATE_H_
-
-#import <Foundation/Foundation.h>
-
-@interface ServiceDelegate
-    : NSObject<NSXPCListenerDelegate, NSUserNotificationCenterDelegate>
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_NOTIFICATIONS_NOTIFICATION_SERVICE_DELEGATE_H_
diff --git a/chrome/browser/ui/cocoa/notifications/notification_service_delegate.mm b/chrome/browser/ui/cocoa/notifications/notification_service_delegate.mm
deleted file mode 100644
index 72de78b..0000000
--- a/chrome/browser/ui/cocoa/notifications/notification_service_delegate.mm
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/notifications/notification_service_delegate.h"
-
-#import <AppKit/AppKit.h>
-
-#include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/notifications/alert_notification_service.h"
-#import "chrome/browser/ui/cocoa/notifications/notification_delivery.h"
-#import "chrome/browser/ui/cocoa/notifications/notification_response_builder_mac.h"
-#import "chrome/browser/ui/cocoa/notifications/xpc_transaction_handler.h"
-
-@class NSUserNotificationCenter;
-
-@implementation ServiceDelegate {
-  // Helper to manage the XPC transaction reference count with respect to
-  // still-visible notifications.
-  base::scoped_nsobject<XPCTransactionHandler> _transactionHandler;
-
-  // Client connection accepted from the browser process, to which messages
-  // are sent in response to notification actions.
-  base::scoped_nsobject<NSXPCConnection> _connection;
-}
-
-- (instancetype)init {
-  if ((self = [super init])) {
-    [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:self];
-    _transactionHandler.reset([[XPCTransactionHandler alloc] init]);
-  }
-  return self;
-}
-
-- (void)dealloc {
-  [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:nil];
-  [super dealloc];
-}
-
-- (BOOL)listener:(NSXPCListener*)listener
-    shouldAcceptNewConnection:(NSXPCConnection*)newConnection {
-  newConnection.exportedInterface =
-      [NSXPCInterface interfaceWithProtocol:@protocol(NotificationDelivery)];
-  [newConnection.exportedInterface
-         setClasses:[NSSet setWithObjects:[NSArray class], [NSData class],
-                                          [NSDictionary class], [NSImage class],
-                                          [NSNumber class], [NSString class],
-                                          nil]
-        forSelector:@selector(deliverNotification:)
-      argumentIndex:0
-            ofReply:NO];
-
-  base::scoped_nsobject<AlertNotificationService> object(
-      [[AlertNotificationService alloc]
-          initWithTransactionHandler:_transactionHandler]);
-  newConnection.exportedObject = object.get();
-  newConnection.remoteObjectInterface =
-      [NSXPCInterface interfaceWithProtocol:@protocol(NotificationReply)];
-  _connection.reset(newConnection, base::scoped_policy::RETAIN);
-  [newConnection resume];
-
-  return YES;
-}
-
-// NSUserNotificationCenterDelegate:
-- (void)userNotificationCenter:(NSUserNotificationCenter*)center
-       didActivateNotification:(NSUserNotification*)notification {
-  NSDictionary* response =
-      [NotificationResponseBuilder buildActivatedDictionary:notification];
-  [[_connection remoteObjectProxy] notificationClick:response];
-}
-
-// _NSUserNotificationCenterDelegatePrivate:
-- (void)userNotificationCenter:(NSUserNotificationCenter*)center
-               didDismissAlert:(NSUserNotification*)notification {
-  NSDictionary* response =
-      [NotificationResponseBuilder buildDismissedDictionary:notification];
-  [[_connection remoteObjectProxy] notificationClick:response];
-  [_transactionHandler closeTransactionIfNeeded];
-}
-
-// _NSUserNotificationCenterDelegatePrivate:
-- (void)userNotificationCenter:(NSUserNotificationCenter*)center
-    didRemoveDeliveredNotifications:(NSArray*)notifications {
-  for (NSUserNotification* notification in notifications) {
-    NSDictionary* response =
-        [NotificationResponseBuilder buildDismissedDictionary:notification];
-    [[_connection remoteObjectProxy] notificationClick:response];
-  }
-  [_transactionHandler closeTransactionIfNeeded];
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/notifications/service_delegate.h b/chrome/browser/ui/cocoa/notifications/service_delegate.h
new file mode 100644
index 0000000..a56cacd
--- /dev/null
+++ b/chrome/browser/ui/cocoa/notifications/service_delegate.h
@@ -0,0 +1,13 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_COCOA_NOTIFICATIONS_SERVICE_DELEGATE_H_
+#define CHROME_BROWSER_UI_COCOA_NOTIFICATIONS_SERVICE_DELEGATE_H_
+
+#import <Foundation/Foundation.h>
+
+@interface ServiceDelegate : NSObject <NSXPCListenerDelegate>
+@end
+
+#endif  // CHROME_BROWSER_UI_COCOA_NOTIFICATIONS_SERVICE_DELEGATE_H_
diff --git a/chrome/browser/ui/cocoa/notifications/service_delegate.mm b/chrome/browser/ui/cocoa/notifications/service_delegate.mm
new file mode 100644
index 0000000..320e9c6
--- /dev/null
+++ b/chrome/browser/ui/cocoa/notifications/service_delegate.mm
@@ -0,0 +1,62 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "chrome/browser/ui/cocoa/notifications/service_delegate.h"
+
+#import <AppKit/AppKit.h>
+
+#include "base/mac/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/notifications/alert_notification_service.h"
+#import "chrome/browser/ui/cocoa/notifications/notification_delivery.h"
+#import "chrome/browser/ui/cocoa/notifications/notification_response_builder_mac.h"
+#import "chrome/browser/ui/cocoa/notifications/xpc_transaction_handler.h"
+
+@implementation ServiceDelegate {
+  // Helper to manage the XPC transaction reference count with respect to
+  // still-visible notifications.
+  base::scoped_nsobject<XPCTransactionHandler> _transactionHandler;
+
+  // Client connection accepted from the browser process, to which messages
+  // are sent in response to notification actions.
+  base::scoped_nsobject<NSXPCConnection> _connection;
+}
+
+- (instancetype)init {
+  if ((self = [super init])) {
+    _transactionHandler.reset([[XPCTransactionHandler alloc] init]);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [super dealloc];
+}
+
+- (BOOL)listener:(NSXPCListener*)listener
+    shouldAcceptNewConnection:(NSXPCConnection*)newConnection {
+  newConnection.exportedInterface =
+      [NSXPCInterface interfaceWithProtocol:@protocol(NotificationDelivery)];
+  [newConnection.exportedInterface
+         setClasses:[NSSet setWithObjects:[NSArray class], [NSData class],
+                                          [NSDictionary class], [NSImage class],
+                                          [NSNumber class], [NSString class],
+                                          nil]
+        forSelector:@selector(deliverNotification:)
+      argumentIndex:0
+            ofReply:NO];
+
+  base::scoped_nsobject<AlertNotificationService> object(
+      [[AlertNotificationService alloc]
+          initWithTransactionHandler:_transactionHandler
+                       xpcConnection:newConnection]);
+  newConnection.exportedObject = object.get();
+  newConnection.remoteObjectInterface =
+      [NSXPCInterface interfaceWithProtocol:@protocol(NotificationReply)];
+  _connection.reset(newConnection, base::scoped_policy::RETAIN);
+  [newConnection resume];
+
+  return YES;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/notifications/xpc_service_main.mm b/chrome/browser/ui/cocoa/notifications/xpc_service_main.mm
index 4052ac6..10fa0b8 100644
--- a/chrome/browser/ui/cocoa/notifications/xpc_service_main.mm
+++ b/chrome/browser/ui/cocoa/notifications/xpc_service_main.mm
@@ -6,7 +6,7 @@
 #include <xpc/xpc.h>
 
 #include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/notifications/notification_service_delegate.h"
+#import "chrome/browser/ui/cocoa/notifications/service_delegate.h"
 
 // The main method of the notification alert xpc service.
 // It is initiaized by Chrome on demand whenever a notification of type alert
diff --git a/chrome/browser/ui/cocoa/notifications/xpc_transaction_handler.h b/chrome/browser/ui/cocoa/notifications/xpc_transaction_handler.h
index 4342f69..6efe5b5 100644
--- a/chrome/browser/ui/cocoa/notifications/xpc_transaction_handler.h
+++ b/chrome/browser/ui/cocoa/notifications/xpc_transaction_handler.h
@@ -10,6 +10,9 @@
 // Keeps track of whether a XPC transaction is opened.
 @interface XPCTransactionHandler : NSObject
 
+// Sets which API to use, NSUserNotificationCenter or UNUserNotificationCenter.
+- (void)setUseUNNotification:(BOOL)useUNNotification;
+
 // Only open a new transaction if one is not already opened.
 - (void)openTransactionIfNeeded;
 
diff --git a/chrome/browser/ui/cocoa/notifications/xpc_transaction_handler.mm b/chrome/browser/ui/cocoa/notifications/xpc_transaction_handler.mm
index 67bc7311..8b7e219a 100644
--- a/chrome/browser/ui/cocoa/notifications/xpc_transaction_handler.mm
+++ b/chrome/browser/ui/cocoa/notifications/xpc_transaction_handler.mm
@@ -5,19 +5,18 @@
 #import <AppKit/AppKit.h>
 #import <Foundation/Foundation.h>
 
+#include "base/notreached.h"
 #import "chrome/browser/ui/cocoa/notifications/xpc_transaction_handler.h"
 
 @class NSUserNotificationCenter;
 
 @implementation XPCTransactionHandler {
-  bool _transactionOpen;
+  BOOL _transactionOpen;
+  BOOL _useUNNotification;
 }
 
-- (instancetype)init {
-  if ((self = [super init])) {
-    _transactionOpen = false;
-  }
-  return self;
+- (void)setUseUNNotification:(BOOL)useUNNotification {
+  _useUNNotification = useUNNotification;
 }
 
 - (void)openTransactionIfNeeded {
@@ -26,18 +25,23 @@
       return;
     }
     xpc_transaction_begin();
-    _transactionOpen = true;
+    _transactionOpen = YES;
   }
 }
 
 - (void)closeTransactionIfNeeded {
   @synchronized(self) {
+    if (_useUNNotification) {
+      NOTIMPLEMENTED();
+      return;
+    }
+
     NSUserNotificationCenter* notificationCenter =
         [NSUserNotificationCenter defaultUserNotificationCenter];
     NSUInteger showing = [[notificationCenter deliveredNotifications] count];
     if (showing == 0 && _transactionOpen) {
       xpc_transaction_end();
-      _transactionOpen = false;
+      _transactionOpen = NO;
     }
   }
 }
diff --git a/chrome/browser/ui/commander/commander_backend.h b/chrome/browser/ui/commander/commander_backend.h
index 90925593..2084e2d 100644
--- a/chrome/browser/ui/commander/commander_backend.h
+++ b/chrome/browser/ui/commander/commander_backend.h
@@ -32,6 +32,10 @@
   // If |result_set_id| is stale due to race conditions, this is a no-op to
   // ensure that we don't perform an action the user didn't intend.
   virtual void OnCommandSelected(size_t command_index, int result_set_id) = 0;
+  // Called when the user has cancelled entering a composite command. This
+  // should have the effect of returning the backend to the state it was in
+  // previous to the composite command being selected.
+  virtual void OnCompositeCommandCancelled() {}
   // Sets the callback to be used when a fresh view model is ready to be
   // displayed. Invocations of the callback are not necessarily 1:1 or
   // synchronous with user input, since some command sources may be async or
diff --git a/chrome/browser/ui/commander/commander_controller.cc b/chrome/browser/ui/commander/commander_controller.cc
index 7e27682..0adb84ef 100644
--- a/chrome/browser/ui/commander/commander_controller.cc
+++ b/chrome/browser/ui/commander/commander_controller.cc
@@ -101,6 +101,11 @@
   }
 }
 
+void CommanderController::OnCompositeCommandCancelled() {
+  DCHECK(delegate_);
+  delegate_.reset();
+}
+
 void CommanderController::SetUpdateCallback(ViewModelUpdateCallback callback) {
   callback_ = std::move(callback);
 }
diff --git a/chrome/browser/ui/commander/commander_controller.h b/chrome/browser/ui/commander/commander_controller.h
index 26e8686..d62ef2a 100644
--- a/chrome/browser/ui/commander/commander_controller.h
+++ b/chrome/browser/ui/commander/commander_controller.h
@@ -25,9 +25,10 @@
   CommanderController(const CommanderController& other) = delete;
   CommanderController& operator=(const CommanderController& other) = delete;
 
-  // CommandPaletteBackend overrides.
+  // CommanderBackend overrides.
   void OnTextChanged(const base::string16& text, Browser* browser) override;
   void OnCommandSelected(size_t command_index, int result_set_id) override;
+  void OnCompositeCommandCancelled() override;
   void SetUpdateCallback(ViewModelUpdateCallback callback) override;
   void Reset() override;
 
diff --git a/chrome/browser/ui/commander/commander_controller_unittest.cc b/chrome/browser/ui/commander/commander_controller_unittest.cc
index 071662c9..4717020 100644
--- a/chrome/browser/ui/commander/commander_controller_unittest.cc
+++ b/chrome/browser/ui/commander/commander_controller_unittest.cc
@@ -56,11 +56,6 @@
   return item;
 }
 
-template <typename T>
-std::unique_ptr<CommandItem> CreateCompositeCommandItem(
-    const base::string16& title,
-    double scope) {}
-
 TestCommandSource* AddSource(
     std::vector<std::unique_ptr<CommandSource>>* sources,
     std::unique_ptr<TestCommandSource> source) {
@@ -75,9 +70,10 @@
  public:
   class TestBackend : public CommanderBackend {
    public:
-    explicit TestBackend(CommanderControllerTest* owner) {
-      owner->SetTestBackend(this);
+    explicit TestBackend(CommanderControllerTest* owner) : owner_(owner) {
+      owner_->SetTestBackend(this);
     }
+    ~TestBackend() override { owner_->SetTestBackend(nullptr); }
     void OnTextChanged(const base::string16& text, Browser* browser) override {
       text_changed_invocations_.push_back(text);
     }
@@ -100,6 +96,7 @@
     }
 
    private:
+    CommanderControllerTest* owner_;
     ViewModelUpdateCallback callback_;
     std::vector<base::string16> text_changed_invocations_;
     std::vector<size_t> command_selected_invocations_;
@@ -134,6 +131,29 @@
     test_backend_ = test_backend;
   }
 
+  std::unique_ptr<TestCommandSource> CreateCompositeCommandSource() {
+    return std::make_unique<TestCommandSource>(base::BindRepeating(
+        [](CommanderControllerTest* instance, const base::string16&,
+           Browser* browser) -> CommandSource::CommandResults {
+          auto item = std::make_unique<CommandItem>();
+          item->title = base::ASCIIToUTF16("Do something...");
+          item->score = 100;
+          item->matched_ranges.emplace_back(0, item->title.size());
+          item->delegate_factory = base::BindOnce(
+              [](CommanderControllerTest* instance)
+                  -> std::unique_ptr<CommanderBackend> {
+                return std::make_unique<TestBackend>(instance);
+              },
+              instance);
+          CommandSource::CommandResults results;
+          results.push_back(std::move(item));
+          return results;
+        },
+        this));
+  }
+
+  bool is_composite_command_active() const { return test_backend_ != nullptr; }
+
  protected:
   std::unique_ptr<base::RunLoop> run_loop_;
   int expected_count_;
@@ -427,33 +447,14 @@
   }
   ASSERT_EQ(received_view_models_.size(), 1u);
   CommanderViewModel model = received_view_models_.back();
-
   controller->OnCommandSelected(1, model.result_set_id);
 
   EXPECT_FALSE(item_called);
 }
 
 TEST_F(CommanderControllerTest, InvokingCompositeCommandSendsPrompt) {
-  auto source = std::make_unique<TestCommandSource>(base::BindRepeating(
-      [](CommanderControllerTest* instance, const base::string16&,
-         Browser* browser) -> CommandSource::CommandResults {
-        auto item = std::make_unique<CommandItem>();
-        item->title = base::ASCIIToUTF16("Do something...");
-        item->score = 100;
-        item->matched_ranges.emplace_back(0, item->title.size());
-        item->delegate_factory = base::BindOnce(
-            [](CommanderControllerTest* instance)
-                -> std::unique_ptr<CommanderBackend> {
-              return std::make_unique<TestBackend>(instance);
-            },
-            instance);
-        CommandSource::CommandResults results;
-        results.push_back(std::move(item));
-        return results;
-      },
-      this));
   std::vector<std::unique_ptr<CommandSource>> sources;
-  sources.push_back(std::move(source));
+  sources.push_back(CreateCompositeCommandSource());
   auto controller =
       CommanderController::CreateWithSourcesForTesting(std::move(sources));
   controller->SetUpdateCallback(base::BindRepeating(
@@ -466,7 +467,6 @@
   ASSERT_EQ(received_view_models_.size(), 1u);
   {
     ViewModelCallbackWaiter waiter(this);
-
     controller->OnCommandSelected(0,
                                   received_view_models_.back().result_set_id);
   }
@@ -475,26 +475,8 @@
 }
 
 TEST_F(CommanderControllerTest, OnTextChangedPassedToDelegate) {
-  auto source = std::make_unique<TestCommandSource>(base::BindRepeating(
-      [](CommanderControllerTest* instance, const base::string16&,
-         Browser* browser) -> CommandSource::CommandResults {
-        auto item = std::make_unique<CommandItem>();
-        item->title = base::ASCIIToUTF16("Do something...");
-        item->score = 100;
-        item->matched_ranges.emplace_back(0, item->title.size());
-        item->delegate_factory = base::BindOnce(
-            [](CommanderControllerTest* instance)
-                -> std::unique_ptr<CommanderBackend> {
-              return std::make_unique<TestBackend>(instance);
-            },
-            instance);
-        CommandSource::CommandResults results;
-        results.push_back(std::move(item));
-        return results;
-      },
-      this));
   std::vector<std::unique_ptr<CommandSource>> sources;
-  sources.push_back(std::move(source));
+  sources.push_back(CreateCompositeCommandSource());
   auto controller =
       CommanderController::CreateWithSourcesForTesting(std::move(sources));
   controller->SetUpdateCallback(base::BindRepeating(
@@ -511,6 +493,7 @@
     controller->OnCommandSelected(0,
                                   received_view_models_.back().result_set_id);
   }
+  ASSERT_TRUE(is_composite_command_active());
   EXPECT_TRUE(test_backend_->text_changed_invocations().empty());
 
   controller->OnTextChanged(base::ASCIIToUTF16("hocus pocus"), browser());
@@ -520,26 +503,8 @@
 }
 
 TEST_F(CommanderControllerTest, OnCommandSelectedPassedToDelegate) {
-  auto source = std::make_unique<TestCommandSource>(base::BindRepeating(
-      [](CommanderControllerTest* instance, const base::string16&,
-         Browser* browser) -> CommandSource::CommandResults {
-        auto item = std::make_unique<CommandItem>();
-        item->title = base::ASCIIToUTF16("Do something...");
-        item->score = 100;
-        item->matched_ranges.emplace_back(0, item->title.size());
-        item->delegate_factory = base::BindOnce(
-            [](CommanderControllerTest* instance)
-                -> std::unique_ptr<CommanderBackend> {
-              return std::make_unique<TestBackend>(instance);
-            },
-            instance);
-        CommandSource::CommandResults results;
-        results.push_back(std::move(item));
-        return results;
-      },
-      this));
   std::vector<std::unique_ptr<CommandSource>> sources;
-  sources.push_back(std::move(source));
+  sources.push_back(CreateCompositeCommandSource());
   auto controller =
       CommanderController::CreateWithSourcesForTesting(std::move(sources));
   controller->SetUpdateCallback(base::BindRepeating(
@@ -556,7 +521,7 @@
     controller->OnCommandSelected(0,
                                   received_view_models_.back().result_set_id);
   }
-
+  ASSERT_TRUE(is_composite_command_active());
   EXPECT_TRUE(test_backend_->text_changed_invocations().empty());
 
   controller->OnCommandSelected(586,
@@ -565,4 +530,34 @@
   EXPECT_EQ(test_backend_->command_selected_invocations().back(), 586u);
 }
 
+TEST_F(CommanderControllerTest, OnCompositeCommandCancelledRemovesDelegate) {
+  std::vector<std::unique_ptr<CommandSource>> sources;
+  sources.push_back(CreateCompositeCommandSource());
+  auto controller =
+      CommanderController::CreateWithSourcesForTesting(std::move(sources));
+  controller->SetUpdateCallback(base::BindRepeating(
+      &CommanderControllerTest::OnViewModelUpdated, base::Unretained(this)));
+
+  // Prime the sources so we can select an item.
+  {
+    ViewModelCallbackWaiter waiter(this);
+    controller->OnTextChanged(base::ASCIIToUTF16("abracadabra"), browser());
+  }
+  ASSERT_EQ(received_view_models_.size(), 1u);
+
+  // Selecting
+  {
+    ViewModelCallbackWaiter waiter(this);
+    controller->OnCommandSelected(0,
+                                  received_view_models_.back().result_set_id);
+  }
+  ASSERT_EQ(received_view_models_.size(), 2u);
+  EXPECT_EQ(received_view_models_.back().action,
+            CommanderViewModel::Action::kPrompt);
+  EXPECT_TRUE(is_composite_command_active());
+
+  controller->OnCompositeCommandCancelled();
+  EXPECT_FALSE(is_composite_command_active());
+}
+
 }  // namespace commander
diff --git a/chrome/browser/ui/exclusive_access/mouse_lock_controller.cc b/chrome/browser/ui/exclusive_access/mouse_lock_controller.cc
index 0017c41..6610453 100644
--- a/chrome/browser/ui/exclusive_access/mouse_lock_controller.cc
+++ b/chrome/browser/ui/exclusive_access/mouse_lock_controller.cc
@@ -29,7 +29,7 @@
 // The amount of time to disallow repeated pointer lock calls after the user
 // successfully escapes from one lock request.
 constexpr base::TimeDelta kEffectiveUserEscapeDuration =
-    base::TimeDelta::FromMilliseconds(2000);
+    base::TimeDelta::FromMilliseconds(1250);
 
 }  // namespace
 
diff --git a/chrome/browser/ui/extensions/application_launch.cc b/chrome/browser/ui/extensions/application_launch.cc
index 280dbac4..b827295 100644
--- a/chrome/browser/ui/extensions/application_launch.cc
+++ b/chrome/browser/ui/extensions/application_launch.cc
@@ -221,8 +221,8 @@
     //
     // TODO(erg): AppLaunchParams should pass user_gesture from the extension
     // system to here.
-    browser =
-        new Browser(Browser::CreateParams(Browser::TYPE_NORMAL, profile, true));
+    browser = Browser::Create(
+        Browser::CreateParams(Browser::TYPE_NORMAL, profile, true));
     browser->window()->Show();
     // There's no current tab in this browser window, so add a new one.
     disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
@@ -443,7 +443,7 @@
       DetermineWindowShowState(profile, params.container, extension);
   browser_params.can_resize = can_resize;
 
-  return new Browser(browser_params);
+  return Browser::Create(browser_params);
 }
 
 WebContents* NavigateApplicationWindow(Browser* browser,
diff --git a/chrome/browser/ui/extensions/extension_message_bubble_browsertest.cc b/chrome/browser/ui/extensions/extension_message_bubble_browsertest.cc
index f689d68..3aa328c 100644
--- a/chrome/browser/ui/extensions/extension_message_bubble_browsertest.cc
+++ b/chrome/browser/ui/extensions/extension_message_bubble_browsertest.cc
@@ -118,7 +118,8 @@
           .Build();
   extension_service()->AddExtension(action_extension.get());
 
-  Browser* second_browser = new Browser(Browser::CreateParams(profile(), true));
+  Browser* second_browser =
+      Browser::Create(Browser::CreateParams(profile(), true));
   ASSERT_TRUE(second_browser);
   second_browser->window()->Show();
   base::RunLoop().RunUntilIdle();
@@ -140,7 +141,8 @@
   extension_service()->DisableExtension(
       no_action_extension->id(),
       extensions::disable_reason::DISABLE_NOT_VERIFIED);
-  Browser* second_browser = new Browser(Browser::CreateParams(profile(), true));
+  Browser* second_browser =
+      Browser::Create(Browser::CreateParams(profile(), true));
   ASSERT_TRUE(second_browser);
   second_browser->window()->Show();
   base::RunLoop().RunUntilIdle();
@@ -171,7 +173,8 @@
       no_action_extension->id(),
       extensions::disable_reason::DISABLE_NOT_VERIFIED);
 
-  Browser* second_browser = new Browser(Browser::CreateParams(profile(), true));
+  Browser* second_browser =
+      Browser::Create(Browser::CreateParams(profile(), true));
   ASSERT_TRUE(second_browser);
   second_browser->window()->Show();
   base::RunLoop().RunUntilIdle();
@@ -216,7 +219,8 @@
 
   // Create a second browser with the extension installed - the bubble will be
   // set to show.
-  Browser* second_browser = new Browser(Browser::CreateParams(profile(), true));
+  Browser* second_browser =
+      Browser::Create(Browser::CreateParams(profile(), true));
   ASSERT_TRUE(second_browser);
   second_browser->window()->Show();
   // Uninstall the extension before the bubble is shown. This should not crash,
@@ -245,7 +249,8 @@
           .Build();
   extension_service()->AddExtension(action_extension.get());
 
-  Browser* second_browser = new Browser(Browser::CreateParams(profile(), true));
+  Browser* second_browser =
+      Browser::Create(Browser::CreateParams(profile(), true));
   ASSERT_TRUE(second_browser);
   second_browser->window()->Show();
   base::RunLoop().RunUntilIdle();
@@ -255,7 +260,8 @@
   base::RunLoop().RunUntilIdle();
 
   // The bubble was already shown, so it shouldn't be shown again.
-  Browser* third_browser = new Browser(Browser::CreateParams(profile(), true));
+  Browser* third_browser =
+      Browser::Create(Browser::CreateParams(profile(), true));
   ASSERT_TRUE(third_browser);
   third_browser->window()->Show();
   base::RunLoop().RunUntilIdle();
@@ -352,13 +358,16 @@
 void ExtensionMessageBubbleBrowserTest::TestBubbleWithMultipleWindows() {
   CheckBubbleIsNotPresent(browser(), false, false);
   LoadExtension(test_data_dir_.AppendASCII("simple_with_popup"));
-  Browser* second_browser = new Browser(Browser::CreateParams(profile(), true));
+  Browser* second_browser =
+      Browser::Create(Browser::CreateParams(profile(), true));
   ASSERT_TRUE(second_browser);
   second_browser->window()->Show();
-  Browser* third_browser = new Browser(Browser::CreateParams(profile(), true));
+  Browser* third_browser =
+      Browser::Create(Browser::CreateParams(profile(), true));
   ASSERT_TRUE(third_browser);
   third_browser->window()->Show();
-  Browser* fourth_browser = new Browser(Browser::CreateParams(profile(), true));
+  Browser* fourth_browser =
+      Browser::Create(Browser::CreateParams(profile(), true));
   ASSERT_TRUE(fourth_browser);
   fourth_browser->window()->Show();
   base::RunLoop().RunUntilIdle();
@@ -383,7 +392,8 @@
       no_action_extension->id(),
       extensions::disable_reason::DISABLE_NOT_VERIFIED);
 
-  Browser* second_browser = new Browser(Browser::CreateParams(profile(), true));
+  Browser* second_browser =
+      Browser::Create(Browser::CreateParams(profile(), true));
   ASSERT_TRUE(second_browser);
   second_browser->window()->Show();
   base::RunLoop().RunUntilIdle();
@@ -407,7 +417,8 @@
       extensions::ExtensionRegistry::Get(profile());
   std::string id = extension->id();
   EXPECT_TRUE(registry->enabled_extensions().GetByID(id));
-  Browser* second_browser = new Browser(Browser::CreateParams(profile(), true));
+  Browser* second_browser =
+      Browser::Create(Browser::CreateParams(profile(), true));
   ASSERT_TRUE(second_browser);
   second_browser->window()->Show();
   base::RunLoop().RunUntilIdle();
@@ -427,7 +438,8 @@
       extensions::ExtensionRegistry::Get(profile());
   std::string id = extension->id();
   EXPECT_TRUE(registry->enabled_extensions().GetByID(id));
-  Browser* second_browser = new Browser(Browser::CreateParams(profile(), true));
+  Browser* second_browser =
+      Browser::Create(Browser::CreateParams(profile(), true));
   ASSERT_TRUE(second_browser);
   second_browser->window()->Show();
   base::RunLoop().RunUntilIdle();
diff --git a/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc b/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc
index ce65288..2238f85 100644
--- a/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc
+++ b/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc
@@ -1388,7 +1388,7 @@
   // Open a new incognito window and navigate to the same page.
   Profile* incognito_profile = browser()->profile()->GetPrimaryOTRProfile();
   Browser* incognito_browser =
-      new Browser(Browser::CreateParams(incognito_profile, true));
+      Browser::Create(Browser::CreateParams(incognito_profile, true));
   content::WindowedNotificationObserver observer(
       content::NOTIFICATION_LOAD_STOP,
       content::NotificationService::AllSources());
@@ -1450,7 +1450,7 @@
 IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FitWindow) {
   Browser::CreateParams params(Browser::TYPE_POPUP, browser()->profile(), true);
   params.initial_bounds = gfx::Rect(0, 0, 250, 500);
-  Browser* popup = new Browser(params);
+  Browser* popup = Browser::Create(params);
   content::WindowedNotificationObserver observer(
       content::NOTIFICATION_LOAD_STOP,
       content::NotificationService::AllSources());
diff --git a/chrome/browser/ui/omnibox/clipboard_utils.cc b/chrome/browser/ui/omnibox/clipboard_utils.cc
index 8f86e3ca7..4ba8d9c 100644
--- a/chrome/browser/ui/omnibox/clipboard_utils.cc
+++ b/chrome/browser/ui/omnibox/clipboard_utils.cc
@@ -10,7 +10,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "components/omnibox/browser/omnibox_view.h"
 #include "ui/base/clipboard/clipboard.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 
 base::string16 GetClipboardText(bool notify_if_restricted) {
   // Try text format.
diff --git a/chrome/browser/ui/scoped_tabbed_browser_displayer.cc b/chrome/browser/ui/scoped_tabbed_browser_displayer.cc
index 9ad5bffb..a2baf76b 100644
--- a/chrome/browser/ui/scoped_tabbed_browser_displayer.cc
+++ b/chrome/browser/ui/scoped_tabbed_browser_displayer.cc
@@ -13,7 +13,7 @@
 ScopedTabbedBrowserDisplayer::ScopedTabbedBrowserDisplayer(Profile* profile) {
   browser_ = FindTabbedBrowser(profile, false);
   if (!browser_)
-    browser_ = new Browser(Browser::CreateParams(profile, true));
+    browser_ = Browser::Create(Browser::CreateParams(profile, true));
 }
 
 ScopedTabbedBrowserDisplayer::~ScopedTabbedBrowserDisplayer() {
diff --git a/chrome/browser/ui/search/local_ntp_browsertest.cc b/chrome/browser/ui/search/local_ntp_browsertest.cc
index ab47a7e..54a68925 100644
--- a/chrome/browser/ui/search/local_ntp_browsertest.cc
+++ b/chrome/browser/ui/search/local_ntp_browsertest.cc
@@ -1232,7 +1232,7 @@
 // Just like LocalNTPTest.ProcessPerSite, but for an incognito window.
 IN_PROC_BROWSER_TEST_F(LocalNTPTest, ProcessPerSite_Incognito) {
   GURL ntp_url("chrome://newtab");
-  Browser* incognito_browser = new Browser(Browser::CreateParams(
+  Browser* incognito_browser = Browser::Create(Browser::CreateParams(
       browser()->profile()->GetPrimaryOTRProfile(), true));
 
   // Open NTP in |tab1|.
diff --git a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
index 26d69d1..c9d0bbb 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
@@ -310,7 +310,7 @@
   OpenURLsPopupObserver observer;
   BrowserList::AddObserver(&observer);
 
-  Browser* popup = new Browser(
+  Browser* popup = Browser::Create(
       Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile(), true));
   ASSERT_TRUE(popup->is_type_popup());
   ASSERT_EQ(popup, observer.added_browser_);
@@ -729,15 +729,15 @@
   DisableWelcomePages({profile1, profile2});
 
   // Open some urls with the browsers, and close them.
-  Browser* browser1 =
-      new Browser(Browser::CreateParams(Browser::TYPE_NORMAL, profile1, true));
+  Browser* browser1 = Browser::Create(
+      Browser::CreateParams(Browser::TYPE_NORMAL, profile1, true));
   chrome::NewTab(browser1);
   ui_test_utils::NavigateToURL(browser1,
                                embedded_test_server()->GetURL("/empty.html"));
   CloseBrowserSynchronously(browser1);
 
-  Browser* browser2 =
-      new Browser(Browser::CreateParams(Browser::TYPE_NORMAL, profile2, true));
+  Browser* browser2 = Browser::Create(
+      Browser::CreateParams(Browser::TYPE_NORMAL, profile2, true));
   chrome::NewTab(browser2);
   ui_test_utils::NavigateToURL(browser2,
                                embedded_test_server()->GetURL("/form.html"));
@@ -871,7 +871,7 @@
   SessionStartupPref::SetStartupPref(profile_urls, pref_urls);
 
   // Open a page with profile_last.
-  Browser* browser_last = new Browser(
+  Browser* browser_last = Browser::Create(
       Browser::CreateParams(Browser::TYPE_NORMAL, profile_last, true));
   chrome::NewTab(browser_last);
   ui_test_utils::NavigateToURL(browser_last,
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
index b8ad866..87756b3 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -281,7 +281,7 @@
     // incomplete check on whether a user gesture created a window which looked
     // at the state of the MessageLoop.
     Browser::CreateParams params = Browser::CreateParams(profile_, false);
-    browser = new Browser(params);
+    browser = Browser::Create(params);
   }
 
   bool first_tab = true;
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_model.cc b/chrome/browser/ui/toolbar/toolbar_actions_model.cc
index 350d93a..0f0b80ec 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_model.cc
+++ b/chrome/browser/ui/toolbar/toolbar_actions_model.cc
@@ -14,10 +14,12 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/one_shot_event.h"
+#include "base/ranges/algorithm.h"
 #include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/extensions/extension_management.h"
 #include "chrome/browser/extensions/extension_message_bubble_controller.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/extensions/tab_helper.h"
@@ -241,6 +243,10 @@
   }
 }
 
+void ToolbarActionsModel::OnExtensionManagementSettingsChanged() {
+  OnActionToolbarPrefChange();
+}
+
 void ToolbarActionsModel::RemovePref(const ActionId& action_id) {
   auto pos = std::find(last_known_positions_.begin(),
                        last_known_positions_.end(), action_id);
@@ -276,6 +282,10 @@
   extension_registry_observer_.Add(extension_registry_);
   extension_action_observer_.Add(extension_action_api_);
 
+  auto* management =
+      extensions::ExtensionManagementFactory::GetForBrowserContext(profile_);
+  extension_management_observer_.Add(management);
+
   actions_initialized_ = true;
   for (Observer& observer : observers_)
     observer.OnToolbarModelInitialized();
@@ -451,6 +461,13 @@
   return base::Contains(pinned_action_ids_, action_id);
 }
 
+bool ToolbarActionsModel::IsActionForcePinned(const ActionId& action_id) const {
+  DCHECK(base::FeatureList::IsEnabled(features::kExtensionsToolbarMenu));
+  auto* management =
+      extensions::ExtensionManagementFactory::GetForBrowserContext(profile_);
+  return base::Contains(management->GetForcePinnedList(), action_id);
+}
+
 void ToolbarActionsModel::MovePinnedAction(const ActionId& action_id,
                                            size_t target_index) {
   DCHECK(base::FeatureList::IsEnabled(features::kExtensionsToolbarMenu));
@@ -656,6 +673,7 @@
                                               bool is_now_visible) {
   if (base::FeatureList::IsEnabled(features::kExtensionsToolbarMenu)) {
     DCHECK_NE(is_now_visible, IsActionPinned(action_id));
+    DCHECK(!IsActionForcePinned(action_id));
     auto new_pinned_action_ids = pinned_action_ids_;
     if (is_now_visible) {
       new_pinned_action_ids.push_back(action_id);
@@ -829,10 +847,19 @@
 
 std::vector<ToolbarActionsModel::ActionId>
 ToolbarActionsModel::GetFilteredPinnedActionIds() const {
+  // Force-pinned extensions should always be present in the output vector.
+  extensions::ExtensionIdList pinned = extension_prefs_->GetPinnedExtensions();
+  auto* management =
+      extensions::ExtensionManagementFactory::GetForBrowserContext(profile_);
+  // O(n^2), but there are typically very few force-pinned extensions.
+  base::ranges::copy_if(
+      management->GetForcePinnedList(), std::back_inserter(pinned),
+      [&pinned](const std::string& id) { return !base::Contains(pinned, id); });
+
   // TODO(pbos): Make sure that the pinned IDs are pruned from ExtensionPrefs on
   // startup so that we don't keep saving stale IDs.
   std::vector<ActionId> filtered_action_ids;
-  for (auto& action_id : extension_prefs_->GetPinnedExtensions()) {
+  for (auto& action_id : pinned) {
     if (HasAction(action_id))
       filtered_action_ids.push_back(action_id);
   }
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_model.h b/chrome/browser/ui/toolbar/toolbar_actions_model.h
index a197bc88..a6644ac 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_model.h
+++ b/chrome/browser/ui/toolbar/toolbar_actions_model.h
@@ -13,6 +13,7 @@
 #include "base/observer_list.h"
 #include "base/scoped_observer.h"
 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
+#include "chrome/browser/extensions/extension_management.h"
 #include "chrome/browser/extensions/load_error_reporter.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/prefs/pref_change_registrar.h"
@@ -43,6 +44,7 @@
 class ToolbarActionsModel : public extensions::ExtensionActionAPI::Observer,
                             public extensions::LoadErrorReporter::Observer,
                             public extensions::ExtensionRegistryObserver,
+                            public extensions::ExtensionManagement::Observer,
                             public KeyedService {
  public:
   using ActionId = std::string;
@@ -187,6 +189,9 @@
   // Returns true if the action is pinned to the toolbar.
   bool IsActionPinned(const ActionId& action_id) const;
 
+  // Returns true if the action is force-pinned to the toolbar.
+  bool IsActionForcePinned(const ActionId& action_id) const;
+
   // Move the pinned action for |action_id| to |target_index|.
   void MovePinnedAction(const ActionId& action_id, size_t target_index);
 
@@ -220,6 +225,9 @@
                      const base::FilePath& extension_path,
                      const std::string& error) override;
 
+  // extensions::ExtensionManagement::Observer:
+  void OnExtensionManagementSettingsChanged() override;
+
   // To be called after the extension service is ready; gets loaded extensions
   // from the ExtensionRegistry, their saved order from the pref service, and
   // constructs |action_ids_| from these data. IncognitoPopulate() takes
@@ -340,6 +348,10 @@
                  extensions::LoadErrorReporter::Observer>
       load_error_reporter_observer_{this};
 
+  ScopedObserver<extensions::ExtensionManagement,
+                 extensions::ExtensionManagement::Observer>
+      extension_management_observer_{this};
+
   base::WeakPtrFactory<ToolbarActionsModel> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(ToolbarActionsModel);
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_model_factory.cc b/chrome/browser/ui/toolbar/toolbar_actions_model_factory.cc
index 18f6485b..c8d6031 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_model_factory.cc
+++ b/chrome/browser/ui/toolbar/toolbar_actions_model_factory.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/toolbar/toolbar_actions_model_factory.h"
 
 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
+#include "chrome/browser/extensions/extension_management.h"
 #include "chrome/browser/extensions/extension_system_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
@@ -34,6 +35,7 @@
   DependsOn(extensions::ExtensionPrefsFactory::GetInstance());
   DependsOn(extensions::ExtensionRegistryFactory::GetInstance());
   DependsOn(extensions::ExtensionSystemFactory::GetInstance());
+  DependsOn(extensions::ExtensionManagementFactory::GetInstance());
 }
 
 ToolbarActionsModelFactory::~ToolbarActionsModelFactory() {}
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc b/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc
index 66c2861..56b2c6e 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc
+++ b/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc
@@ -11,12 +11,14 @@
 #include "base/callback.h"
 #include "base/callback_helpers.h"
 #include "base/files/file_util.h"
+#include "base/json/json_reader.h"
 #include "base/memory/ref_counted.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
 #include "base/strings/string16.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/scoped_feature_list.h"
+#include "base/values.h"
 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
 #include "chrome/browser/extensions/extension_action_test_util.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -29,6 +31,7 @@
 #include "chrome/browser/ui/ui_features.h"
 #include "chrome/common/pref_names.h"
 #include "components/crx_file/id_util.h"
+#include "components/policy/core/common/policy_map.h"
 #include "components/prefs/scoped_user_pref_update.h"
 #include "content/public/test/test_renderer_host.h"
 #include "content/public/test/web_contents_tester.h"
@@ -1545,3 +1548,37 @@
   EXPECT_FALSE(toolbar_model()->IsActionPinned(extension->id()));
   EXPECT_THAT(prefs->GetPinnedExtensions(), testing::IsEmpty());
 }
+
+TEST_F(ToolbarActionsModelUnitTest, ForcePinnedByPolicy) {
+  Init();
+
+  // Set the extension to force-pin via enterprise policy.
+  std::string extension_id = crx_file::id_util::GenerateId("qwertyuiop");
+  std::string json = base::StringPrintf(
+      R"({
+        "%s": {
+          "toolbar_pin": "force_pinned"
+        }
+      })",
+      extension_id.c_str());
+  base::Optional<base::Value> parsed = base::JSONReader::Read(json);
+  policy::PolicyMap map;
+  map.Set("ExtensionSettings", policy::POLICY_LEVEL_MANDATORY,
+          policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_PLATFORM,
+          std::move(parsed), nullptr);
+  policy_provider()->UpdateChromePolicy(map);
+
+  scoped_refptr<const extensions::Extension> extension =
+      extensions::ExtensionBuilder("test")
+          .SetAction(ActionType::BROWSER_ACTION)
+          .SetLocation(extensions::Manifest::INTERNAL)
+          .SetID(extension_id)
+          .Build();
+
+  // Add an extension. It should auto-pin because of the ExtensionSettings
+  // policy.
+  EXPECT_TRUE(AddExtension(extension));
+  EXPECT_TRUE(toolbar_model()->IsActionPinned(extension->id()));
+  auto* prefs = extensions::ExtensionPrefs::Get(profile());
+  EXPECT_FALSE(base::Contains(prefs->GetPinnedExtensions(), extension_id));
+}
diff --git a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_lacros.cc b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_lacros.cc
index 5c7b2e73c..8aad4c43 100644
--- a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_lacros.cc
+++ b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_lacros.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/views/chrome_browser_main_extra_parts_views_lacros.h"
 
 #include "chrome/browser/lacros/immersive_context_lacros.h"
+#include "chromeos/ui/base/tablet_state.h"
 
 ChromeBrowserMainExtraPartsViewsLacros::
     ChromeBrowserMainExtraPartsViewsLacros() = default;
@@ -14,6 +15,7 @@
 
 void ChromeBrowserMainExtraPartsViewsLacros::PreProfileInit() {
   immersive_context_ = std::make_unique<ImmersiveContextLacros>();
+  tablet_state_ = std::make_unique<chromeos::TabletState>();
 
   ChromeBrowserMainExtraPartsViews::PreProfileInit();
 }
diff --git a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_lacros.h b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_lacros.h
index f9470061..afde7f8 100644
--- a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_lacros.h
+++ b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_lacros.h
@@ -9,6 +9,10 @@
 
 #include <memory>
 
+namespace chromeos {
+class TabletState;
+}
+
 class ImmersiveContextLacros;
 
 class ChromeBrowserMainExtraPartsViewsLacros
@@ -26,6 +30,7 @@
   void PreProfileInit() override;
 
   std::unique_ptr<ImmersiveContextLacros> immersive_context_;
+  std::unique_ptr<chromeos::TabletState> tablet_state_;
 };
 
 #endif  // CHROME_BROWSER_UI_VIEWS_CHROME_BROWSER_MAIN_EXTRA_PARTS_VIEWS_LACROS_H_
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_item_view.cc b/chrome/browser/ui/views/extensions/extensions_menu_item_view.cc
index 5d0b5f4..f358345 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_item_view.cc
+++ b/chrome/browser/ui/views/extensions/extensions_menu_item_view.cc
@@ -46,12 +46,13 @@
     Browser* browser,
     std::unique_ptr<ToolbarActionViewController> controller,
     bool allow_pinning)
-    : primary_action_button_(new ExtensionsMenuButton(browser,
+    : profile_(browser->profile()),
+      primary_action_button_(new ExtensionsMenuButton(browser,
                                                       this,
                                                       controller.get(),
                                                       allow_pinning)),
       controller_(std::move(controller)),
-      model_(ToolbarActionsModel::Get(browser->profile())) {
+      model_(ToolbarActionsModel::Get(profile_)) {
   // Set so the extension button receives enter/exit on children to retain hover
   // status when hovering child views.
   SetNotifyEnterExitOnChild(true);
@@ -76,13 +77,11 @@
         base::BindRepeating(&ExtensionsMenuItemView::PinButtonPressed,
                             base::Unretained(this)));
     pin_button->SetBorder(views::CreateEmptyBorder(kSecondaryButtonInsets));
-    // Extension pinning is not available in Incognito as it leaves a trace of
-    // user activity.
-    pin_button->SetEnabled(!browser->profile()->IsOffTheRecord());
 
     pin_button_ = pin_button.get();
     AddChildView(std::move(pin_button));
   }
+  UpdatePinButton();
 
   auto context_menu_button = CreateBubbleMenuItem(
       EXTENSION_CONTEXT_MENU, views::Button::PressedCallback());
@@ -123,9 +122,21 @@
 void ExtensionsMenuItemView::UpdatePinButton() {
   if (!pin_button_)
     return;
-  pin_button_->SetTooltipText(l10n_util::GetStringUTF16(
-      IsPinned() ? IDS_EXTENSIONS_MENU_UNPIN_BUTTON_TOOLTIP
-                 : IDS_EXTENSIONS_MENU_PIN_BUTTON_TOOLTIP));
+
+  bool is_force_pinned =
+      model_ && model_->IsActionForcePinned(controller_->GetId());
+  int pin_button_string_id = 0;
+  if (is_force_pinned)
+    pin_button_string_id = IDS_EXTENSIONS_PINNED_BY_ADMIN;
+  else if (IsPinned())
+    pin_button_string_id = IDS_EXTENSIONS_UNPIN_FROM_TOOLBAR;
+  else
+    pin_button_string_id = IDS_EXTENSIONS_PIN_TO_TOOLBAR;
+  pin_button_->SetTooltipText(l10n_util::GetStringUTF16(pin_button_string_id));
+  // Extension pinning is not available in Incognito as it leaves a trace of
+  // user activity.
+  pin_button_->SetEnabled(!is_force_pinned && !profile_->IsOffTheRecord());
+
   SkColor unpinned_icon_color =
       GetAdjustedIconColor(GetNativeTheme()->GetSystemColor(
           ui::NativeTheme::kColorId_MenuIconColor));
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_item_view.h b/chrome/browser/ui/views/extensions/extensions_menu_item_view.h
index 3032b76..7d7c3a2 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_item_view.h
+++ b/chrome/browser/ui/views/extensions/extensions_menu_item_view.h
@@ -12,6 +12,7 @@
 class Browser;
 class ExtensionContextMenuController;
 class ExtensionsMenuButton;
+class Profile;
 class ToolbarActionViewController;
 class ToolbarActionsModel;
 
@@ -65,6 +66,8 @@
   // background.
   SkColor GetAdjustedIconColor(SkColor icon_color) const;
 
+  Profile* const profile_;
+
   ExtensionsMenuButton* const primary_action_button_;
 
   std::unique_ptr<ToolbarActionViewController> controller_;
diff --git a/chrome/browser/ui/views/frame/browser_frame_ash_browsertest.cc b/chrome/browser/ui/views/frame/browser_frame_ash_browsertest.cc
index 6443bed1..f2611b26 100644
--- a/chrome/browser/ui/views/frame/browser_frame_ash_browsertest.cc
+++ b/chrome/browser/ui/views/frame/browser_frame_ash_browsertest.cc
@@ -47,7 +47,7 @@
   gfx::Rect original_bounds(gfx::Rect(150, 250, 510, 150));
   params.initial_show_state = ui::SHOW_STATE_NORMAL;
   params.initial_bounds = original_bounds;
-  Browser* browser = new Browser(params);
+  Browser* browser = Browser::Create(params);
   browser->window()->Show();
 
   // The bounds passed via |initial_bounds| should be respected regardless of
@@ -59,7 +59,7 @@
   // tabbed windows, the position should be auto-managed.
   browser->window()->Close();
   params.initial_bounds = gfx::Rect();
-  browser = new Browser(params);
+  browser = Browser::Create(params);
   browser->window()->Show();
 
   // For tabbed browser window, it will be centered to work area by auto window
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
index c262f98..9780aaaa 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
@@ -677,7 +677,7 @@
       "test_browser_app", true /* trusted_source */, gfx::Rect(0, 0, 300, 300),
       browser()->profile(), true);
   params.initial_show_state = ui::SHOW_STATE_DEFAULT;
-  Browser* browser = new Browser(params);
+  Browser* browser = Browser::Create(params);
   ASSERT_TRUE(browser->is_type_app());
   BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
 
@@ -1342,7 +1342,7 @@
       "test_browser_app", true /* trusted_source */, gfx::Rect(),
       browser()->profile(), true);
   params.initial_show_state = ui::SHOW_STATE_DEFAULT;
-  Browser* browser2 = new Browser(params);
+  Browser* browser2 = Browser::Create(params);
   AddBlankTabAndShow(browser2);
   BrowserView* browser_view2 = BrowserView::GetBrowserViewForBrowser(browser2);
   Widget* widget2 = browser_view2->GetWidget();
@@ -1376,7 +1376,7 @@
   browser()->window()->Close();
 
   // Open a new app window.
-  Browser* app_browser = new Browser(Browser::CreateParams::CreateForApp(
+  Browser* app_browser = Browser::Create(Browser::CreateParams::CreateForApp(
       "test_browser_app", true /* trusted_source */, gfx::Rect(),
       browser()->profile(), true /* user_gesture */));
   aura::Window* window = app_browser->window()->GetNativeWindow();
@@ -1398,7 +1398,7 @@
       "test_browser_app", true /* trusted_source */, gfx::Rect(),
       browser()->profile(), true);
   params.initial_show_state = ui::SHOW_STATE_DEFAULT;
-  Browser* browser = new Browser(params);
+  Browser* browser = Browser::Create(params);
   BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
   ImmersiveModeController* immersive_mode_controller =
       browser_view->immersive_mode_controller();
@@ -1499,7 +1499,7 @@
       "test_browser_app", true /* trusted_source */, gfx::Rect(),
       browser()->profile(), true);
   params.initial_show_state = ui::SHOW_STATE_DEFAULT;
-  Browser* browser = new Browser(params);
+  Browser* browser = Browser::Create(params);
   ASSERT_TRUE(browser->is_type_app());
   browser->window()->Show();
 
diff --git a/chrome/browser/ui/views/frame/browser_view_browsertest.cc b/chrome/browser/ui/views/frame/browser_view_browsertest.cc
index df3b123..17e38f7 100644
--- a/chrome/browser/ui/views/frame/browser_view_browsertest.cc
+++ b/chrome/browser/ui/views/frame/browser_view_browsertest.cc
@@ -123,7 +123,7 @@
 // is invoked on the other.
 IN_PROC_BROWSER_TEST_F(BrowserViewTest, CloseWithTabs) {
   Browser* browser2 =
-      new Browser(Browser::CreateParams(browser()->profile(), true));
+      Browser::Create(Browser::CreateParams(browser()->profile(), true));
   chrome::AddTabAt(browser2, GURL(), -1, true);
   chrome::AddTabAt(browser2, GURL(), -1, true);
   TestWebContentsObserver observer(
@@ -136,7 +136,7 @@
 // BrowserView will destroy.
 IN_PROC_BROWSER_TEST_F(BrowserViewTest, CloseWithTabsStartWithActive) {
   Browser* browser2 =
-      new Browser(Browser::CreateParams(browser()->profile(), true));
+      Browser::Create(Browser::CreateParams(browser()->profile(), true));
   chrome::AddTabAt(browser2, GURL(), -1, true);
   chrome::AddTabAt(browser2, GURL(), -1, true);
   browser2->tab_strip_model()->ActivateTabAt(
diff --git a/chrome/browser/ui/views/frame/browser_view_focus_uitest.cc b/chrome/browser/ui/views/frame/browser_view_focus_uitest.cc
index d3ee43e..5db0533 100644
--- a/chrome/browser/ui/views/frame/browser_view_focus_uitest.cc
+++ b/chrome/browser/ui/views/frame/browser_view_focus_uitest.cc
@@ -66,7 +66,7 @@
 #if defined(OS_WIN)
   // Open a new browser window.
   Browser* browser2 =
-      new Browser(Browser::CreateParams(browser()->profile(), true));
+      Browser::Create(Browser::CreateParams(browser()->profile(), true));
   ASSERT_TRUE(browser2);
   chrome::AddTabAt(browser2, GURL(), -1, true);
   browser2->window()->Show();
diff --git a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc
index d6df2e7..542c26c5 100644
--- a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc
+++ b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc
@@ -566,7 +566,7 @@
       "test_browser_app", true /* trusted_source */, gfx::Rect(),
       browser()->profile(), true);
   params.initial_show_state = ui::SHOW_STATE_DEFAULT;
-  Browser* browser = new Browser(params);
+  Browser* browser = Browser::Create(params);
   AddBlankTabAndShow(browser);
 
   ASSERT_TRUE(browser->is_type_app());
diff --git a/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc b/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc
index a87ddea7..4bb499c 100644
--- a/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc
@@ -449,7 +449,7 @@
 // Ensure normal sites with low engagement are not blocked in incognito.
 IN_PROC_BROWSER_TEST_P(SafetyTipPageInfoBubbleViewBrowserTest,
                        NoShowOnLowEngagementIncognito) {
-  Browser* incognito_browser = new Browser(Browser::CreateParams(
+  Browser* incognito_browser = Browser::Create(Browser::CreateParams(
       browser()->profile()->GetPrimaryOTRProfile(), true));
   auto kNavigatedUrl = GetURL("site1.com");
   SetEngagementScore(incognito_browser, kNavigatedUrl, kLowEngagement);
@@ -477,7 +477,7 @@
 // Ensure blocked sites with high engagement are not blocked in incognito.
 IN_PROC_BROWSER_TEST_P(SafetyTipPageInfoBubbleViewBrowserTest,
                        NoShowOnHighEngagementIncognito) {
-  Browser* incognito_browser = new Browser(Browser::CreateParams(
+  Browser* incognito_browser = Browser::Create(Browser::CreateParams(
       browser()->profile()->GetPrimaryOTRProfile(), true));
   auto kNavigatedUrl = GetURL("site1.com");
   reputation::SetSafetyTipBadRepPatterns({"site1.com/"});
@@ -518,7 +518,7 @@
 // Ensure blocked sites get blocked in incognito.
 IN_PROC_BROWSER_TEST_P(SafetyTipPageInfoBubbleViewBrowserTest,
                        ShowOnBlockIncognito) {
-  Browser* incognito_browser = new Browser(Browser::CreateParams(
+  Browser* incognito_browser = Browser::Create(Browser::CreateParams(
       browser()->profile()->GetPrimaryOTRProfile(), true));
   auto kNavigatedUrl = GetURL("site1.com");
   reputation::SetSafetyTipBadRepPatterns({"site1.com/"});
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
index 0fef576..17baa7b 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -2034,7 +2034,7 @@
   // Don't copy the initial workspace since the *current* workspace might be
   // different and copying the workspace will move the tab to the initial one.
   create_params.initial_workspace = "";
-  Browser* browser = new Browser(create_params);
+  Browser* browser = Browser::Create(create_params);
   is_dragging_new_browser_ = true;
   // If the window is created maximized then the bounds we supplied are ignored.
   // We need to reset them again so they are honored.
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
index 958540f..afdcf759 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -2826,7 +2826,7 @@
   // Create a browser window whose initial show state is MAXIMIZED.
   Browser::CreateParams params(browser()->profile(), /*user_gesture=*/false);
   params.initial_show_state = ui::SHOW_STATE_MAXIMIZED;
-  Browser* browser = new Browser(params);
+  Browser* browser = Browser::Create(params);
   AddBlankTabAndShow(browser);
   TabStrip* tab_strip = GetTabStripForBrowser(browser);
   AddTabsAndResetBrowser(browser, 1);
@@ -3779,7 +3779,7 @@
   Browser::CreateParams params(browser()->profile(), true);
   params.initial_show_state = ui::SHOW_STATE_NORMAL;
   params.initial_bounds = work_area;
-  Browser* browser2 = new Browser(params);
+  Browser* browser2 = Browser::Create(params);
   AddBlankTabAndShow(browser2);
 
   TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
diff --git a/chrome/browser/ui/views/tabs/tab_search_button.cc b/chrome/browser/ui/views/tabs/tab_search_button.cc
index 71fc764..6a9096c 100644
--- a/chrome/browser/ui/views/tabs/tab_search_button.cc
+++ b/chrome/browser/ui/views/tabs/tab_search_button.cc
@@ -53,7 +53,7 @@
            gfx::CreateVectorIcon(kTabSearchIcon, GetForegroundColor()));
 }
 
-void TabSearchButton::OnWidgetClosing(views::Widget* widget) {
+void TabSearchButton::OnWidgetDestroying(views::Widget* widget) {
   DCHECK_EQ(bubble_, widget);
   observed_bubble_widget_.Remove(bubble_);
   bubble_ = nullptr;
diff --git a/chrome/browser/ui/views/tabs/tab_search_button.h b/chrome/browser/ui/views/tabs/tab_search_button.h
index f2b611be..6b540875 100644
--- a/chrome/browser/ui/views/tabs/tab_search_button.h
+++ b/chrome/browser/ui/views/tabs/tab_search_button.h
@@ -39,7 +39,7 @@
   void FrameColorsChanged() override;
 
   // views::WidgetObserver:
-  void OnWidgetClosing(views::Widget* widget) override;
+  void OnWidgetDestroying(views::Widget* widget) override;
 
   // When this is called the bubble may already be showing or be loading in.
   // This returns true if the method call results in the creation of a new Tab
diff --git a/chrome/browser/ui/views/tabs/tab_search_button_browsertest.cc b/chrome/browser/ui/views/tabs/tab_search_button_browsertest.cc
index 692cad6..bca9135 100644
--- a/chrome/browser/ui/views/tabs/tab_search_button_browsertest.cc
+++ b/chrome/browser/ui/views/tabs/tab_search_button_browsertest.cc
@@ -7,6 +7,7 @@
 #include <vector>
 
 #include "base/feature_list.h"
+#include "base/run_loop.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "chrome/browser/ui/browser.h"
@@ -41,6 +42,15 @@
     return browser_view()->GetTabSearchButton();
   }
 
+  void RunUntilBubbleWidgetDestroyed() {
+    ASSERT_NE(nullptr, tab_search_button()->bubble_for_testing());
+    base::RunLoop run_loop;
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                  run_loop.QuitClosure());
+    run_loop.Run();
+    ASSERT_EQ(nullptr, tab_search_button()->bubble_for_testing());
+  }
+
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
 };
@@ -50,10 +60,10 @@
   views::test::ButtonTestApi(tab_search_button()).NotifyClick(GetDummyEvent());
   ASSERT_NE(nullptr, tab_search_button()->bubble_for_testing());
 
-  // Close the tab search bubble widget, the bubble should be cleared from the
-  // TabSearchButton.
   tab_search_button()->CloseTabSearchBubble();
-  ASSERT_EQ(nullptr, tab_search_button()->bubble_for_testing());
+  ASSERT_TRUE(tab_search_button()->bubble_for_testing()->IsClosed());
+
+  RunUntilBubbleWidgetDestroyed();
 }
 
 IN_PROC_BROWSER_TEST_F(TabSearchButtonBrowserTest, TestBubbleVisible) {
@@ -73,10 +83,10 @@
   // The bubble should be visible after being shown.
   EXPECT_TRUE(tab_search_button()->IsBubbleVisible());
 
-  // Close the tab search bubble widget, the bubble should be cleared from the
-  // TabSearchButton.
   tab_search_button()->CloseTabSearchBubble();
-  ASSERT_EQ(nullptr, tab_search_button()->bubble_for_testing());
+  ASSERT_TRUE(tab_search_button()->bubble_for_testing()->IsClosed());
+
+  RunUntilBubbleWidgetDestroyed();
 }
 
 IN_PROC_BROWSER_TEST_F(TabSearchButtonBrowserTest, BubbleNotVisibleIncognito) {
@@ -100,9 +110,9 @@
   // Accelerator keys should have created the tab search bubble.
   ASSERT_NE(nullptr, tab_search_button()->bubble_for_testing());
 
-  // Close the tab search bubble widget, the bubble should be cleared from the
-  // TabSearchButton.
   tab_search_button()->CloseTabSearchBubble();
-  ASSERT_EQ(nullptr, tab_search_button()->bubble_for_testing());
+  ASSERT_TRUE(tab_search_button()->bubble_for_testing()->IsClosed());
+
+  RunUntilBubbleWidgetDestroyed();
 }
 #endif
diff --git a/chrome/browser/ui/views/toolbar/browser_actions_container_browsertest.cc b/chrome/browser/ui/views/toolbar/browser_actions_container_browsertest.cc
index 725ddc33..a13ffec 100644
--- a/chrome/browser/ui/views/toolbar/browser_actions_container_browsertest.cc
+++ b/chrome/browser/ui/views/toolbar/browser_actions_container_browsertest.cc
@@ -153,7 +153,8 @@
           ->browser_actions();
 
   // Create a second browser.
-  Browser* second_browser = new Browser(Browser::CreateParams(profile(), true));
+  Browser* second_browser =
+      Browser::Create(Browser::CreateParams(profile(), true));
   BrowserActionsContainer* second_container =
       BrowserView::GetBrowserViewForBrowser(second_browser)
           ->toolbar()
diff --git a/chrome/browser/ui/web_applications/test/system_web_app_ui_browsertest.cc b/chrome/browser/ui/web_applications/test/system_web_app_ui_browsertest.cc
index 0346e68..a62e8ab 100644
--- a/chrome/browser/ui/web_applications/test/system_web_app_ui_browsertest.cc
+++ b/chrome/browser/ui/web_applications/test/system_web_app_ui_browsertest.cc
@@ -43,7 +43,7 @@
 
  protected:
   Browser* CreateIncognitoBrowser() {
-    Browser* incognito = new Browser(Browser::CreateParams(
+    Browser* incognito = Browser::Create(Browser::CreateParams(
         browser()->profile()->GetPrimaryOTRProfile(), true));
 
     content::WindowedNotificationObserver observer(
diff --git a/chrome/browser/ui/web_applications/web_app_controller_browsertest.cc b/chrome/browser/ui/web_applications/web_app_controller_browsertest.cc
index f4410209..42c9834 100644
--- a/chrome/browser/ui/web_applications/web_app_controller_browsertest.cc
+++ b/chrome/browser/ui/web_applications/web_app_controller_browsertest.cc
@@ -83,8 +83,8 @@
 Browser*
 WebAppControllerBrowserTestBase::NavigateInNewWindowAndAwaitInstallabilityCheck(
     const GURL& url) {
-  Browser* new_browser =
-      new Browser(Browser::CreateParams(Browser::TYPE_NORMAL, profile(), true));
+  Browser* new_browser = Browser::Create(
+      Browser::CreateParams(Browser::TYPE_NORMAL, profile(), true));
   AddBlankTabAndShow(new_browser);
   NavigateAndAwaitInstallabilityCheck(new_browser, url);
   return new_browser;
diff --git a/chrome/browser/ui/web_applications/web_app_launch_manager.cc b/chrome/browser/ui/web_applications/web_app_launch_manager.cc
index 2496545..a74b79e 100644
--- a/chrome/browser/ui/web_applications/web_app_launch_manager.cc
+++ b/chrome/browser/ui/web_applications/web_app_launch_manager.cc
@@ -89,7 +89,7 @@
                 /*user_gesture=*/true);
   browser_params.initial_show_state = DetermineWindowShowState();
   browser_params.can_resize = can_resize;
-  return new Browser(browser_params);
+  return Browser::Create(browser_params);
 }
 
 content::WebContents* NavigateWebApplicationWindow(
@@ -159,8 +159,8 @@
       disposition = params.disposition;
     } else {
       browser =
-          new Browser(Browser::CreateParams(Browser::TYPE_NORMAL, profile_,
-                                            /*user_gesture=*/true));
+          Browser::Create(Browser::CreateParams(Browser::TYPE_NORMAL, profile_,
+                                                /*user_gesture=*/true));
     }
   } else {
     if (params.disposition == WindowOpenDisposition::CURRENT_TAB &&
diff --git a/chrome/browser/ui/webui/chrome_web_contents_handler.cc b/chrome/browser/ui/webui/chrome_web_contents_handler.cc
index 4c25d8e..d4ef9fe7 100644
--- a/chrome/browser/ui/webui/chrome_web_contents_handler.cc
+++ b/chrome/browser/ui/webui/chrome_web_contents_handler.cc
@@ -44,8 +44,8 @@
   if (!browser) {
     // TODO(erg): OpenURLParams should pass a user_gesture flag, pass it to
     // CreateParams, and pass the real value to nav_params below.
-    browser =
-        new Browser(Browser::CreateParams(Browser::TYPE_NORMAL, profile, true));
+    browser = Browser::Create(
+        Browser::CreateParams(Browser::TYPE_NORMAL, profile, true));
   }
   NavigateParams nav_params(browser, params.url, params.transition);
   nav_params.FillNavigateParamsFromOpenURLParams(params);
@@ -89,7 +89,7 @@
   Browser* browser = chrome::FindTabbedBrowser(profile, false);
   const bool browser_created = !browser;
   if (!browser) {
-    browser = new Browser(
+    browser = Browser::Create(
         Browser::CreateParams(Browser::TYPE_NORMAL, profile, user_gesture));
   }
   NavigateParams params(browser, std::move(new_contents));
diff --git a/chrome/browser/ui/webui/chromeos/edu_coexistence_login_handler_chromeos.cc b/chrome/browser/ui/webui/chromeos/edu_coexistence_login_handler_chromeos.cc
index a0cd0ce1..8429cf03 100644
--- a/chrome/browser/ui/webui/chromeos/edu_coexistence_login_handler_chromeos.cc
+++ b/chrome/browser/ui/webui/chromeos/edu_coexistence_login_handler_chromeos.cc
@@ -53,6 +53,9 @@
 constexpr char kOobe[] = "oobe";
 constexpr char kInSession[] = "in_session";
 
+constexpr char kFetchAccessTokenResultHistogram[] =
+    "AccountManager.EduCoexistence.FetchAccessTokenResult";
+
 signin::IdentityManager* GetIdentityManager() {
   Profile* profile = ProfileManager::GetActiveUserProfile();
   DCHECK(profile);
@@ -197,6 +200,9 @@
 void EduCoexistenceLoginHandler::OnOAuthAccessTokensFetched(
     GoogleServiceAuthError error,
     signin::AccessTokenInfo info) {
+  base::UmaHistogramEnumeration(kFetchAccessTokenResultHistogram, error.state(),
+                                GoogleServiceAuthError::NUM_STATES);
+
   if (error.state() != GoogleServiceAuthError::State::NONE) {
     // TODO(yilkal) call on to the ui to show error screen.
     return;
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
index fb83366..6ecbe04d 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -59,7 +59,6 @@
 #include "chrome/browser/ui/webui/chromeos/login/signin_fatal_error_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h"
-#include "chrome/browser/ui/webui/metrics_handler.h"
 #include "chrome/browser/ui/webui/signin/signin_utils.h"
 #include "chrome/common/channel_info.h"
 #include "chrome/common/chrome_features.h"
@@ -743,8 +742,6 @@
               &GaiaScreenHandler::HandleSecurityTokenPinEntered);
   AddCallback("onFatalError", &GaiaScreenHandler::HandleOnFatalError);
 
-  // Allow UMA metrics collection from JS.
-  web_ui()->AddMessageHandler(std::make_unique<MetricsHandler>());
   BaseScreenHandler::RegisterMessages();
 }
 
diff --git a/chrome/browser/ui/webui/chromeos/multidevice_internals/multidevice_internals_phone_hub_handler.cc b/chrome/browser/ui/webui/chromeos/multidevice_internals/multidevice_internals_phone_hub_handler.cc
index 4df2cf1..57d5494 100644
--- a/chrome/browser/ui/webui/chromeos/multidevice_internals/multidevice_internals_phone_hub_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/multidevice_internals/multidevice_internals_phone_hub_handler.cc
@@ -460,10 +460,6 @@
                     metadatas);
   TryAddingMetadata("browserTabTwoMetadata", browser_tab_status_dict,
                     metadatas);
-  TryAddingMetadata("browserTabThreeMetadata", browser_tab_status_dict,
-                    metadatas);
-  TryAddingMetadata("browserTabFourMetadata", browser_tab_status_dict,
-                    metadatas);
 
   fake_phone_hub_manager_->mutable_phone_model()->SetBrowserTabsModel(
       phonehub::BrowserTabsModel(is_tab_sync_enabled, metadatas));
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc
index 652e6075..5c05f930 100644
--- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc
+++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc
@@ -15,8 +15,7 @@
 #include "chrome/browser/search/instant_service.h"
 #include "chrome/browser/search/instant_service_factory.h"
 #include "chrome/browser/search/ntp_features.h"
-#include "chrome/browser/search/recipe_tasks/recipe_tasks_handler.h"
-#include "chrome/browser/search/shopping_tasks/shopping_tasks_handler.h"
+#include "chrome/browser/search/task_module/task_module_handler.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/ui/search/ntp_user_data_logger.h"
 #include "chrome/browser/ui/search/omnibox_mojo_utils.h"
@@ -251,11 +250,8 @@
   source->AddResourcePath("promo_browser_command.mojom-lite.js",
                           IDR_NEW_TAB_PAGE_PROMO_BROWSER_COMMAND_MOJO_LITE_JS);
   source->AddResourcePath(
-      "modules/recipe_tasks/recipe_tasks.mojom-lite.js",
-      IDR_NEW_TAB_PAGE_MODULES_RECIPE_TASKS_RECIPE_TASKS_MOJO_LITE_JS);
-  source->AddResourcePath(
-      "modules/shopping_tasks/shopping_tasks.mojom-lite.js",
-      IDR_NEW_TAB_PAGE_MODULES_SHOPPING_TASKS_SHOPPING_TASKS_MOJO_LITE_JS);
+      "modules/task_module/task_module.mojom-lite.js",
+      IDR_NEW_TAB_PAGE_MODULES_TASK_MODULE_TASK_MODULE_MOJO_LITE_JS);
 #if !defined(OFFICIAL_BUILD)
   source->AddResourcePath("foo.mojom-lite.js",
                           IDR_NEW_TAB_PAGE_FOO_MOJO_LITE_JS);
@@ -381,16 +377,9 @@
 }
 
 void NewTabPageUI::BindInterface(
-    mojo::PendingReceiver<recipe_tasks::mojom::RecipeTasksHandler>
+    mojo::PendingReceiver<task_module::mojom::TaskModuleHandler>
         pending_receiver) {
-  recipe_tasks_handler_ = std::make_unique<RecipeTasksHandler>(
-      std::move(pending_receiver), profile_);
-}
-
-void NewTabPageUI::BindInterface(
-    mojo::PendingReceiver<shopping_tasks::mojom::ShoppingTasksHandler>
-        pending_receiver) {
-  shopping_tasks_handler_ = std::make_unique<ShoppingTasksHandler>(
+  task_module_handler_ = std::make_unique<TaskModuleHandler>(
       std::move(pending_receiver), profile_);
 }
 #if !defined(OFFICIAL_BUILD)
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.h b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.h
index 5bd1d8e..4aecfe2 100644
--- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.h
+++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.h
@@ -9,8 +9,7 @@
 #include "chrome/browser/media/kaleidoscope/mojom/kaleidoscope.mojom.h"
 #include "chrome/browser/promo_browser_command/promo_browser_command.mojom-forward.h"
 #include "chrome/browser/search/instant_service_observer.h"
-#include "chrome/browser/search/recipe_tasks/recipe_tasks.mojom.h"
-#include "chrome/browser/search/shopping_tasks/shopping_tasks.mojom.h"
+#include "chrome/browser/search/task_module/task_module.mojom.h"
 #if !defined(OFFICIAL_BUILD)
 #include "chrome/browser/ui/webui/new_tab_page/foo/foo.mojom.h"  // nogncheck crbug.com/1125897
 #endif
@@ -38,8 +37,7 @@
 class NewTabPageHandler;
 class Profile;
 class PromoBrowserCommandHandler;
-class RecipeTasksHandler;
-class ShoppingTasksHandler;
+class TaskModuleHandler;
 
 class NewTabPageUI
     : public ui::MojoWebUIController,
@@ -81,17 +79,10 @@
           pending_receiver);
 
   // Instantiates the implementor of the
-  // recipe_tasks::mojom::RecipeTasksHandler mojo interface passing the
-  // pending receiver that will be internally bound.
-  void BindInterface(
-      mojo::PendingReceiver<recipe_tasks::mojom::RecipeTasksHandler>
-          pending_receiver);
-
-  // Instantiates the implementor of the
   // shopping_tasks::mojom::ShoppingTasksHandler mojo interface passing the
   // pending receiver that will be internally bound.
   void BindInterface(
-      mojo::PendingReceiver<shopping_tasks::mojom::ShoppingTasksHandler>
+      mojo::PendingReceiver<task_module::mojom::TaskModuleHandler>
           pending_receiver);
 
 #if !defined(OFFICIAL_BUILD)
@@ -147,8 +138,7 @@
 
   // Mojo implementations for modules:
   std::unique_ptr<KaleidoscopeDataProviderImpl> kaleidoscope_data_provider_;
-  std::unique_ptr<RecipeTasksHandler> recipe_tasks_handler_;
-  std::unique_ptr<ShoppingTasksHandler> shopping_tasks_handler_;
+  std::unique_ptr<TaskModuleHandler> task_module_handler_;
 
   WEB_UI_CONTROLLER_TYPE_DECL();
 
diff --git a/chrome/browser/ui/webui/settings/people_handler_unittest.cc b/chrome/browser/ui/webui/settings/people_handler_unittest.cc
index abd46e7..81d64ca 100644
--- a/chrome/browser/ui/webui/settings/people_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/people_handler_unittest.cc
@@ -109,6 +109,8 @@
                     types.Has(syncer::UserSelectableType::kPasswords));
   result.SetBoolean("preferencesSynced",
                     types.Has(syncer::UserSelectableType::kPreferences));
+  result.SetBoolean("readingListSynced",
+                    types.Has(syncer::UserSelectableType::kReadingList));
   result.SetBoolean("tabsSynced", types.Has(syncer::UserSelectableType::kTabs));
   result.SetBoolean("themesSynced",
                     types.Has(syncer::UserSelectableType::kThemes));
@@ -171,6 +173,8 @@
             types.Has(syncer::UserSelectableType::kPasswords));
   CheckBool(dictionary, "preferencesSynced",
             types.Has(syncer::UserSelectableType::kPreferences));
+  CheckBool(dictionary, "readingListSynced",
+            types.Has(syncer::UserSelectableType::kReadingList));
   CheckBool(dictionary, "tabsSynced",
             types.Has(syncer::UserSelectableType::kTabs));
   CheckBool(dictionary, "themesSynced",
@@ -912,6 +916,7 @@
   CheckBool(dictionary, "extensionsRegistered", true);
   CheckBool(dictionary, "passwordsRegistered", true);
   CheckBool(dictionary, "preferencesRegistered", true);
+  CheckBool(dictionary, "readingListRegistered", true);
   CheckBool(dictionary, "tabsRegistered", true);
   CheckBool(dictionary, "themesRegistered", true);
   CheckBool(dictionary, "typedUrlsRegistered", true);
diff --git a/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc
index 095a38e..4d6fe58 100644
--- a/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc
@@ -188,6 +188,7 @@
       {"syncPageTitle", IDS_SETTINGS_SYNC_SYNC_AND_NON_PERSONALIZED_SERVICES},
       {"passphraseConfirmationPlaceholder",
        IDS_SETTINGS_PASSPHRASE_CONFIRMATION_PLACEHOLDER},
+      {"readingListCheckboxLabel", IDS_SETTINGS_READING_LIST_CHECKBOX_LABEL},
       {"syncLoading", IDS_SETTINGS_SYNC_LOADING},
       {"themesAndWallpapersCheckboxLabel",
        IDS_SETTINGS_THEMES_AND_WALLPAPERS_CHECKBOX_LABEL},
diff --git a/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper_delegate_impl.cc b/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper_delegate_impl.cc
index 918fe594..fffa7a9 100644
--- a/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper_delegate_impl.cc
+++ b/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper_delegate_impl.cc
@@ -33,7 +33,7 @@
     // create a new one.
     browser = chrome::FindLastActiveWithProfile(profile);
     if (!browser) {
-      browser = new Browser(Browser::CreateParams(profile, true));
+      browser = Browser::Create(Browser::CreateParams(profile, true));
       chrome::AddTabAt(browser, GURL(), -1, true);
     }
     browser->window()->Show();
diff --git a/chrome/browser/ui/webui/sync_internals_message_handler_unittest.cc b/chrome/browser/ui/webui/sync_internals_message_handler_unittest.cc
index 1de9bca4..464091891 100644
--- a/chrome/browser/ui/webui/sync_internals_message_handler_unittest.cc
+++ b/chrome/browser/ui/webui/sync_internals_message_handler_unittest.cc
@@ -66,7 +66,8 @@
   void GetEntityCountsForDebugging(
       base::OnceCallback<void(const std::vector<syncer::TypeEntitiesCount>&)>
           callback) const override {
-    return std::move(callback).Run({{syncer::PASSWORDS, 42, 42}});
+    return std::move(callback).Run(
+        {syncer::TypeEntitiesCount(syncer::PASSWORDS)});
   }
 
   int add_observer_count() const { return add_observer_count_; }
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index ae59ec1..7b2b13a 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-master-1603929441-de7c595584c292110f839d1296c0369f387aa3ca.profdata
+chrome-linux-master-1603972752-7774997975c1fc77dd139039f32c4c5217a4f93d.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index a2d9413d..5c53a26 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-master-1603929441-b6b34c1c4b0f9e2ddac4473f28fe820beebad5c9.profdata
+chrome-mac-master-1603972752-eb96abf6b462a9960649372890eeb96e7f549740.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 7a40e73..0e935bb 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-master-1603884477-f14a1ebfd4bd191c8d016252078cbad2c54f6d16.profdata
+chrome-win32-master-1603918565-280375955eaa6ff7fe0c1e66a947d33ea408d529.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 745d78c..01ed051 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-master-1603767556-44fda54b3a92e9d2336119e8c5ad34567957992b.profdata
+chrome-win64-master-1603907949-4ffda8056377a01132d9724a51a14693bc70ab3c.profdata
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index 9ab655a1..afac5d9 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -76,6 +76,7 @@
     public_deps += [ "//components/version_info/android:channel_getter" ]
   } else if (is_chromeos) {
     sources += [ "channel_info_chromeos.cc" ]
+    deps += [ "//chromeos/crosapi/cpp" ]
   } else if (is_posix) {
     sources += [ "channel_info_posix.cc" ]
   }
diff --git a/chrome/common/channel_info_chromeos.cc b/chrome/common/channel_info_chromeos.cc
index c0dcad98..06c1e378 100644
--- a/chrome/common/channel_info_chromeos.cc
+++ b/chrome/common/channel_info_chromeos.cc
@@ -6,6 +6,7 @@
 
 #include "base/system/sys_info.h"
 #include "build/branding_buildflags.h"
+#include "chromeos/crosapi/cpp/crosapi_constants.h"
 #include "components/version_info/version_info.h"
 
 namespace chrome {
@@ -16,13 +17,13 @@
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 // Sets the |g_chromeos_channel|.
 void SetChannel(const std::string& channel) {
-  if (channel == "stable-channel")
+  if (channel == crosapi::kReleaseChannelStable)
     g_chromeos_channel = version_info::Channel::STABLE;
-  else if (channel == "beta-channel")
+  else if (channel == crosapi::kReleaseChannelBeta)
     g_chromeos_channel = version_info::Channel::BETA;
-  else if (channel == "dev-channel")
+  else if (channel == crosapi::kReleaseChannelDev)
     g_chromeos_channel = version_info::Channel::DEV;
-  else if (channel == "canary-channel")
+  else if (channel == crosapi::kReleaseChannelCanary)
     g_chromeos_channel = version_info::Channel::CANARY;
   else
     g_chromeos_channel = version_info::Channel::UNKNOWN;
@@ -55,9 +56,9 @@
     return g_chromeos_channel;
 
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
-  static const char kChromeOSReleaseTrack[] = "CHROMEOS_RELEASE_TRACK";
   std::string channel;
-  if (base::SysInfo::GetLsbReleaseValue(kChromeOSReleaseTrack, &channel)) {
+  if (base::SysInfo::GetLsbReleaseValue(crosapi::kChromeOSReleaseTrack,
+                                        &channel)) {
     SetChannel(channel);
     is_channel_set = true;
   }
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 97aa15f3..9b672fe 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -30,9 +30,6 @@
 // extension API.
 const char kAllowHttpScreenCapture[] = "allow-http-screen-capture";
 
-// Don't block outdated plugins.
-const char kAllowOutdatedPlugins[]          = "allow-outdated-plugins";
-
 // Allows profiles to be created outside of the user data dir.
 // TODO(https://crbug.com/1060366): Various places in Chrome assume that all
 // profiles are within the user data dir. Some tests need to violate that
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index e5e7f18..56aa501 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -37,7 +37,6 @@
 // alongside the definition of their values in the .cc file.
 extern const char kAllowCrossOriginAuthPrompt[];
 extern const char kAllowHttpScreenCapture[];
-extern const char kAllowOutdatedPlugins[];
 extern const char kAllowProfilesOutsideUserDir[];
 extern const char kAllowRunningInsecureContent[];
 extern const char kAllowSilentPush[];
diff --git a/chrome/common/extensions/api/accessibility_private.json b/chrome/common/extensions/api/accessibility_private.json
index 33e2576..0efd90da 100644
--- a/chrome/common/extensions/api/accessibility_private.json
+++ b/chrome/common/extensions/api/accessibility_private.json
@@ -172,6 +172,12 @@
         "type": "string",
         "enum": [ "focusPreviousPane", "focusNextPane" ],
         "description": "A subset of accelerator actions used by accessibility."
+      },
+      {
+        "id": "AccessibilityFeature",
+        "type": "string",
+        "enum": [ "selectToSpeakNavigationControl" ],
+        "description": "Subset of accessibility features."
       }
     ],
     "functions": [
@@ -469,6 +475,29 @@
           }
         ],
         "platforms": ["chromeos"]
+      },
+      {
+        "name": "isFeatureEnabled",
+        "type": "function",
+        "description": "Checks to see if an accessibility feature is enabled.",
+        "parameters": [
+          {
+            "name": "feature",
+            "$ref": "AccessibilityFeature"
+          },
+          {
+            "name": "callback",
+            "type": "function",
+            "description": "Returns whether feature is enabled.",
+            "parameters": [
+              {
+                "name": "featureEnabled",
+                "type": "boolean"
+              }
+            ]
+          }
+        ],
+        "platforms": ["chromeos"]
       }
     ],
     "events": [
diff --git a/chrome/common/privacy_budget/privacy_budget_features.cc b/chrome/common/privacy_budget/privacy_budget_features.cc
index 9571caa..a95c3cdb 100644
--- a/chrome/common/privacy_budget/privacy_budget_features.cc
+++ b/chrome/common/privacy_budget/privacy_budget_features.cc
@@ -30,4 +30,11 @@
 const base::FeatureParam<std::string> kIdentifiabilityStudyPerTypeSettings = {
     &kIdentifiabilityStudy, "TypeRate", ""};
 
+const base::FeatureParam<std::string>
+    kIdentifiabilityStudyPerSurfaceSampleRates = {&kIdentifiabilityStudy,
+                                                  "SurfaceSampleRate", ""};
+
+const base::FeatureParam<std::string> kIdentifiabilityStudyPerTypeSampleRates =
+    {&kIdentifiabilityStudy, "TypeSampleRate", "2;100"};
+
 }  // namespace features
diff --git a/chrome/common/privacy_budget/privacy_budget_features.h b/chrome/common/privacy_budget/privacy_budget_features.h
index e46cc2b8..95ea2e6 100644
--- a/chrome/common/privacy_budget/privacy_budget_features.h
+++ b/chrome/common/privacy_budget/privacy_budget_features.h
@@ -98,7 +98,7 @@
 extern const base::FeatureParam<std::string>
     kIdentifiabilityStudyPerSurfaceSettings;
 
-// Selection rate for clusters of related surfaces.
+// Selection rate for clusters of related surface types.
 //
 // Parameter name: "TypeRate"
 // Parameter type: Comma separated list of <filter-string>;<rate> pairs.
@@ -109,6 +109,27 @@
 extern const base::FeatureParam<std::string>
     kIdentifiabilityStudyPerTypeSettings;
 
+// Sample rates for clusters of related surfaces.
+//
+// Parameter name: "SurfaceSampleRate"
+// Parameter type: Comma separated list of <filter-string>;<rate> pairs.
+//
+// E.g.:
+//   * "257;800" : Sets the selection rate to 1-in-800 for
+//                 IdentifiableSurface::FromTypeAndToken(kWebFeature, 1).
+extern const base::FeatureParam<std::string>
+    kIdentifiabilityStudyPerSurfaceSampleRates;
+
+// Sample rate for clusters of related surface types.
+//
+// Parameter name: "TypeSampleRate"
+// Parameter type: Comma separated list of <filter-string>;<rate> pairs.
+//
+// E.g.:
+//   * "2;1000" : Sets the selection rate to 1-in-1000 for *all* surfaces with
+//                type kCanvasReadback.
+extern const base::FeatureParam<std::string>
+    kIdentifiabilityStudyPerTypeSampleRates;
 }  // namespace features
 
 #endif  // CHROME_COMMON_PRIVACY_BUDGET_PRIVACY_BUDGET_FEATURES_H_
diff --git a/chrome/common/privacy_budget/privacy_budget_settings_provider.cc b/chrome/common/privacy_budget/privacy_budget_settings_provider.cc
index 53c6c23..cb8d34b 100644
--- a/chrome/common/privacy_budget/privacy_budget_settings_provider.cc
+++ b/chrome/common/privacy_budget/privacy_budget_settings_provider.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "base/ranges/algorithm.h"
 #include "base/stl_util.h"
 #include "chrome/common/privacy_budget/field_trial_param_conversions.h"
 #include "chrome/common/privacy_budget/privacy_budget_features.h"
@@ -18,6 +19,12 @@
       blocked_types_(
           DecodeIdentifiabilityFieldTrialParam<IdentifiableSurfaceTypeSet>(
               features::kIdentifiabilityStudyBlockedTypes.Get())),
+      per_surface_sample_rates_(
+          DecodeIdentifiabilityFieldTrialParam<SurfaceSampleRateMap>(
+              features::kIdentifiabilityStudyPerSurfaceSampleRates.Get())),
+      per_type_sample_rates_(
+          DecodeIdentifiabilityFieldTrialParam<TypeSampleRateMap>(
+              features::kIdentifiabilityStudyPerTypeSampleRates.Get())),
 
       // In practice there's really no point in enabling the feature with a max
       // active surface count of 0.
@@ -35,16 +42,54 @@
 }
 
 bool PrivacyBudgetSettingsProvider::IsAnyTypeOrSurfaceBlocked() const {
-  return !blocked_surfaces_.empty() || !blocked_types_.empty();
+  return !blocked_surfaces_.empty() || !blocked_types_.empty() ||
+         base::ranges::any_of(per_surface_sample_rates_,
+                              [](const auto& p) { return p.second == 0; }) ||
+         base::ranges::any_of(per_type_sample_rates_,
+                              [](const auto& p) { return p.second == 0; });
 }
 
 bool PrivacyBudgetSettingsProvider::IsSurfaceAllowed(
     blink::IdentifiableSurface surface) const {
   return !base::Contains(blocked_surfaces_, surface) &&
-         IsTypeAllowed(surface.GetType());
+         IsTypeAllowed(surface.GetType()) && SampleRateImpl(surface) > 0;
 }
 
 bool PrivacyBudgetSettingsProvider::IsTypeAllowed(
     blink::IdentifiableSurface::Type type) const {
-  return !base::Contains(blocked_types_, type);
+  return !base::Contains(blocked_types_, type) && SampleRateImpl(type) > 0;
+}
+
+int PrivacyBudgetSettingsProvider::SampleRate(
+    blink::IdentifiableSurface surface) const {
+  if (base::Contains(blocked_surfaces_, surface) ||
+      base::Contains(blocked_types_, surface.GetType())) {
+    return 0;
+  }
+  return SampleRateImpl(surface);
+}
+
+int PrivacyBudgetSettingsProvider::SampleRate(
+    blink::IdentifiableSurface::Type type) const {
+  if (base::Contains(blocked_types_, type))
+    return 0;
+  return SampleRateImpl(type);
+}
+
+int PrivacyBudgetSettingsProvider::SampleRateImpl(
+    blink::IdentifiableSurface surface) const {
+  auto it = per_surface_sample_rates_.find(surface);
+  if (it != per_surface_sample_rates_.end())
+    return it->second;
+
+  return SampleRateImpl(surface.GetType());
+}
+
+int PrivacyBudgetSettingsProvider::SampleRateImpl(
+    blink::IdentifiableSurface::Type type) const {
+  auto it = per_type_sample_rates_.find(type);
+  if (it != per_type_sample_rates_.end())
+    return it->second;
+
+  return 1;
 }
diff --git a/chrome/common/privacy_budget/privacy_budget_settings_provider.h b/chrome/common/privacy_budget/privacy_budget_settings_provider.h
index b4e44c8..81d597d 100644
--- a/chrome/common/privacy_budget/privacy_budget_settings_provider.h
+++ b/chrome/common/privacy_budget/privacy_budget_settings_provider.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include <unordered_set>
 
+#include "base/containers/flat_map.h"
 #include "third_party/blink/public/common/privacy_budget/identifiability_study_settings_provider.h"
 #include "third_party/blink/public/common/privacy_budget/identifiable_surface.h"
 
@@ -52,8 +53,20 @@
   bool IsAnyTypeOrSurfaceBlocked() const override;
   bool IsSurfaceAllowed(blink::IdentifiableSurface surface) const override;
   bool IsTypeAllowed(blink::IdentifiableSurface::Type type) const override;
+  int SampleRate(blink::IdentifiableSurface surface) const override;
+  int SampleRate(blink::IdentifiableSurface::Type type) const override;
 
  private:
+  using SurfaceSampleRateMap =
+      base::flat_map<blink::IdentifiableSurface,
+                     int,
+                     blink::IdentifiableSurfaceCompLess>;
+  using TypeSampleRateMap =
+      base::flat_map<blink::IdentifiableSurface::Type, int>;
+
+  int SampleRateImpl(blink::IdentifiableSurface surface) const;
+  int SampleRateImpl(blink::IdentifiableSurface::Type type) const;
+
   // Set of identifiable surfaces for which we will NOT collect metrics. This
   // list is server controlled.
   const IdentifiableSurfaceSet blocked_surfaces_;
@@ -62,8 +75,19 @@
   // This list is server controlled.
   const IdentifiableSurfaceTypeSet blocked_types_;
 
-  // True if identifiability study is enabled. If this field is false, then none
-  // of the other values are applicable.
+  // Per surface custom sampling rates. The effective sampling probability for
+  // a surface is the `per_surface_sample_rates_[surface]` if it is defined.
+  // Otherwise defaults to the appropriate `per_type_sample_rate_` or
+  // 1.
+  const SurfaceSampleRateMap per_surface_sample_rates_;
+
+  // Per surface *type* custom sampling rates. The effective sampling
+  // probability for a surface type is the `per_type_sample_rates_[type]` if it
+  // is defined. Otherwise defaults to 1.
+  const TypeSampleRateMap per_type_sample_rates_;
+
+  // True if identifiability study is enabled. If this field is false, then
+  // none of the other values are applicable.
   const bool enabled_ = false;
 };
 
diff --git a/chrome/common/privacy_budget/scoped_privacy_budget_config.cc b/chrome/common/privacy_budget/scoped_privacy_budget_config.cc
index 3d92b507..d532774a 100644
--- a/chrome/common/privacy_budget/scoped_privacy_budget_config.cc
+++ b/chrome/common/privacy_budget/scoped_privacy_budget_config.cc
@@ -11,7 +11,9 @@
 
 namespace test {
 
-ScopedPrivacyBudgetConfig::Parameters::Parameters() = default;
+ScopedPrivacyBudgetConfig::Parameters::Parameters()
+    : per_type_sampling_rate(
+          {{blink::IdentifiableSurface::Type::kCanvasReadback, 1}}) {}
 ScopedPrivacyBudgetConfig::Parameters::Parameters(const Parameters&) = default;
 ScopedPrivacyBudgetConfig::Parameters::Parameters(Parameters&&) = default;
 ScopedPrivacyBudgetConfig::Parameters::~Parameters() = default;
@@ -72,13 +74,23 @@
     ftp.insert({features::kIdentifiabilityStudyMaxSurfaces.name,
                 base::NumberToString(parameters.max_surfaces)});
   }
-  if (!parameters.per_surface_sampling_rate.empty()) {
+  if (!parameters.per_surface_selection_rate.empty()) {
     ftp.insert({features::kIdentifiabilityStudyPerSurfaceSettings.name,
                 EncodeIdentifiabilityFieldTrialParam(
+                    parameters.per_surface_selection_rate)});
+  }
+  if (!parameters.per_type_selection_rate.empty()) {
+    ftp.insert({features::kIdentifiabilityStudyPerTypeSettings.name,
+                EncodeIdentifiabilityFieldTrialParam(
+                    parameters.per_type_selection_rate)});
+  }
+  if (!parameters.per_surface_sampling_rate.empty()) {
+    ftp.insert({features::kIdentifiabilityStudyPerSurfaceSampleRates.name,
+                EncodeIdentifiabilityFieldTrialParam(
                     parameters.per_surface_sampling_rate)});
   }
   if (!parameters.per_type_sampling_rate.empty()) {
-    ftp.insert({features::kIdentifiabilityStudyPerTypeSettings.name,
+    ftp.insert({features::kIdentifiabilityStudyPerTypeSampleRates.name,
                 EncodeIdentifiabilityFieldTrialParam(
                     parameters.per_type_sampling_rate)});
   }
diff --git a/chrome/common/privacy_budget/scoped_privacy_budget_config.h b/chrome/common/privacy_budget/scoped_privacy_budget_config.h
index d84fd64..f81c339 100644
--- a/chrome/common/privacy_budget/scoped_privacy_budget_config.h
+++ b/chrome/common/privacy_budget/scoped_privacy_budget_config.h
@@ -32,8 +32,9 @@
   // These fields correspond to the equivalent features described in
   // privacy_budget_features.h
   //
-  // The default values enable the identifiability study with a sampling rate of
-  // 1, which means every surface is included in UKM reports.
+  // The default values enable the identifiability study with a selection rate
+  // of 1, which means every surface is included in UKM reports, and a sampling
+  // rate of 1, which means every report is sampled.
   struct Parameters {
     Parameters();
     Parameters(const Parameters&);
@@ -47,6 +48,8 @@
     std::vector<blink::IdentifiableSurface::Type> blocked_types;
     int surface_selection_rate = 1;
     int max_surfaces = std::numeric_limits<int>::max();
+    std::map<blink::IdentifiableSurface, int> per_surface_selection_rate;
+    std::map<blink::IdentifiableSurface::Type, int> per_type_selection_rate;
     std::map<blink::IdentifiableSurface, int> per_surface_sampling_rate;
     std::map<blink::IdentifiableSurface::Type, int> per_type_sampling_rate;
   };
diff --git a/chrome/credential_provider/build/make_setup.py b/chrome/credential_provider/build/make_setup.py
index 611cc29..7d9586d5 100755
--- a/chrome/credential_provider/build/make_setup.py
+++ b/chrome/credential_provider/build/make_setup.py
@@ -163,7 +163,7 @@
     # Move the executable into a subfolder as there needs to be only one
     # executable in the parent folder.
     subprocess.check_call(rn_cmd +
-        ['gcpw_extension.exe', 'extension\gcpw_extension.exe'],
+        ['gcpw_extension.exe', os.path.join('extension', 'gcpw_extension.exe')],
         stdout=nul_file)
 
   # Combine the SFX module with the archive to make a self extracting
diff --git a/chrome/renderer/v8_unwinder.cc b/chrome/renderer/v8_unwinder.cc
index 813fa47..86b33ee 100644
--- a/chrome/renderer/v8_unwinder.cc
+++ b/chrome/renderer/v8_unwinder.cc
@@ -8,6 +8,14 @@
 #include <memory>
 #include <utility>
 
+#include "build/build_config.h"
+
+#if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS)
+// V8 requires the embedder to establish the architecture define.
+#define V8_TARGET_ARCH_ARM 1
+#include "v8/include/v8-unwinder-state.h"
+#endif
+
 namespace {
 
 class V8Module : public base::ModuleCache::Module {
@@ -76,6 +84,52 @@
   return range;
 }
 
+void CopyCalleeSavedRegisterFromRegisterContext(
+    const base::RegisterContext& register_context,
+    v8::CalleeSavedRegisters* callee_saved_registers) {
+#if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS)
+  // ARM requires callee-saved registers to be restored:
+  // https://crbug.com/v8/10799.
+  DCHECK(callee_saved_registers);
+  callee_saved_registers->arm_r4 =
+      reinterpret_cast<void*>(register_context.arm_r4);
+  callee_saved_registers->arm_r5 =
+      reinterpret_cast<void*>(register_context.arm_r5);
+  callee_saved_registers->arm_r6 =
+      reinterpret_cast<void*>(register_context.arm_r6);
+  callee_saved_registers->arm_r7 =
+      reinterpret_cast<void*>(register_context.arm_r7);
+  callee_saved_registers->arm_r8 =
+      reinterpret_cast<void*>(register_context.arm_r8);
+  callee_saved_registers->arm_r9 =
+      reinterpret_cast<void*>(register_context.arm_r9);
+  callee_saved_registers->arm_r10 =
+      reinterpret_cast<void*>(register_context.arm_r10);
+#endif
+}
+
+void CopyCalleeSavedRegisterToRegisterContext(
+    const v8::CalleeSavedRegisters* callee_saved_registers,
+    base::RegisterContext& register_context) {
+#if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS)
+  DCHECK(callee_saved_registers);
+  register_context.arm_r4 =
+      reinterpret_cast<uintptr_t>(callee_saved_registers->arm_r4);
+  register_context.arm_r5 =
+      reinterpret_cast<uintptr_t>(callee_saved_registers->arm_r5);
+  register_context.arm_r6 =
+      reinterpret_cast<uintptr_t>(callee_saved_registers->arm_r6);
+  register_context.arm_r7 =
+      reinterpret_cast<uintptr_t>(callee_saved_registers->arm_r7);
+  register_context.arm_r8 =
+      reinterpret_cast<uintptr_t>(callee_saved_registers->arm_r8);
+  register_context.arm_r9 =
+      reinterpret_cast<uintptr_t>(callee_saved_registers->arm_r9);
+  register_context.arm_r10 =
+      reinterpret_cast<uintptr_t>(callee_saved_registers->arm_r10);
+#endif
+}
+
 }  // namespace
 
 V8Unwinder::V8Unwinder(v8::Isolate* isolate)
@@ -199,6 +253,9 @@
   register_state.fp = reinterpret_cast<void*>(
       base::RegisterContextFramePointer(thread_context));
 
+  CopyCalleeSavedRegisterFromRegisterContext(*thread_context,
+                                             register_state.callee_saved.get());
+
   if (!v8::Unwinder::TryUnwindV8Frames(
           js_entry_stubs_, code_ranges_.size(), code_ranges_.buffer(),
           &register_state, reinterpret_cast<const void*>(stack_top))) {
@@ -217,6 +274,9 @@
   base::RegisterContextFramePointer(thread_context) =
       reinterpret_cast<uintptr_t>(register_state.fp);
 
+  CopyCalleeSavedRegisterToRegisterContext(register_state.callee_saved.get(),
+                                           *thread_context);
+
   stack->emplace_back(
       base::RegisterContextInstructionPointer(thread_context),
       module_cache->GetModuleForAddress(
diff --git a/chrome/services/printing/BUILD.gn b/chrome/services/printing/BUILD.gn
index 2be435e9..c514242 100644
--- a/chrome/services/printing/BUILD.gn
+++ b/chrome/services/printing/BUILD.gn
@@ -53,6 +53,13 @@
 
     deps += [ "//skia" ]
   }
+
+  if (is_win || is_mac || is_linux || is_chromeos) {
+    sources += [
+      "print_backend_service_impl.cc",
+      "print_backend_service_impl.h",
+    ]
+  }
 }
 
 if (is_chromeos) {
diff --git a/chrome/services/printing/print_backend_service_impl.cc b/chrome/services/printing/print_backend_service_impl.cc
new file mode 100644
index 0000000..d38d57b
--- /dev/null
+++ b/chrome/services/printing/print_backend_service_impl.cc
@@ -0,0 +1,40 @@
+// 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/services/printing/print_backend_service_impl.h"
+
+#include <string>
+#include <utility>
+
+#include "base/logging.h"
+#include "base/notreached.h"
+#include "base/optional.h"
+#include "chrome/services/printing/public/mojom/print_backend_service.mojom.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "printing/backend/print_backend.h"
+
+namespace printing {
+
+PrintBackendServiceImpl::PrintBackendServiceImpl(
+    mojo::PendingReceiver<mojom::PrintBackendService> receiver)
+    : receiver_(this, std::move(receiver)) {}
+
+PrintBackendServiceImpl::~PrintBackendServiceImpl() = default;
+
+void PrintBackendServiceImpl::Init(const std::string& locale) {
+  print_backend_ = PrintBackend::CreateInstance(locale);
+}
+
+void PrintBackendServiceImpl::GetDefaultPrinterName(
+    mojom::PrintBackendService::GetDefaultPrinterNameCallback callback) {
+  if (!print_backend_) {
+    DLOG(ERROR)
+        << "Print backend instance has not been initialized for locale.";
+    std::move(callback).Run(base::nullopt);
+    return;
+  }
+  std::move(callback).Run(print_backend_->GetDefaultPrinterName());
+}
+
+}  // namespace printing
diff --git a/chrome/services/printing/print_backend_service_impl.h b/chrome/services/printing/print_backend_service_impl.h
new file mode 100644
index 0000000..1ff1e26
--- /dev/null
+++ b/chrome/services/printing/print_backend_service_impl.h
@@ -0,0 +1,47 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_SERVICES_PRINTING_PRINT_BACKEND_SERVICE_IMPL_H_
+#define CHROME_SERVICES_PRINTING_PRINT_BACKEND_SERVICE_IMPL_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "chrome/services/printing/public/mojom/print_backend_service.mojom.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "printing/backend/print_backend.h"
+
+namespace printing {
+
+class PrintBackendServiceImpl : public mojom::PrintBackendService {
+ public:
+  explicit PrintBackendServiceImpl(
+      mojo::PendingReceiver<mojom::PrintBackendService> receiver);
+  PrintBackendServiceImpl(const PrintBackendServiceImpl&) = delete;
+  PrintBackendServiceImpl& operator=(const PrintBackendServiceImpl&) = delete;
+  ~PrintBackendServiceImpl() override;
+
+ private:
+  friend class PrintBackendServiceTestImpl;
+
+  using GetDefaultPrinterCallback =
+      base::OnceCallback<void(const base::Optional<std::string>& printer_name)>;
+
+  // mojom::PrintBackendService implementation:
+  void Init(const std::string& locale) override;
+  void GetDefaultPrinterName(
+      mojom::PrintBackendService::GetDefaultPrinterNameCallback callback)
+      override;
+
+  scoped_refptr<PrintBackend> print_backend_;
+
+  mojo::Receiver<mojom::PrintBackendService> receiver_;
+};
+
+}  // namespace printing
+
+#endif  // CHROME_SERVICES_PRINTING_PRINT_BACKEND_SERVICE_IMPL_H_
diff --git a/chrome/services/printing/public/mojom/BUILD.gn b/chrome/services/printing/public/mojom/BUILD.gn
index 2e0b57cf..c4a948d 100644
--- a/chrome/services/printing/public/mojom/BUILD.gn
+++ b/chrome/services/printing/public/mojom/BUILD.gn
@@ -34,6 +34,10 @@
     sources += [ "pdf_to_emf_converter.mojom" ]
   }
 
+  if (is_win || is_mac || is_linux || is_chromeos) {
+    sources += [ "print_backend_service.mojom" ]
+  }
+
   cpp_typemaps = [
     {
       types = [
diff --git a/chrome/services/printing/public/mojom/print_backend_service.mojom b/chrome/services/printing/public/mojom/print_backend_service.mojom
new file mode 100644
index 0000000..8d4a125d
--- /dev/null
+++ b/chrome/services/printing/public/mojom/print_backend_service.mojom
@@ -0,0 +1,19 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module printing.mojom;
+
+// The main interface to Chrome's Print Backend Service, which performs
+// printer queries and commands to operating system printer drivers in an
+// isolated process.
+interface PrintBackendService {
+  // Establish the locale to be used for calls with this service and the
+  // interface to the underlying data source.
+  Init(string locale);
+
+  // Gets the default printer name from the data source.
+  // No value for `printer_name` is provided if there is a failure.
+  GetDefaultPrinterName()
+    => (string? printer_name);
+};
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 8b8e52c..8569b3e 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3031,6 +3031,14 @@
         "//third_party/widevine/cdm",
       ]
     }
+    if (enable_basic_printing &&
+        (is_win || is_mac || is_linux || is_chromeos)) {
+      sources += [ "../browser/printing/print_backend_browsertest.cc" ]
+      deps += [
+        "//chrome/services/printing:lib",
+        "//printing:test_support",
+      ]
+    }
     if (enable_print_preview) {
       sources += [
         "../browser/printing/pdf_nup_converter_client_browsertest.cc",
@@ -4653,8 +4661,7 @@
 
       # NTP is in native code on Android.
       "../browser/search/ntp_features_unittest.cc",
-      "../browser/search/recipe_tasks/recipe_tasks_service_unittest.cc",
-      "../browser/search/shopping_tasks/shopping_tasks_service_unittest.cc",
+      "../browser/search/task_module/task_module_service_unittest.cc",
     ]
     if (is_posix || is_fuchsia) {
       sources += [ "../browser/process_singleton_posix_unittest.cc" ]
diff --git a/chrome/test/base/in_process_browser_test.cc b/chrome/test/base/in_process_browser_test.cc
index d79ae03..dac9662 100644
--- a/chrome/test/base/in_process_browser_test.cc
+++ b/chrome/test/base/in_process_browser_test.cc
@@ -470,7 +470,7 @@
 // Creates a browser with a single tab (about:blank), waits for the tab to
 // finish loading and shows the browser.
 Browser* InProcessBrowserTest::CreateBrowser(Profile* profile) {
-  Browser* browser = new Browser(Browser::CreateParams(profile, true));
+  Browser* browser = Browser::Create(Browser::CreateParams(profile, true));
   AddBlankTabAndShow(browser);
   return browser;
 }
@@ -480,22 +480,22 @@
   if (!profile)
     profile = browser()->profile();
   // Create a new browser with using the incognito profile.
-  Browser* incognito =
-      new Browser(Browser::CreateParams(profile->GetPrimaryOTRProfile(), true));
+  Browser* incognito = Browser::Create(
+      Browser::CreateParams(profile->GetPrimaryOTRProfile(), true));
   AddBlankTabAndShow(incognito);
   return incognito;
 }
 
 Browser* InProcessBrowserTest::CreateBrowserForPopup(Profile* profile) {
-  Browser* browser =
-      new Browser(Browser::CreateParams(Browser::TYPE_POPUP, profile, true));
+  Browser* browser = Browser::Create(
+      Browser::CreateParams(Browser::TYPE_POPUP, profile, true));
   AddBlankTabAndShow(browser);
   return browser;
 }
 
 Browser* InProcessBrowserTest::CreateBrowserForApp(const std::string& app_name,
                                                    Profile* profile) {
-  Browser* browser = new Browser(Browser::CreateParams::CreateForApp(
+  Browser* browser = Browser::Create(Browser::CreateParams::CreateForApp(
       app_name, false /* trusted_source */, gfx::Rect(), profile, true));
   AddBlankTabAndShow(browser);
   return browser;
@@ -519,7 +519,7 @@
     profile = profile->GetPrimaryOTRProfile();
 
   // Create browser and add tab.
-  Browser* browser = new Browser(Browser::CreateParams(profile, true));
+  Browser* browser = Browser::Create(Browser::CreateParams(profile, true));
   AddBlankTabAndShow(browser);
   return browser;
 }
diff --git a/chrome/test/base/in_process_browser_test_mac.mm b/chrome/test/base/in_process_browser_test_mac.mm
index eb6ef0f..e6a06fdf 100644
--- a/chrome/test/base/in_process_browser_test_mac.mm
+++ b/chrome/test/base/in_process_browser_test_mac.mm
@@ -45,7 +45,7 @@
   // Making a browser window can cause AppKit to throw objects into the
   // autorelease pool. Flush the pool when this function returns.
   @autoreleasepool {
-    Browser* browser = new Browser(Browser::CreateParams(profile, true));
+    Browser* browser = Browser::Create(Browser::CreateParams(profile, true));
     AddBlankTabAndShow(browser);
     return browser;
   }
@@ -60,7 +60,7 @@
       profile = browser()->profile();
 
     // Create a new browser with using the incognito profile.
-    Browser* incognito = new Browser(
+    Browser* incognito = Browser::Create(
         Browser::CreateParams(profile->GetPrimaryOTRProfile(), true));
     AddBlankTabAndShow(incognito);
     return incognito;
@@ -71,8 +71,8 @@
   // Making a browser window can cause AppKit to throw objects into the
   // autorelease pool. Flush the pool when this function returns.
   @autoreleasepool {
-    Browser* browser =
-        new Browser(Browser::CreateParams(Browser::TYPE_POPUP, profile, true));
+    Browser* browser = Browser::Create(
+        Browser::CreateParams(Browser::TYPE_POPUP, profile, true));
     AddBlankTabAndShow(browser);
     return browser;
   }
@@ -83,7 +83,7 @@
   // Making a browser window can cause AppKit to throw objects into the
   // autorelease pool. Flush the pool when this function returns.
   @autoreleasepool {
-    Browser* browser = new Browser(Browser::CreateParams::CreateForApp(
+    Browser* browser = Browser::Create(Browser::CreateParams::CreateForApp(
         app_name, false /* trusted_source */, gfx::Rect(), profile, true));
     AddBlankTabAndShow(browser);
     return browser;
diff --git a/chrome/test/base/test_browser_window_aura.cc b/chrome/test/base/test_browser_window_aura.cc
index 3580bb9..f3cbab5 100644
--- a/chrome/test/base/test_browser_window_aura.cc
+++ b/chrome/test/base/test_browser_window_aura.cc
@@ -84,7 +84,7 @@
 std::unique_ptr<Browser> TestBrowserWindowAura::CreateBrowser(
     Browser::CreateParams* params) {
   params->window = this;
-  browser_ = new Browser(*params);
+  browser_ = Browser::Create(*params);
   return base::WrapUnique(browser_);
 }
 
diff --git a/chrome/test/base/web_ui_browser_test_browsertest.cc b/chrome/test/base/web_ui_browser_test_browsertest.cc
index d8d391af..d87e564 100644
--- a/chrome/test/base/web_ui_browser_test_browsertest.cc
+++ b/chrome/test/base/web_ui_browser_test_browsertest.cc
@@ -77,14 +77,7 @@
 }
 
 // Test that bogus javascript fails fast - no timeout waiting for result.
-// Flaky timeouts on Win7 Tests (dbg)(1); see https://crbug.com/985255.
-#if defined(OS_WIN) && !defined(NDEBUG)
-#define MAYBE_TestRuntimeErrorFailsFast DISABLED_TestRuntimeErrorFailsFast
-#else
-#define MAYBE_TestRuntimeErrorFailsFast TestRuntimeErrorFailsFast
-#endif
-IN_PROC_BROWSER_TEST_F(WebUIBrowserExpectFailTest,
-                       MAYBE_TestRuntimeErrorFailsFast) {
+IN_PROC_BROWSER_TEST_F(WebUIBrowserExpectFailTest, TestRuntimeErrorFailsFast) {
   AddLibrary(base::FilePath(FILE_PATH_LITERAL("runtime_error.js")));
   ui_test_utils::NavigateToURL(browser(), DummyUrl());
   EXPECT_FATAL_FAILURE(RunJavascriptTestNoReturn("TestRuntimeErrorFailsFast"),
diff --git a/chrome/test/data/extensions/api_test/accessibility_private/is_feature_enabled_feature_disabled.html b/chrome/test/data/extensions/api_test/accessibility_private/is_feature_enabled_feature_disabled.html
new file mode 100644
index 0000000..dd201305
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/accessibility_private/is_feature_enabled_feature_disabled.html
@@ -0,0 +1,6 @@
+<!--
+ * 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.
+-->
+<script src="is_feature_enabled_feature_disabled.js"></script>
diff --git a/chrome/test/data/extensions/api_test/accessibility_private/is_feature_enabled_feature_disabled.js b/chrome/test/data/extensions/api_test/accessibility_private/is_feature_enabled_feature_disabled.js
new file mode 100644
index 0000000..1d9c39f3
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/accessibility_private/is_feature_enabled_feature_disabled.js
@@ -0,0 +1,28 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var allTests = [
+  function testFeatureDisabled() {
+    chrome.accessibilityPrivate.isFeatureEnabled(
+        'selectToSpeakNavigationControl', (enabled) => {
+          if (!enabled) {
+            chrome.test.succeed();
+          } else {
+            chrome.test.fail();
+          }
+        });
+  },
+  function testFeatureUnknown() {
+    try {
+      chrome.accessibilityPrivate.isFeatureEnabled('fooBar', () => {});
+      // Should throw error before this point.
+      chrome.test.fail();
+    } catch (err) {
+      // Expect call to throw error.
+      chrome.test.succeed();
+    }
+  }
+];
+
+chrome.test.runTests(allTests);
diff --git a/chrome/test/data/extensions/api_test/accessibility_private/is_feature_enabled_feature_enabled.html b/chrome/test/data/extensions/api_test/accessibility_private/is_feature_enabled_feature_enabled.html
new file mode 100644
index 0000000..3d2f75f
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/accessibility_private/is_feature_enabled_feature_enabled.html
@@ -0,0 +1,6 @@
+<!--
+ * 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.
+-->
+<script src="is_feature_enabled_feature_enabled.js"></script>
diff --git a/chrome/test/data/extensions/api_test/accessibility_private/is_feature_enabled_feature_enabled.js b/chrome/test/data/extensions/api_test/accessibility_private/is_feature_enabled_feature_enabled.js
new file mode 100644
index 0000000..21df79e
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/accessibility_private/is_feature_enabled_feature_enabled.js
@@ -0,0 +1,18 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var allTests = [
+  function testFeatureEnabled() {
+    chrome.accessibilityPrivate.isFeatureEnabled(
+        'selectToSpeakNavigationControl', (enabled) => {
+          if (enabled) {
+            chrome.test.succeed();
+          } else {
+            chrome.test.fail();
+          }
+        });
+  },
+];
+
+chrome.test.runTests(allTests);
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index 44eb804f4..fbc38bef7 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -1601,7 +1601,8 @@
               "installation_mode": "allowed",
               "blocked_permissions": [
                 "history"
-              ]
+              ],
+              "toolbar_pin": "force_pinned"
             },
             "bcdefghijklmnopabcdefghijklmnopa": {
               "installation_mode": "force_installed",
@@ -2584,39 +2585,11 @@
   },
 
   "PluginsAllowedForUrls": {
-    "os": ["win", "linux", "mac", "chromeos"],
-    "policy_pref_mapping_test": [
-      {
-        "policies": { "PluginsAllowedForUrls": ["[*.]google.com"]},
-        "prefs": { "profile.managed_plugins_allowed_for_urls": {} },
-        "indicator_tests": [
-          {
-            "pref": "profile.managed_plugins_allowed_for_urls",
-            "test_setup_js": "document.querySelector('button.exceptions-list-button[contentType=plugins]').click();",
-            "selector": "[content-exception=plugins]"
-          }
-        ],
-        "note": "TODO(bartfab): Flag this with can_be_recommended when http://crbug.com/106682 is fixed."
-      }
-    ]
+    "note": "Deprecated since Chrome 88. See https://crbug.com/1083496"
   },
 
   "PluginsBlockedForUrls": {
-    "os": ["win", "linux", "mac", "chromeos"],
-    "policy_pref_mapping_test": [
-      {
-        "policies": { "PluginsBlockedForUrls": ["[*.]google.com"]},
-        "prefs": { "profile.managed_plugins_blocked_for_urls": {} },
-        "indicator_tests": [
-          {
-            "pref": "profile.managed_plugins_blocked_for_urls",
-            "test_setup_js": "document.querySelector('button.exceptions-list-button[contentType=plugins]').click();",
-            "selector": "[content-exception=plugins]"
-          }
-        ],
-        "note": "TODO(bartfab): Flag this with can_be_recommended when http://crbug.com/106682 is fixed."
-      }
-    ]
+    "note": "Deprecated since Chrome 88. See https://crbug.com/1083496"
   },
 
   "PopupsAllowedForUrls": {
@@ -2857,13 +2830,7 @@
   },
 
   "AllowOutdatedPlugins": {
-    "os": ["win", "linux", "mac", "chromeos"],
-    "policy_pref_mapping_test": [
-      {
-        "policies": {"AllowOutdatedPlugins": true},
-        "prefs": { "plugins.allow_outdated": {}}
-      }
-    ]
+    "note": "Deprecated since Chrome 88. See https://crbug.com/1083496"
   },
 
   "AlwaysAuthorizePlugins": {
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn
index 03dbb65..dd234d6 100644
--- a/chrome/test/data/webui/BUILD.gn
+++ b/chrome/test/data/webui/BUILD.gn
@@ -465,7 +465,6 @@
 js_modulizer("modulize_local") {
   input_files = [
     "cr_focus_row_behavior_test.js",
-    "cr_test.js",
     "fake_chrome_event.js",
     "mock_controller.js",
     "mock_timer.js",
@@ -483,7 +482,7 @@
     "cr_components:closure_compile",
     "cr_elements:closure_compile",
     "inline_login:closure_compile",
-    "js/cr/ui:closure_compile",
+    "js/cr:closure_compile",
     "new_tab_page:closure_compile",
     "print_preview:closure_compile",
     "read_later:closure_compile",
diff --git a/chrome/test/data/webui/cr_test.js b/chrome/test/data/webui/cr_test.js
index e8166c4..2d3d129e 100644
--- a/chrome/test/data/webui/cr_test.js
+++ b/chrome/test/data/webui/cr_test.js
@@ -2,12 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// #import {addSingletonGetter} from 'chrome://resources/js/cr.m.js';
-
-/* #ignore */ var EventTarget;
+var EventTarget;
 
 function setUp() {
-  /* #ignore */ EventTarget = cr.EventTarget;
+  EventTarget = cr.EventTarget;
 }
 
 function testDefineProperty() {
@@ -129,6 +127,7 @@
   var obj = document.createElement('div');
 
   var hit = false;
+
   function onTestSet(value, oldValue) {
     assertEquals(obj, this);
     assertEquals(null, oldValue);
@@ -208,6 +207,7 @@
 function testDefinePropertyBoolAttrEventWithHook() {
   var obj = document.createElement('div');
   var hit = false;
+
   function onTestSet(value, oldValue) {
     assertEquals(obj, this);
     assertTrue(this.test);
@@ -220,7 +220,7 @@
   assertTrue(hit);
 }
 
-/* #export */ function testAddSingletonGetter() {
+function testAddSingletonGetter() {
   function Foo() {}
   cr.addSingletonGetter(Foo);
 
@@ -244,7 +244,7 @@
       x, z, 'Should return a different object after clearing for testing');
 }
 
-/* #export */ function testDefineWithGetter() {
+function testDefineWithGetter() {
   var v = 0;
   cr.define('foo', function() {
     return {
@@ -259,6 +259,3 @@
   v = 1;
   assertEquals(1, foo.v);
 }
-
-window.setUp = setUp;
-window.testAddSingletonGetter = testAddSingletonGetter;
diff --git a/chrome/test/data/webui/js/cr/BUILD.gn b/chrome/test/data/webui/js/cr/BUILD.gn
index 56fb8493..61c9678 100644
--- a/chrome/test/data/webui/js/cr/BUILD.gn
+++ b/chrome/test/data/webui/js/cr/BUILD.gn
@@ -12,6 +12,29 @@
   ]
 }
 
+group("closure_compile") {
+  deps = [
+    ":closure_compile_local",
+    "ui:closure_compile",
+  ]
+}
+
 js_modulizer("modulize_local") {
   input_files = [ "event_target_test.js" ]
 }
+
+js_library("event_target_test.m") {
+  sources =
+      [ "$root_gen_dir/chrome/test/data/webui/js/cr/event_target_test.m.js" ]
+  deps = [
+    "../..:chai_assert",
+    "//ui/webui/resources/js/cr:event_target.m",
+  ]
+  extra_deps = [ ":modulize_local" ]
+}
+
+js_type_check("closure_compile_local") {
+  uses_js_modules = true
+
+  deps = [ ":event_target_test.m" ]
+}
diff --git a/chrome/test/data/webui/js/cr/event_target_test.js b/chrome/test/data/webui/js/cr/event_target_test.js
index 65fcde4..53975fb3 100644
--- a/chrome/test/data/webui/js/cr/event_target_test.js
+++ b/chrome/test/data/webui/js/cr/event_target_test.js
@@ -3,16 +3,17 @@
 // found in the LICENSE file.
 
 // clang-format off
+// #import {assertEquals, assertTrue, assertFalse} from '../../../chai_assert.js';
 // #import {NativeEventTarget as EventTarget} from 'chrome://resources/js/cr/event_target.m.js';
 // clang-format on
 
 /* #ignore */ /* @const */ var EventTarget;
 
-/* #export */ function setUp() {
+function setUp() {
   /* #ignore */ EventTarget = cr.EventTarget;
 }
 
-/* #export */ function testFunctionListener() {
+function testFunctionListener() {
   var fi = 0;
   function f(e) {
     fi++;
@@ -41,20 +42,20 @@
   assertEquals(1, gi, 'Should have been called once');
 }
 
-/* #export */ function testHandleEvent() {
+function testHandleEvent() {
   var fi = 0;
-  var f = {
+  var f = /** @type {!EventListener} */ ({
     handleEvent: function(e) {
       fi++;
     }
-  };
+  });
 
   var gi = 0;
-  var g = {
+  var g = /** @type {!EventListener} */ ({
     handleEvent: function(e) {
       gi++;
     }
-  };
+  });
 
   var et = new EventTarget;
   et.addEventListener('f', f);
@@ -74,7 +75,7 @@
   assertEquals(1, gi, 'Should have been called once');
 }
 
-/* #export */ function testPreventDefault() {
+function testPreventDefault() {
   var i = 0;
   function prevent(e) {
     i++;
@@ -100,7 +101,9 @@
   assertEquals(1, i);
 }
 
-window.setUp = setUp;
-window.testFunctionListener = testFunctionListener;
-window.testHandleEvent = testHandleEvent;
-window.testPreventDefault = testPreventDefault;
+Object.assign(window, {
+  setUp,
+  testFunctionListener,
+  testHandleEvent,
+  testPreventDefault,
+});
diff --git a/chrome/test/data/webui/js/cr/ui/BUILD.gn b/chrome/test/data/webui/js/cr/ui/BUILD.gn
index bcee9a8..aaa92afd 100644
--- a/chrome/test/data/webui/js/cr/ui/BUILD.gn
+++ b/chrome/test/data/webui/js/cr/ui/BUILD.gn
@@ -33,11 +33,23 @@
   extra_deps = [ ":modulize" ]
 }
 
+js_library("command_test.m") {
+  sources =
+      [ "$root_gen_dir/chrome/test/data/webui/js/cr/ui/command_test.m.js" ]
+  deps = [
+    "../../..:chai_assert",
+    "//ui/webui/resources/js/cr:ui.m",
+    "//ui/webui/resources/js/cr/ui:command.m",
+  ]
+  extra_deps = [ ":modulize" ]
+}
+
 js_type_check("closure_compile") {
   uses_js_modules = true
 
   deps = [
     ":array_data_model_test.m",
+    ":command_test.m",
     "../../..:chai_assert",
   ]
 }
diff --git a/chrome/test/data/webui/js/cr/ui/command_test.js b/chrome/test/data/webui/js/cr/ui/command_test.js
index 22f02af..a6fed225 100644
--- a/chrome/test/data/webui/js/cr/ui/command_test.js
+++ b/chrome/test/data/webui/js/cr/ui/command_test.js
@@ -2,16 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// clang-format off
+// #import {assertEquals, assertTrue, assertFalse} from '../../../chai_assert.js';
 // #import {Command} from 'chrome://resources/js/cr/ui/command.m.js';
 // #import {decorate} from 'chrome://resources/js/cr/ui.m.js';
+// clang-format on
 
-/* #export */ function setUp() {
+function setUp() {
   const cmd = document.createElement('command');
   cmd.setAttribute('shortcut', 'n|Ctrl');
   document.body.appendChild(cmd);
 }
 
-/* #export */ function testCommandDefaultPrevented() {
+function testCommandDefaultPrevented() {
   var calls = 0;
   document.addEventListener('canExecute', function(e) {
     ++calls;
@@ -21,7 +24,8 @@
   });
 
   cr.ui.decorate('command', cr.ui.Command);
-  document.querySelector('command').canExecuteChange();
+  /** @type {!cr.ui.Command} */ (document.querySelector('command'))
+      .canExecuteChange();
   assertEquals(1, calls);
 }
 
@@ -37,9 +41,9 @@
   };
 }
 
-/* #export */ function testShortcuts() {
+function testShortcuts() {
   cr.ui.decorate('command', cr.ui.Command);
-  const cmd = document.querySelector('command');
+  const cmd = /** @type {!cr.ui.Command} */ (document.querySelector('command'));
   // US keyboard - qwerty-N should work.
   assertTrue(cmd.matchesEvent(createEvent('n', 'KeyN', 0x4e)));
   // DV keyboard - qwerty-L (dvorak-N) should work.
@@ -50,6 +54,8 @@
   assertTrue(cmd.matchesEvent(createEvent('Ñ‚', 'KeyN', 0x4e)));
 }
 
-window.setUp = setUp;
-window.testCommandDefaultPrevented = testCommandDefaultPrevented;
-window.testShortcuts = testShortcuts;
+Object.assign(window, {
+  setUp,
+  testCommandDefaultPrevented,
+  testShortcuts,
+});
diff --git a/chrome/test/data/webui/new_tab_page/modules/recipe_tasks/module_test.js b/chrome/test/data/webui/new_tab_page/modules/recipe_tasks/module_test.js
deleted file mode 100644
index 0df140b..0000000
--- a/chrome/test/data/webui/new_tab_page/modules/recipe_tasks/module_test.js
+++ /dev/null
@@ -1,197 +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.
-
-import {recipeTasksDescriptor, RecipeTasksHandlerProxy} from 'chrome://new-tab-page/new_tab_page.js';
-import {TestBrowserProxy} from 'chrome://test/test_browser_proxy.m.js';
-import {eventToPromise} from 'chrome://test/test_util.m.js';
-
-suite('NewTabPageModulesRecipeTasksModuleTest', () => {
-  /**
-   * @implements {RecipeTasksHandlerProxy}
-   * @extends {TestBrowserProxy}
-   */
-  let testProxy;
-
-  setup(() => {
-    PolymerTest.clearBody();
-
-    testProxy = TestBrowserProxy.fromClass(RecipeTasksHandlerProxy);
-    testProxy.handler =
-        TestBrowserProxy.fromClass(recipeTasks.mojom.RecipeTasksHandlerRemote);
-    RecipeTasksHandlerProxy.instance_ = testProxy;
-  });
-
-  test('creates no module if no task', async () => {
-    // Arrange.
-    testProxy.handler.setResultFor(
-        'getPrimaryRecipeTask', Promise.resolve({recipeTask: null}));
-
-    // Act.
-    await recipeTasksDescriptor.initialize();
-
-    // Assert.
-    assertEquals(1, testProxy.handler.getCallCount('getPrimaryRecipeTask'));
-    assertEquals(null, recipeTasksDescriptor.element);
-  });
-
-  test('creates module if task', async () => {
-    // Arrange.
-    const recipeTask = {
-      title: 'Hello world',
-      recipes: [
-        {
-          name: 'foo',
-          imageUrl: {url: 'https://foo.com/img.png'},
-          info: 'foo info',
-          targetUrl: {url: 'https://foo.com'},
-        },
-        {
-          name: 'bar',
-          imageUrl: {url: 'https://bar.com/img.png'},
-          info: 'bar info',
-          targetUrl: {url: 'https://bar.com'},
-        },
-      ],
-      relatedSearches: [
-        {
-          text: 'baz',
-          targetUrl: {url: 'https://baz.com'},
-        },
-        {
-          text: 'blub',
-          targetUrl: {url: 'https://blub.com'},
-        },
-      ],
-    };
-    testProxy.handler.setResultFor(
-        'getPrimaryRecipeTask', Promise.resolve({recipeTask}));
-
-    // Act.
-    await recipeTasksDescriptor.initialize();
-    const module = recipeTasksDescriptor.element;
-    document.body.append(module);
-    module.$.recipesRepeat.render();
-    module.$.relatedSearchesRepeat.render();
-
-    // Assert.
-    const recipes = Array.from(module.shadowRoot.querySelectorAll('.recipe'));
-    const pills = Array.from(module.shadowRoot.querySelectorAll('.pill'));
-    assertEquals(1, testProxy.handler.getCallCount('getPrimaryRecipeTask'));
-    assertEquals(2, recipes.length);
-    assertEquals(2, pills.length);
-    assertEquals('https://foo.com/', recipes[0].href);
-    assertEquals(
-        'https://foo.com/img.png', recipes[0].querySelector('img').autoSrc);
-    assertEquals('foo', recipes[0].querySelector('.name').innerText);
-    assertEquals('foo', recipes[0].querySelector('.name').title);
-    assertEquals('foo info', recipes[0].querySelector('.info').innerText);
-    assertEquals('https://bar.com/', recipes[1].href);
-    assertEquals(
-        'https://bar.com/img.png', recipes[1].querySelector('img').autoSrc);
-    assertEquals('bar', recipes[1].querySelector('.name').innerText);
-    assertEquals('bar', recipes[1].querySelector('.name').title);
-    assertEquals('bar info', recipes[1].querySelector('.info').innerText);
-    assertEquals('https://baz.com/', pills[0].href);
-    assertEquals('baz', pills[0].querySelector('.search-text').innerText);
-    assertEquals('https://blub.com/', pills[1].href);
-    assertEquals('blub', pills[1].querySelector('.search-text').innerText);
-  });
-
-  test('recipes and pills are hidden when cutoff', async () => {
-    const repeat = (n, fn) => Array(n).fill(0).map(fn);
-    testProxy.handler.setResultFor('getPrimaryRecipeTask', Promise.resolve({
-      recipeTask: {
-        title: 'Hello world',
-        recipes: repeat(20, () => ({
-                              name: 'foo',
-                              imageUrl: {url: 'https://foo.com/img.png'},
-                              info: 'foo info',
-                              targetUrl: {url: 'https://foo.com'},
-                            })),
-        relatedSearches: repeat(20, () => ({
-                                      text: 'baz',
-                                      targetUrl: {url: 'https://baz.com'},
-                                    })),
-      }
-    }));
-    await recipeTasksDescriptor.initialize();
-    const moduleElement = recipeTasksDescriptor.element;
-    document.body.append(moduleElement);
-    moduleElement.$.recipesRepeat.render();
-    moduleElement.$.relatedSearchesRepeat.render();
-    const getElements = () =>
-        Array.from(moduleElement.shadowRoot.querySelectorAll('.recipe, .pill'));
-    assertEquals(40, getElements().length);
-    const hiddenCount = () =>
-        getElements().filter(el => el.style.visibility === 'hidden').length;
-    const checkHidden = async (width, count) => {
-      const waitForVisibilityUpdate =
-          eventToPromise('visibility-update', moduleElement);
-      moduleElement.style.width = width;
-      await waitForVisibilityUpdate;
-      assertEquals(count, hiddenCount());
-    };
-    await checkHidden('500px', 31);
-    await checkHidden('300px', 35);
-    await checkHidden('700px', 26);
-    await checkHidden('500px', 31);
-  });
-
-  test('Backend is notified when module is dismissed or restored', async () => {
-    // Arrange.
-    const recipeTask = {
-      title: 'Continue searching for Hello world',
-      name: 'Hello world',
-      recipes: [
-        {
-          name: 'foo',
-          imageUrl: {url: 'https://foo.com/img.png'},
-          info: 'foo info',
-          targetUrl: {url: 'https://foo.com'},
-        },
-        {
-          name: 'bar',
-          imageUrl: {url: 'https://bar.com/img.png'},
-          info: 'bar info',
-          targetUrl: {url: 'https://bar.com'},
-        },
-      ],
-      relatedSearches: [
-        {
-          text: 'baz',
-          targetUrl: {url: 'https://baz.com'},
-        },
-        {
-          text: 'blub',
-          targetUrl: {url: 'https://blub.com'},
-        },
-      ],
-    };
-    testProxy.handler.setResultFor(
-        'getPrimaryRecipeTask', Promise.resolve({recipeTask}));
-
-
-    // Act.
-    await recipeTasksDescriptor.initialize();
-
-    // Assert.
-    assertEquals('function', typeof recipeTasksDescriptor.actions.dismiss);
-    assertEquals('function', typeof recipeTasksDescriptor.actions.restore);
-
-    // Act.
-    const toastMessage = recipeTasksDescriptor.actions.dismiss();
-
-    // Assert.
-    assertEquals('Removed Hello world', toastMessage);
-    assertEquals(
-        'Hello world', await testProxy.handler.whenCalled('dismissRecipeTask'));
-
-    // Act.
-    recipeTasksDescriptor.actions.restore();
-
-    // Assert.
-    assertEquals(
-        'Hello world', await testProxy.handler.whenCalled('restoreRecipeTask'));
-  });
-});
diff --git a/chrome/test/data/webui/new_tab_page/modules/shopping_tasks/module_test.js b/chrome/test/data/webui/new_tab_page/modules/task_module/module_test.js
similarity index 71%
rename from chrome/test/data/webui/new_tab_page/modules/shopping_tasks/module_test.js
rename to chrome/test/data/webui/new_tab_page/modules/task_module/module_test.js
index b8f279f..dff5ed7 100644
--- a/chrome/test/data/webui/new_tab_page/modules/shopping_tasks/module_test.js
+++ b/chrome/test/data/webui/new_tab_page/modules/task_module/module_test.js
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {shoppingTasksDescriptor, ShoppingTasksHandlerProxy} from 'chrome://new-tab-page/new_tab_page.js';
+import {shoppingTasksDescriptor, TaskModuleHandlerProxy} from 'chrome://new-tab-page/new_tab_page.js';
 import {TestBrowserProxy} from 'chrome://test/test_browser_proxy.m.js';
 import {eventToPromise} from 'chrome://test/test_util.m.js';
 
-suite('NewTabPageModulesShoppingTasksModuleTest', () => {
+suite('NewTabPageModulesTaskModuleTest', () => {
   /**
-   * @implements {ShoppingTasksHandlerProxy}
+   * @implements {TaskModuleHandlerProxy}
    * @extends {TestBrowserProxy}
    */
   let testProxy;
@@ -16,30 +16,30 @@
   setup(() => {
     PolymerTest.clearBody();
 
-    testProxy = TestBrowserProxy.fromClass(ShoppingTasksHandlerProxy);
-    testProxy.handler = TestBrowserProxy.fromClass(
-        shoppingTasks.mojom.ShoppingTasksHandlerRemote);
-    ShoppingTasksHandlerProxy.instance_ = testProxy;
+    testProxy = TestBrowserProxy.fromClass(TaskModuleHandlerProxy);
+    testProxy.handler =
+        TestBrowserProxy.fromClass(taskModule.mojom.TaskModuleHandlerRemote);
+    TaskModuleHandlerProxy.instance_ = testProxy;
   });
 
   test('creates no module if no task', async () => {
     // Arrange.
     testProxy.handler.setResultFor(
-        'getPrimaryShoppingTask', Promise.resolve({shoppingTask: null}));
+        'getPrimaryTask', Promise.resolve({task: null}));
 
     // Act.
     await shoppingTasksDescriptor.initialize();
 
     // Assert.
-    assertEquals(1, testProxy.handler.getCallCount('getPrimaryShoppingTask'));
+    assertEquals(1, testProxy.handler.getCallCount('getPrimaryTask'));
     assertEquals(null, shoppingTasksDescriptor.element);
   });
 
   test('creates module if task', async () => {
     // Arrange.
-    const shoppingTask = {
+    const task = {
       title: 'Hello world',
-      products: [
+      taskItems: [
         {
           name: 'foo',
           imageUrl: {url: 'https://foo.com/img.png'},
@@ -66,20 +66,21 @@
         },
       ],
     };
-    testProxy.handler.setResultFor(
-        'getPrimaryShoppingTask', Promise.resolve({shoppingTask}));
+    testProxy.handler.setResultFor('getPrimaryTask', Promise.resolve({task}));
 
     // Act.
     await shoppingTasksDescriptor.initialize();
-    const module = shoppingTasksDescriptor.element;
-    document.body.append(module);
-    module.$.productsRepeat.render();
-    module.$.relatedSearchesRepeat.render();
+    const moduleElement = shoppingTasksDescriptor.element;
+    document.body.append(moduleElement);
+    moduleElement.$.taskItemsRepeat.render();
+    moduleElement.$.relatedSearchesRepeat.render();
 
     // Assert.
-    const products = Array.from(module.shadowRoot.querySelectorAll('.product'));
-    const pills = Array.from(module.shadowRoot.querySelectorAll('.pill'));
-    assertEquals(1, testProxy.handler.getCallCount('getPrimaryShoppingTask'));
+    const products =
+        Array.from(moduleElement.shadowRoot.querySelectorAll('.task-item'));
+    const pills =
+        Array.from(moduleElement.shadowRoot.querySelectorAll('.pill'));
+    assertEquals(1, testProxy.handler.getCallCount('getPrimaryTask'));
     assertEquals(2, products.length);
     assertEquals(2, pills.length);
     assertEquals('https://foo.com/', products[0].href);
@@ -106,16 +107,16 @@
 
   test('products and pills are hidden when cutoff', async () => {
     const repeat = (n, fn) => Array(n).fill(0).map(fn);
-    testProxy.handler.setResultFor('getPrimaryShoppingTask', Promise.resolve({
-      shoppingTask: {
+    testProxy.handler.setResultFor('getPrimaryTask', Promise.resolve({
+      task: {
         title: 'Hello world',
-        products: repeat(20, () => ({
-                               name: 'foo',
-                               imageUrl: {url: 'https://foo.com/img.png'},
-                               price: '1 gazillion dollars',
-                               info: 'foo info',
-                               targetUrl: {url: 'https://foo.com'},
-                             })),
+        taskItems: repeat(20, () => ({
+                                name: 'foo',
+                                imageUrl: {url: 'https://foo.com/img.png'},
+                                price: '1 gazillion dollars',
+                                info: 'foo info',
+                                targetUrl: {url: 'https://foo.com'},
+                              })),
         relatedSearches: repeat(20, () => ({
                                       text: 'baz',
                                       targetUrl: {url: 'https://baz.com'},
@@ -125,10 +126,10 @@
     await shoppingTasksDescriptor.initialize();
     const moduleElement = shoppingTasksDescriptor.element;
     document.body.append(moduleElement);
-    moduleElement.$.productsRepeat.render();
+    moduleElement.$.taskItemsRepeat.render();
     moduleElement.$.relatedSearchesRepeat.render();
     const getElements = () => Array.from(
-        moduleElement.shadowRoot.querySelectorAll('.product, .pill'));
+        moduleElement.shadowRoot.querySelectorAll('.task-item, .pill'));
     assertEquals(40, getElements().length);
     const hiddenCount = () =>
         getElements().filter(el => el.style.visibility === 'hidden').length;
@@ -147,10 +148,10 @@
 
   test('Backend is notified when module is dismissed or restored', async () => {
     // Arrange.
-    const shoppingTask = {
+    const task = {
       title: 'Continue searching for Hello world',
       name: 'Hello world',
-      products: [
+      taskItems: [
         {
           name: 'foo',
           imageUrl: {url: 'https://foo.com/img.png'},
@@ -177,8 +178,7 @@
         },
       ],
     };
-    testProxy.handler.setResultFor(
-        'getPrimaryShoppingTask', Promise.resolve({shoppingTask}));
+    testProxy.handler.setResultFor('getPrimaryTask', Promise.resolve({task}));
 
 
     // Act.
@@ -193,16 +193,16 @@
 
     // Assert.
     assertEquals('Removed Hello world', toastMessage);
-    assertEquals(
-        'Hello world',
-        await testProxy.handler.whenCalled('dismissShoppingTask'));
+    assertDeepEquals(
+        [taskModule.mojom.TaskModuleType.kShopping, 'Hello world'],
+        await testProxy.handler.whenCalled('dismissTask'));
 
     // Act.
     shoppingTasksDescriptor.actions.restore();
 
     // Assert.
-    assertEquals(
-        'Hello world',
-        await testProxy.handler.whenCalled('restoreShoppingTask'));
+    assertDeepEquals(
+        [taskModule.mojom.TaskModuleType.kShopping, 'Hello world'],
+        await testProxy.handler.whenCalled('restoreTask'));
   });
 });
diff --git a/chrome/test/data/webui/new_tab_page/new_tab_page_browsertest.js b/chrome/test/data/webui/new_tab_page/new_tab_page_browsertest.js
index 57bc79a..6a5303e 100644
--- a/chrome/test/data/webui/new_tab_page/new_tab_page_browsertest.js
+++ b/chrome/test/data/webui/new_tab_page/new_tab_page_browsertest.js
@@ -245,27 +245,13 @@
 });
 
 // eslint-disable-next-line no-var
-var NewTabPageModulesRecipeTasksModuleTest =
-    class extends NewTabPageBrowserTest {
+var NewTabPageModulesTaskModuleTest = class extends NewTabPageBrowserTest {
   /** @override */
   get browsePreload() {
-    return 'chrome://new-tab-page/test_loader.html?module=new_tab_page/modules/recipe_tasks/module_test.js';
+    return 'chrome://new-tab-page/test_loader.html?module=new_tab_page/modules/task_module/module_test.js';
   }
 };
 
-TEST_F('NewTabPageModulesRecipeTasksModuleTest', 'All', function() {
-  mocha.run();
-});
-
-// eslint-disable-next-line no-var
-var NewTabPageModulesShoppingTasksModuleTest =
-    class extends NewTabPageBrowserTest {
-  /** @override */
-  get browsePreload() {
-    return 'chrome://new-tab-page/test_loader.html?module=new_tab_page/modules/shopping_tasks/module_test.js';
-  }
-};
-
-TEST_F('NewTabPageModulesShoppingTasksModuleTest', 'All', function() {
+TEST_F('NewTabPageModulesTaskModuleTest', 'All', function() {
   mocha.run();
 });
diff --git a/chrome/test/data/webui/settings/sync_test_util.js b/chrome/test/data/webui/settings/sync_test_util.js
index 13f63b2..9f2c006a 100644
--- a/chrome/test/data/webui/settings/sync_test_util.js
+++ b/chrome/test/data/webui/settings/sync_test_util.js
@@ -34,6 +34,8 @@
       paymentsIntegrationEnabled: true,
       preferencesRegistered: true,
       preferencesSynced: true,
+      readingListRegistered: true,
+      readingListSynced: true,
       setNewPassphrase: false,
       syncAllDataTypes: true,
       tabsRegistered: true,
diff --git a/chrome/test/data/webui/webui_resource_browsertest.cc b/chrome/test/data/webui/webui_resource_browsertest.cc
index be7f0f1..e03a10b 100644
--- a/chrome/test/data/webui/webui_resource_browsertest.cc
+++ b/chrome/test/data/webui/webui_resource_browsertest.cc
@@ -61,10 +61,6 @@
   LoadTestUrl("cr_test.html");
 }
 
-IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, CrModuleTest) {
-  LoadTestUrl("?module=cr_test.m.js");
-}
-
 IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, CrReloadTest) {
   LoadTestUrl("cr_reload_test.html");
 }
diff --git a/chrome/utility/DEPS b/chrome/utility/DEPS
index 29b5f28c..b7f4d57 100644
--- a/chrome/utility/DEPS
+++ b/chrome/utility/DEPS
@@ -12,6 +12,7 @@
   # when Cloud print chrome/service is removed.
   "+chrome/services/printing/pdf_to_emf_converter_factory.h",
   "+chrome/services/printing/printing_service.h",
+  "+chrome/services/printing/print_backend_service_impl.h",
   "+chrome/services/printing/public/mojom",
   "+chrome/services/qrcode_generator",
   "+chrome/services/removable_storage_writer",
diff --git a/chrome/utility/services.cc b/chrome/utility/services.cc
index 5d3864f2..9660f26b 100644
--- a/chrome/utility/services.cc
+++ b/chrome/utility/services.cc
@@ -25,6 +25,7 @@
 #include "content/public/common/content_features.h"
 #include "content/public/utility/utility_thread.h"
 #include "extensions/buildflags/buildflags.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/service_factory.h"
 #include "printing/buildflags/buildflags.h"
 
@@ -74,9 +75,15 @@
 #endif
 
 #if BUILDFLAG(ENABLE_PRINTING)
+#if defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) || \
+    defined(OS_CHROMEOS)
+#include "chrome/services/printing/print_backend_service_impl.h"
+#include "chrome/services/printing/public/mojom/print_backend_service.mojom.h"
+#endif
+
 #include "components/services/print_compositor/print_compositor_impl.h"  // nogncheck
 #include "components/services/print_compositor/public/mojom/print_compositor.mojom.h"  // nogncheck
-#endif
+#endif  // BUILDFLAG(ENABLE_PRINTING)
 
 #include "components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.h"
 #include "components/services/paint_preview_compositor/public/mojom/paint_preview_compositor.mojom.h"
@@ -216,13 +223,22 @@
 #endif  // BUILDFLAG(ENABLE_PAINT_PREVIEW)
 
 #if BUILDFLAG(ENABLE_PRINTING)
+#if defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) || \
+    defined(OS_CHROMEOS)
+auto RunPrintBackendService(
+    mojo::PendingReceiver<printing::mojom::PrintBackendService> receiver) {
+  return std::make_unique<printing::PrintBackendServiceImpl>(
+      std::move(receiver));
+}
+#endif
+
 auto RunPrintCompositor(
     mojo::PendingReceiver<printing::mojom::PrintCompositor> receiver) {
   return std::make_unique<printing::PrintCompositorImpl>(
       std::move(receiver), true /* initialize_environment */,
       content::UtilityThread::Get()->GetIOTaskRunner());
 }
-#endif
+#endif  // BUILDFLAG(ENABLE_PRINTING)
 
 #if defined(OS_CHROMEOS)
 auto RunImeService(
@@ -303,6 +319,10 @@
 #endif
 
 #if BUILDFLAG(ENABLE_PRINTING)
+#if defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) || \
+    defined(OS_CHROMEOS)
+  services.Add(RunPrintBackendService);
+#endif
   services.Add(RunPrintCompositor);
 #endif
 
diff --git a/chromeos/components/media_app_ui/resources/js/piex_module.js b/chromeos/components/media_app_ui/resources/js/piex_module.js
index 2e4677e..b8340602 100644
--- a/chromeos/components/media_app_ui/resources/js/piex_module.js
+++ b/chromeos/components/media_app_ui/resources/js/piex_module.js
@@ -133,8 +133,8 @@
  * @return {!Promise<!File>}
  */
 async function extractFromRawImageBuffer(buffer) {
-  /** Quantization table. */
-  const DQT_MARKER = 0xffdb;
+  /** Application Segment Marker. */
+  const APP1_MARKER = 0xffe1;
 
   /** SOI. Page 64. */
   const START_OF_IMAGE = 0xffd8;
@@ -171,9 +171,11 @@
     return original('No SOI');
   }
 
-  // Files returned by Piex should begin immediately with JPEG headers.
-  if (view.getUint16(2) !== DQT_MARKER) {
-    return original('Unexpected marker');
+  // Files returned by Piex should begin immediately with JPEG headers (and the
+  // Define Quantization Table marker). If a layer between here and Piex has
+  // added its own APP marker segment(s), don't add a duplicate.
+  if (view.getUint16(2) === APP1_MARKER) {
+    return original('APP1 marker already present');
   }
 
   // Ignore the Start-Of-Image already in `jpegData` (TIFF_HEADER has one).
diff --git a/chromeos/components/phonehub/browser_tabs_model.cc b/chromeos/components/phonehub/browser_tabs_model.cc
index d8dbba0..fed4184 100644
--- a/chromeos/components/phonehub/browser_tabs_model.cc
+++ b/chromeos/components/phonehub/browser_tabs_model.cc
@@ -9,7 +9,7 @@
 namespace chromeos {
 namespace phonehub {
 
-const size_t BrowserTabsModel::kMaxMostRecentTabs = 4;
+const size_t BrowserTabsModel::kMaxMostRecentTabs = 2;
 
 BrowserTabsModel::BrowserTabMetadata::BrowserTabMetadata(
     GURL url,
diff --git a/chromeos/constants/BUILD.gn b/chromeos/constants/BUILD.gn
index 2fa3e0b..3e451420 100644
--- a/chromeos/constants/BUILD.gn
+++ b/chromeos/constants/BUILD.gn
@@ -12,7 +12,6 @@
     "//base:i18n",
     "//build:branding_buildflags",
     "//chromeos/dbus/constants",
-    "//third_party/icu",
   ]
   sources = [
     "chromeos_constants.cc",
diff --git a/chromeos/constants/chromeos_features.cc b/chromeos/constants/chromeos_features.cc
index 475bb61..9070f04 100644
--- a/chromeos/constants/chromeos_features.cc
+++ b/chromeos/constants/chromeos_features.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "chromeos/constants/chromeos_features.h"
+
 #include "base/feature_list.h"
 #include "base/metrics/field_trial_params.h"
 
diff --git a/chromeos/constants/chromeos_switches.cc b/chromeos/constants/chromeos_switches.cc
index bceb5c3..69957b9 100644
--- a/chromeos/constants/chromeos_switches.cc
+++ b/chromeos/constants/chromeos_switches.cc
@@ -8,7 +8,6 @@
 
 #include "base/command_line.h"
 #include "base/metrics/field_trial.h"
-#include "third_party/icu/source/common/unicode/locid.h"
 
 namespace chromeos {
 namespace switches {
@@ -534,12 +533,6 @@
 // App window previews when hovering over the shelf.
 const char kShelfHoverPreviews[] = "shelf-hover-previews";
 
-// If true, files in Android internal storage will be shown in Files app.
-const char kShowAndroidFilesInFilesApp[] = "show-android-files-in-files-app";
-
-// If true, files in Android internal storage will be hidden in Files app.
-const char kHideAndroidFilesInFilesApp[] = "hide-android-files-in-files-app";
-
 // The name of the per-model directory which contains per-region
 // subdirectories with regulatory label files for this model.
 // The per-model directories (if there are any) are located under
diff --git a/chromeos/constants/chromeos_switches.h b/chromeos/constants/chromeos_switches.h
index 2814c64..480bafd 100644
--- a/chromeos/constants/chromeos_switches.h
+++ b/chromeos/constants/chromeos_switches.h
@@ -165,8 +165,6 @@
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kGuestWallpaperLarge[];
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kGuestWallpaperSmall[];
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kHasChromeOSKeyboard[];
-COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
-extern const char kHideAndroidFilesInFilesApp[];
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kHomedir[];
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kIgnoreArcVmDevConf[];
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
@@ -208,8 +206,6 @@
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kSamlPasswordChangeUrl[];
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kShelfHoverPreviews[];
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kShelfHotseat[];
-COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
-extern const char kShowAndroidFilesInFilesApp[];
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kShowLoginDevOverlay[];
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kShowOobeDevOverlay[];
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
diff --git a/chromeos/crosapi/cpp/crosapi_constants.cc b/chromeos/crosapi/cpp/crosapi_constants.cc
index 9936a06..e7504b0 100644
--- a/chromeos/crosapi/cpp/crosapi_constants.cc
+++ b/chromeos/crosapi/cpp/crosapi_constants.cc
@@ -27,4 +27,13 @@
 // user data partition.
 const char kLacrosUserDataPath[] = "/home/chronos/user/lacros";
 
+// Release channel key in /etc/lsb-release.
+const char kChromeOSReleaseTrack[] = "CHROMEOS_RELEASE_TRACK";
+
+// Release channel values in /etc/lsb-release.
+const char kReleaseChannelCanary[] = "canary-channel";
+const char kReleaseChannelDev[] = "dev-channel";
+const char kReleaseChannelBeta[] = "beta-channel";
+const char kReleaseChannelStable[] = "stable-channel";
+
 }  // namespace crosapi
diff --git a/chromeos/crosapi/cpp/crosapi_constants.h b/chromeos/crosapi/cpp/crosapi_constants.h
index 16903d5..19009786 100644
--- a/chromeos/crosapi/cpp/crosapi_constants.h
+++ b/chromeos/crosapi/cpp/crosapi_constants.h
@@ -19,6 +19,13 @@
 
 COMPONENT_EXPORT(CROSAPI) extern const char kLacrosUserDataPath[];
 
+COMPONENT_EXPORT(CROSAPI) extern const char kChromeOSReleaseTrack[];
+
+COMPONENT_EXPORT(CROSAPI) extern const char kReleaseChannelCanary[];
+COMPONENT_EXPORT(CROSAPI) extern const char kReleaseChannelDev[];
+COMPONENT_EXPORT(CROSAPI) extern const char kReleaseChannelBeta[];
+COMPONENT_EXPORT(CROSAPI) extern const char kReleaseChannelStable[];
+
 }  // namespace crosapi
 
 #endif  // CHROMEOS_CROSAPI_CPP_CROSAPI_CONSTANTS_H_
diff --git a/chromeos/profiles/orderfile.newest.txt b/chromeos/profiles/orderfile.newest.txt
index 5f17584..4e9e9f8f 100644
--- a/chromeos/profiles/orderfile.newest.txt
+++ b/chromeos/profiles/orderfile.newest.txt
@@ -1 +1 @@
-chromeos-chrome-orderfile-field-88-4296.0-1603709458-benchmark-88.0.4303.0-r1.orderfile.xz
+chromeos-chrome-orderfile-field-88-4296.0-1603709458-benchmark-88.0.4304.0-r1.orderfile.xz
diff --git a/chromeos/services/ime/public/proto/BUILD.gn b/chromeos/services/ime/public/proto/BUILD.gn
index d21ff84..79bfe1f 100644
--- a/chromeos/services/ime/public/proto/BUILD.gn
+++ b/chromeos/services/ime/public/proto/BUILD.gn
@@ -6,4 +6,8 @@
 
 proto_library("messages_proto") {
   sources = [ "messages.proto" ]
+
+  # Chrome only allows lite runtime, but google3 side needs full for testing and
+  # fuzzing. Force lite runtime here.
+  cc_generator_options = "lite=true:"
 }
diff --git a/chromeos/services/ime/public/proto/messages.proto b/chromeos/services/ime/public/proto/messages.proto
index 9347c577..3da7f54d 100644
--- a/chromeos/services/ime/public/proto/messages.proto
+++ b/chromeos/services/ime/public/proto/messages.proto
@@ -8,8 +8,6 @@
 
 syntax = "proto2";
 
-option optimize_for = LITE_RUNTIME;
-
 package chromeos.ime;
 
 // The base message type for all communication between the IME service and the
diff --git a/components/arc/clipboard/arc_clipboard_bridge.cc b/components/arc/clipboard/arc_clipboard_bridge.cc
index 0e59cac8..b5d4d3f 100644
--- a/components/arc/clipboard/arc_clipboard_bridge.cc
+++ b/components/arc/clipboard/arc_clipboard_bridge.cc
@@ -17,8 +17,8 @@
 #include "ui/base/clipboard/clipboard.h"
 #include "ui/base/clipboard/clipboard_constants.h"
 #include "ui/base/clipboard/clipboard_monitor.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
 #include "ui/base/clipboard/scoped_clipboard_writer.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 
 namespace arc {
 namespace {
diff --git a/components/autofill_assistant/browser/controller.cc b/components/autofill_assistant/browser/controller.cc
index 904dc3f..3cd1918a 100644
--- a/components/autofill_assistant/browser/controller.cc
+++ b/components/autofill_assistant/browser/controller.cc
@@ -119,7 +119,7 @@
 Controller::Controller(content::WebContents* web_contents,
                        Client* client,
                        const base::TickClock* tick_clock,
-                       RuntimeManagerImpl* runtime_manager,
+                       base::WeakPtr<RuntimeManagerImpl> runtime_manager,
                        std::unique_ptr<Service> service)
     : content::WebContentsObserver(web_contents),
       client_(client),
@@ -416,7 +416,9 @@
 
 void Controller::SetUiShown(bool shown) {
   ui_shown_ = shown;
-  runtime_manager_->SetUIState(shown ? UIState::kShown : UIState::kNotShown);
+  if (runtime_manager_) {
+    runtime_manager_->SetUIState(shown ? UIState::kShown : UIState::kNotShown);
+  }
 }
 
 void Controller::SetGenericUi(
diff --git a/components/autofill_assistant/browser/controller.h b/components/autofill_assistant/browser/controller.h
index ebaf6d80..f56c76e 100644
--- a/components/autofill_assistant/browser/controller.h
+++ b/components/autofill_assistant/browser/controller.h
@@ -63,7 +63,7 @@
   Controller(content::WebContents* web_contents,
              Client* client,
              const base::TickClock* tick_clock,
-             RuntimeManagerImpl* runtime_manager,
+             base::WeakPtr<RuntimeManagerImpl> runtime_manager,
              std::unique_ptr<Service> service);
   ~Controller() override;
 
@@ -360,7 +360,7 @@
   ClientSettings settings_;
   Client* const client_;
   const base::TickClock* const tick_clock_;
-  RuntimeManagerImpl* const runtime_manager_;
+  base::WeakPtr<RuntimeManagerImpl> runtime_manager_;
 
   // Lazily instantiate in GetWebController().
   std::unique_ptr<WebController> web_controller_;
diff --git a/components/autofill_assistant/browser/controller_unittest.cc b/components/autofill_assistant/browser/controller_unittest.cc
index 5fdccd06..1cc269b9 100644
--- a/components/autofill_assistant/browser/controller_unittest.cc
+++ b/components/autofill_assistant/browser/controller_unittest.cc
@@ -105,9 +105,10 @@
     ON_CALL(mock_client_, GetWebContents).WillByDefault(Return(web_contents()));
     ON_CALL(mock_client_, HasHadUI()).WillByDefault(Return(true));
 
+    mock_runtime_manager_ = std::make_unique<MockRuntimeManager>();
     controller_ = std::make_unique<Controller>(
         web_contents(), &mock_client_, task_environment()->GetMockTickClock(),
-        &mock_runtime_manager_, std::move(service));
+        mock_runtime_manager_->GetWeakPtr(), std::move(service));
     controller_->SetWebControllerForTest(std::move(web_controller));
 
     ON_CALL(mock_client_, AttachUI()).WillByDefault(Invoke([this]() {
@@ -239,7 +240,7 @@
   MockService* mock_service_;
   MockWebController* mock_web_controller_;
   NiceMock<MockClient> mock_client_;
-  NiceMock<MockRuntimeManager> mock_runtime_manager_;
+  std::unique_ptr<MockRuntimeManager> mock_runtime_manager_;
   NiceMock<MockControllerObserver> mock_observer_;
   std::unique_ptr<Controller> controller_;
 };
@@ -2856,13 +2857,19 @@
 }
 
 TEST_F(ControllerTest, NotifyRuntimeManagerOnUiStateChange) {
-  EXPECT_CALL(mock_runtime_manager_, SetUIState(UIState::kShown)).Times(1);
+  EXPECT_CALL(*mock_runtime_manager_, SetUIState(UIState::kShown)).Times(1);
   controller_->SetUiShown(true);
 
-  EXPECT_CALL(mock_runtime_manager_, SetUIState(UIState::kNotShown)).Times(1);
+  EXPECT_CALL(*mock_runtime_manager_, SetUIState(UIState::kNotShown)).Times(1);
   controller_->SetUiShown(false);
 }
 
+TEST_F(ControllerTest, RuntimeManagerDestroyed) {
+  mock_runtime_manager_.reset();
+  // This method should not crash.
+  controller_->SetUiShown(true);
+}
+
 TEST_F(ControllerTest, OnGetScriptsFailedWillShutdown) {
   EXPECT_CALL(mock_observer_, OnStatusMessageChanged(l10n_util::GetStringFUTF8(
                                   IDS_AUTOFILL_ASSISTANT_LOADING,
diff --git a/components/autofill_assistant/browser/public/runtime_manager_impl.cc b/components/autofill_assistant/browser/public/runtime_manager_impl.cc
index 1cce94e1..81c02da 100644
--- a/components/autofill_assistant/browser/public/runtime_manager_impl.cc
+++ b/components/autofill_assistant/browser/public/runtime_manager_impl.cc
@@ -41,5 +41,9 @@
   }
 }
 
+base::WeakPtr<RuntimeManagerImpl> RuntimeManagerImpl::GetWeakPtr() {
+  return weak_ptr_factory_.GetWeakPtr();
+}
+
 WEB_CONTENTS_USER_DATA_KEY_IMPL(RuntimeManagerImpl)
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/public/runtime_manager_impl.h b/components/autofill_assistant/browser/public/runtime_manager_impl.h
index 374ad28..8980d30 100644
--- a/components/autofill_assistant/browser/public/runtime_manager_impl.h
+++ b/components/autofill_assistant/browser/public/runtime_manager_impl.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_PUBLIC_RUNTIME_MANAGER_IMPL_H_
 #define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_PUBLIC_RUNTIME_MANAGER_IMPL_H_
 
+#include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "components/autofill_assistant/browser/public/runtime_manager.h"
 #include "components/autofill_assistant/browser/public/runtime_observer.h"
@@ -23,6 +24,8 @@
   static RuntimeManagerImpl* GetForWebContents(content::WebContents* contents);
 
   ~RuntimeManagerImpl() override;
+  RuntimeManagerImpl(const RuntimeManagerImpl&) = delete;
+  RuntimeManagerImpl& operator=(const RuntimeManagerImpl&) = delete;
 
   // From RuntimeManager:
   void AddObserver(RuntimeObserver* observer) override;
@@ -31,6 +34,8 @@
 
   virtual void SetUIState(UIState state);
 
+  base::WeakPtr<RuntimeManagerImpl> GetWeakPtr();
+
  private:
   friend class content::WebContentsUserData<RuntimeManagerImpl>;
   friend class MockRuntimeManager;
@@ -43,6 +48,7 @@
 
   // Observers of Autofill Assistant's state.
   base::ObserverList<RuntimeObserver> observers_;
+  base::WeakPtrFactory<RuntimeManagerImpl> weak_ptr_factory_{this};
 
   WEB_CONTENTS_USER_DATA_KEY_DECL();
 };
diff --git a/components/bookmarks/browser/bookmark_utils.cc b/components/bookmarks/browser/bookmark_utils.cc
index b647ef4..deda4927 100644
--- a/components/bookmarks/browser/bookmark_utils.cc
+++ b/components/bookmarks/browser/bookmark_utils.cc
@@ -31,7 +31,7 @@
 #include "components/query_parser/query_parser.h"
 #include "components/url_formatter/url_formatter.h"
 #include "ui/base/clipboard/clipboard.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 #include "ui/base/models/tree_node_iterator.h"
 #include "url/gurl.h"
 
diff --git a/components/content_settings/core/browser/content_settings_policy_provider.cc b/components/content_settings/core/browser/content_settings_policy_provider.cc
index b74c280a..3784bf9 100644
--- a/components/content_settings/core/browser/content_settings_policy_provider.cc
+++ b/components/content_settings/core/browser/content_settings_policy_provider.cc
@@ -61,12 +61,6 @@
          ContentSettingsType::NOTIFICATIONS, CONTENT_SETTING_ALLOW},
         {prefs::kManagedNotificationsBlockedForUrls,
          ContentSettingsType::NOTIFICATIONS, CONTENT_SETTING_BLOCK},
-        {prefs::kManagedPluginsAllowedForUrls, ContentSettingsType::PLUGINS,
-         CONTENT_SETTING_ALLOW,
-         content_settings::WildcardsInPrimaryPattern::NOT_ALLOWED},
-        {prefs::kManagedPluginsBlockedForUrls, ContentSettingsType::PLUGINS,
-         CONTENT_SETTING_BLOCK,
-         content_settings::WildcardsInPrimaryPattern::NOT_ALLOWED},
         {prefs::kManagedPopupsAllowedForUrls, ContentSettingsType::POPUPS,
          CONTENT_SETTING_ALLOW},
         {prefs::kManagedPopupsBlockedForUrls, ContentSettingsType::POPUPS,
@@ -180,8 +174,6 @@
   registry->RegisterListPref(prefs::kManagedJavaScriptBlockedForUrls);
   registry->RegisterListPref(prefs::kManagedNotificationsAllowedForUrls);
   registry->RegisterListPref(prefs::kManagedNotificationsBlockedForUrls);
-  registry->RegisterListPref(prefs::kManagedPluginsAllowedForUrls);
-  registry->RegisterListPref(prefs::kManagedPluginsBlockedForUrls);
   registry->RegisterListPref(prefs::kManagedPopupsAllowedForUrls);
   registry->RegisterListPref(prefs::kManagedPopupsBlockedForUrls);
   registry->RegisterListPref(prefs::kManagedWebUsbAllowDevicesForUrls);
@@ -266,8 +258,6 @@
       prefs::kManagedNotificationsAllowedForUrls, callback);
   pref_change_registrar_.Add(
       prefs::kManagedNotificationsBlockedForUrls, callback);
-  pref_change_registrar_.Add(prefs::kManagedPluginsAllowedForUrls, callback);
-  pref_change_registrar_.Add(prefs::kManagedPluginsBlockedForUrls, callback);
   pref_change_registrar_.Add(prefs::kManagedPopupsAllowedForUrls, callback);
   pref_change_registrar_.Add(prefs::kManagedPopupsBlockedForUrls, callback);
   pref_change_registrar_.Add(prefs::kManagedWebUsbAskForUrls, callback);
@@ -613,8 +603,6 @@
       name == prefs::kManagedJavaScriptBlockedForUrls ||
       name == prefs::kManagedNotificationsAllowedForUrls ||
       name == prefs::kManagedNotificationsBlockedForUrls ||
-      name == prefs::kManagedPluginsAllowedForUrls ||
-      name == prefs::kManagedPluginsBlockedForUrls ||
       name == prefs::kManagedPopupsAllowedForUrls ||
       name == prefs::kManagedPopupsBlockedForUrls ||
       name == prefs::kManagedWebUsbAskForUrls ||
diff --git a/components/content_settings/core/common/pref_names.cc b/components/content_settings/core/common/pref_names.cc
index 614d27e..0a44132d 100644
--- a/components/content_settings/core/common/pref_names.cc
+++ b/components/content_settings/core/common/pref_names.cc
@@ -82,10 +82,6 @@
     "profile.managed_notifications_allowed_for_urls";
 const char kManagedNotificationsBlockedForUrls[] =
     "profile.managed_notifications_blocked_for_urls";
-const char kManagedPluginsAllowedForUrls[] =
-    "profile.managed_plugins_allowed_for_urls";
-const char kManagedPluginsBlockedForUrls[] =
-    "profile.managed_plugins_blocked_for_urls";
 const char kManagedPopupsAllowedForUrls[] =
     "profile.managed_popups_allowed_for_urls";
 const char kManagedPopupsBlockedForUrls[] =
diff --git a/components/content_settings/core/common/pref_names.h b/components/content_settings/core/common/pref_names.h
index afcbdad..5b16e3e4 100644
--- a/components/content_settings/core/common/pref_names.h
+++ b/components/content_settings/core/common/pref_names.h
@@ -45,8 +45,6 @@
 extern const char kManagedInsecureContentBlockedForUrls[];
 extern const char kManagedJavaScriptAllowedForUrls[];
 extern const char kManagedJavaScriptBlockedForUrls[];
-extern const char kManagedPluginsAllowedForUrls[];
-extern const char kManagedPluginsBlockedForUrls[];
 extern const char kManagedPopupsAllowedForUrls[];
 extern const char kManagedPopupsBlockedForUrls[];
 extern const char kManagedNotificationsAllowedForUrls[];
diff --git a/components/cronet/android/cronet_url_request_adapter.cc b/components/cronet/android/cronet_url_request_adapter.cc
index 447b5a16..baceb916 100644
--- a/components/cronet/android/cronet_url_request_adapter.cc
+++ b/components/cronet/android/cronet_url_request_adapter.cc
@@ -112,8 +112,7 @@
                                jtraffic_stats_tag_set == JNI_TRUE,
                                jtraffic_stats_tag,
                                jtraffic_stats_uid_set == JNI_TRUE,
-                               jtraffic_stats_uid,
-                               /*idempotency=*/net::DEFAULT_IDEMPOTENCY)) {
+                               jtraffic_stats_uid)) {
   owner_.Reset(env, jurl_request);
 }
 
diff --git a/components/cronet/cronet_url_request.cc b/components/cronet/cronet_url_request.cc
index 2f56be3c..b0476e53 100644
--- a/components/cronet/cronet_url_request.cc
+++ b/components/cronet/cronet_url_request.cc
@@ -13,7 +13,6 @@
 #include "base/logging.h"
 #include "build/build_config.h"
 #include "components/cronet/cronet_url_request_context.h"
-#include "net/base/idempotency.h"
 #include "net/base/load_flags.h"
 #include "net/base/load_states.h"
 #include "net/base/net_errors.h"
@@ -63,8 +62,7 @@
                                    bool traffic_stats_tag_set,
                                    int32_t traffic_stats_tag,
                                    bool traffic_stats_uid_set,
-                                   int32_t traffic_stats_uid,
-                                   net::Idempotency idempotency)
+                                   int32_t traffic_stats_uid)
     : context_(context),
       network_tasks_(std::move(callback),
                      url,
@@ -76,8 +74,7 @@
                      traffic_stats_tag_set,
                      traffic_stats_tag,
                      traffic_stats_uid_set,
-                     traffic_stats_uid,
-                     idempotency),
+                     traffic_stats_uid),
       initial_method_("GET"),
       initial_request_headers_(std::make_unique<net::HttpRequestHeaders>()) {
   DCHECK(!context_->IsOnNetworkThread());
@@ -177,8 +174,7 @@
                                              bool traffic_stats_tag_set,
                                              int32_t traffic_stats_tag,
                                              bool traffic_stats_uid_set,
-                                             int32_t traffic_stats_uid,
-                                             net::Idempotency idempotency)
+                                             int32_t traffic_stats_uid)
     : callback_(std::move(callback)),
       initial_url_(url),
       initial_priority_(priority),
@@ -190,8 +186,7 @@
       traffic_stats_tag_set_(traffic_stats_tag_set),
       traffic_stats_tag_(traffic_stats_tag),
       traffic_stats_uid_set_(traffic_stats_uid_set),
-      traffic_stats_uid_(traffic_stats_uid),
-      idempotency_(idempotency) {
+      traffic_stats_uid_(traffic_stats_uid) {
   DETACH_FROM_THREAD(network_thread_checker_);
 }
 
@@ -288,7 +283,6 @@
   url_request_->set_method(method);
   url_request_->SetExtraRequestHeaders(*request_headers);
   url_request_->SetPriority(initial_priority_);
-  url_request_->SetIdempotency(idempotency_);
   if (upload)
     url_request_->set_upload(std::move(upload));
   if (traffic_stats_tag_set_ || traffic_stats_uid_set_) {
diff --git a/components/cronet/cronet_url_request.h b/components/cronet/cronet_url_request.h
index 120a6dd9..9896d3e 100644
--- a/components/cronet/cronet_url_request.h
+++ b/components/cronet/cronet_url_request.h
@@ -13,7 +13,6 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/time/time.h"
-#include "net/base/idempotency.h"
 #include "net/base/request_priority.h"
 #include "net/url_request/url_request.h"
 #include "url/gurl.h"
@@ -150,8 +149,7 @@
                    bool traffic_stats_tag_set,
                    int32_t traffic_stats_tag,
                    bool traffic_stats_uid_set,
-                   int32_t traffic_stats_uid,
-                   net::Idempotency idempotency);
+                   int32_t traffic_stats_uid);
 
   // Methods called prior to Start are never called on network thread.
 
@@ -209,8 +207,7 @@
                  bool traffic_stats_tag_set,
                  int32_t traffic_stats_tag,
                  bool traffic_stats_uid_set,
-                 int32_t traffic_stats_uid,
-                 net::Idempotency idempotency);
+                 int32_t traffic_stats_uid);
 
     // Invoked on the network thread.
     ~NetworkTasks() override;
@@ -288,8 +285,6 @@
     const bool traffic_stats_uid_set_;
     // UID to be applied to URLRequest.
     const int32_t traffic_stats_uid_;
-    // Idempotency of the request.
-    const net::Idempotency idempotency_;
 
     scoped_refptr<net::IOBuffer> read_buffer_;
     std::unique_ptr<net::URLRequest> url_request_;
diff --git a/components/cronet/native/cronet.idl b/components/cronet/native/cronet.idl
index f72d885..8fc14fb3 100644
--- a/components/cronet/native/cronet.idl
+++ b/components/cronet/native/cronet.idl
@@ -1228,23 +1228,6 @@
    * start running in the future.
    */
   Executor? request_finished_executor;
-
-  enum IDEMPOTENCY {
-    DEFAULT_IDEMPOTENCY = 0,
-    IDEMPOTENT = 1,
-    NOT_IDEMPOTENT = 2,
-  };
-
- /**
-   * Idempotency of the request, which determines that if it is safe to enable
-   * 0-RTT for the Cronet request. By default, 0-RTT is only enabled for safe
-   * HTTP methods, i.e., GET, HEAD, OPTIONS, and TRACE. For other methods,
-   * enabling 0-RTT may cause security issues since a network observer can
-   * replay the request. If the request has any side effects, those effects can
-   * happen multiple times. It is only safe to enable the 0-RTT if it is known
-   * that the request is idempotent.
-   */
-  IDEMPOTENCY idempotency = DEFAULT_IDEMPOTENCY;
 };
 
 /**
diff --git a/components/cronet/native/generated/cronet.idl_c.h b/components/cronet/native/generated/cronet.idl_c.h
index 041fd8f58..80a9efe 100644
--- a/components/cronet/native/generated/cronet.idl_c.h
+++ b/components/cronet/native/generated/cronet.idl_c.h
@@ -132,12 +132,6 @@
   Cronet_UrlRequestParams_REQUEST_PRIORITY_REQUEST_PRIORITY_HIGHEST = 4,
 } Cronet_UrlRequestParams_REQUEST_PRIORITY;
 
-typedef enum Cronet_UrlRequestParams_IDEMPOTENCY {
-  Cronet_UrlRequestParams_IDEMPOTENCY_DEFAULT_IDEMPOTENCY = 0,
-  Cronet_UrlRequestParams_IDEMPOTENCY_IDEMPOTENT = 1,
-  Cronet_UrlRequestParams_IDEMPOTENCY_NOT_IDEMPOTENT = 2,
-} Cronet_UrlRequestParams_IDEMPOTENCY;
-
 typedef enum Cronet_RequestFinishedInfo_FINISHED_REASON {
   Cronet_RequestFinishedInfo_FINISHED_REASON_SUCCEEDED = 0,
   Cronet_RequestFinishedInfo_FINISHED_REASON_FAILED = 1,
@@ -1029,10 +1023,6 @@
 void Cronet_UrlRequestParams_request_finished_executor_set(
     Cronet_UrlRequestParamsPtr self,
     const Cronet_ExecutorPtr request_finished_executor);
-CRONET_EXPORT
-void Cronet_UrlRequestParams_idempotency_set(
-    Cronet_UrlRequestParamsPtr self,
-    const Cronet_UrlRequestParams_IDEMPOTENCY idempotency);
 // Cronet_UrlRequestParams getters.
 CRONET_EXPORT
 Cronet_String Cronet_UrlRequestParams_http_method_get(
@@ -1078,9 +1068,6 @@
 CRONET_EXPORT
 Cronet_ExecutorPtr Cronet_UrlRequestParams_request_finished_executor_get(
     const Cronet_UrlRequestParamsPtr self);
-CRONET_EXPORT
-Cronet_UrlRequestParams_IDEMPOTENCY Cronet_UrlRequestParams_idempotency_get(
-    const Cronet_UrlRequestParamsPtr self);
 
 ///////////////////////
 // Struct Cronet_DateTime.
diff --git a/components/cronet/native/generated/cronet.idl_impl_struct.cc b/components/cronet/native/generated/cronet.idl_impl_struct.cc
index e7d6ebd31..7288afc 100644
--- a/components/cronet/native/generated/cronet.idl_impl_struct.cc
+++ b/components/cronet/native/generated/cronet.idl_impl_struct.cc
@@ -715,13 +715,6 @@
   self->request_finished_executor = request_finished_executor;
 }
 
-void Cronet_UrlRequestParams_idempotency_set(
-    Cronet_UrlRequestParamsPtr self,
-    const Cronet_UrlRequestParams_IDEMPOTENCY idempotency) {
-  DCHECK(self);
-  self->idempotency = idempotency;
-}
-
 // Struct Cronet_UrlRequestParams getters.
 Cronet_String Cronet_UrlRequestParams_http_method_get(
     const Cronet_UrlRequestParamsPtr self) {
@@ -808,12 +801,6 @@
   return self->request_finished_executor;
 }
 
-Cronet_UrlRequestParams_IDEMPOTENCY Cronet_UrlRequestParams_idempotency_get(
-    const Cronet_UrlRequestParamsPtr self) {
-  DCHECK(self);
-  return self->idempotency;
-}
-
 // Struct Cronet_DateTime.
 Cronet_DateTime::Cronet_DateTime() = default;
 
diff --git a/components/cronet/native/generated/cronet.idl_impl_struct.h b/components/cronet/native/generated/cronet.idl_impl_struct.h
index 06a7dec7..6a10c1ab 100644
--- a/components/cronet/native/generated/cronet.idl_impl_struct.h
+++ b/components/cronet/native/generated/cronet.idl_impl_struct.h
@@ -151,8 +151,6 @@
   std::vector<Cronet_RawDataPtr> annotations;
   Cronet_RequestFinishedInfoListenerPtr request_finished_listener = nullptr;
   Cronet_ExecutorPtr request_finished_executor = nullptr;
-  Cronet_UrlRequestParams_IDEMPOTENCY idempotency =
-      Cronet_UrlRequestParams_IDEMPOTENCY_DEFAULT_IDEMPOTENCY;
 
  private:
   DISALLOW_ASSIGN(Cronet_UrlRequestParams);
diff --git a/components/cronet/native/generated/cronet.idl_impl_struct_unittest.cc b/components/cronet/native/generated/cronet.idl_impl_struct_unittest.cc
index d048bc6..3091405 100644
--- a/components/cronet/native/generated/cronet.idl_impl_struct_unittest.cc
+++ b/components/cronet/native/generated/cronet.idl_impl_struct_unittest.cc
@@ -256,10 +256,6 @@
       second, Cronet_UrlRequestParams_request_finished_executor_get(first));
   EXPECT_EQ(Cronet_UrlRequestParams_request_finished_executor_get(first),
             Cronet_UrlRequestParams_request_finished_executor_get(second));
-  Cronet_UrlRequestParams_idempotency_set(
-      second, Cronet_UrlRequestParams_idempotency_get(first));
-  EXPECT_EQ(Cronet_UrlRequestParams_idempotency_get(first),
-            Cronet_UrlRequestParams_idempotency_get(second));
   Cronet_UrlRequestParams_Destroy(first);
   Cronet_UrlRequestParams_Destroy(second);
 }
diff --git a/components/cronet/native/url_request.cc b/components/cronet/native/url_request.cc
index d440c024..95e6270 100644
--- a/components/cronet/native/url_request.cc
+++ b/components/cronet/native/url_request.cc
@@ -52,19 +52,6 @@
   return net::DEFAULT_PRIORITY;
 }
 
-net::Idempotency ConvertIdempotency(
-    Cronet_UrlRequestParams_IDEMPOTENCY idempotency) {
-  switch (idempotency) {
-    case Cronet_UrlRequestParams_IDEMPOTENCY_DEFAULT_IDEMPOTENCY:
-      return net::DEFAULT_IDEMPOTENCY;
-    case Cronet_UrlRequestParams_IDEMPOTENCY_IDEMPOTENT:
-      return net::IDEMPOTENT;
-    case Cronet_UrlRequestParams_IDEMPOTENCY_NOT_IDEMPOTENT:
-      return net::NOT_IDEMPOTENT;
-  }
-  return net::DEFAULT_IDEMPOTENCY;
-}
-
 scoped_refptr<UrlResponseInfo> CreateCronet_UrlResponseInfo(
     const std::vector<std::string>& url_chain,
     int http_status_code,
@@ -376,8 +363,7 @@
           engine_->HasRequestFinishedListener() /* params->enableMetrics */,
       // TODO(pauljensen): Consider exposing TrafficStats API via C++ API.
       false /* traffic_stats_tag_set */, 0 /* traffic_stats_tag */,
-      false /* traffic_stats_uid_set */, 0 /* traffic_stats_uid */,
-      ConvertIdempotency(params->idempotency));
+      false /* traffic_stats_uid_set */, 0 /* traffic_stats_uid */);
 
   if (params->upload_data_provider) {
     upload_data_sink_ = std::make_unique<Cronet_UploadDataSinkImpl>(
diff --git a/components/exo/client_controlled_shell_surface.cc b/components/exo/client_controlled_shell_surface.cc
index 494ce6b..8c4e29d 100644
--- a/components/exo/client_controlled_shell_surface.cc
+++ b/components/exo/client_controlled_shell_surface.cc
@@ -591,8 +591,10 @@
   TRACE_EVENT1("exo", "ClientControlledShellSurface::SetExtraTitle",
                "extra_title", base::UTF16ToUTF8(extra_title));
 
-  if (!widget_)
+  if (!widget_) {
+    initial_extra_title_ = extra_title;
     return;
+  }
 
   GetFrameView()->GetHeaderView()->GetFrameHeader()->SetFrameTextOverride(
       extra_title);
@@ -1046,6 +1048,8 @@
   UpdateFrameWidth();
   if (initial_orientation_lock_ != ash::OrientationLockType::kAny)
     SetOrientationLock(initial_orientation_lock_);
+  if (initial_extra_title_ != base::string16())
+    SetExtraTitle(initial_extra_title_);
 
   // Register Client controlled accelerators.
   views::FocusManager* focus_manager = widget_->GetFocusManager();
diff --git a/components/exo/client_controlled_shell_surface.h b/components/exo/client_controlled_shell_surface.h
index 5141d59..f90f550 100644
--- a/components/exo/client_controlled_shell_surface.h
+++ b/components/exo/client_controlled_shell_surface.h
@@ -367,6 +367,8 @@
   // widget is not created yet orientation lock is being set.
   ash::OrientationLockType initial_orientation_lock_ =
       ash::OrientationLockType::kAny;
+  // The extra title to be applied when widget is being created.
+  base::string16 initial_extra_title_ = base::string16();
 
   bool preserve_widget_bounds_ = false;
 
diff --git a/components/exo/data_offer.cc b/components/exo/data_offer.cc
index bfcc853..bc9999e 100644
--- a/components/exo/data_offer.cc
+++ b/components/exo/data_offer.cc
@@ -26,7 +26,7 @@
 #include "ui/base/clipboard/clipboard.h"
 #include "ui/base/clipboard/clipboard_buffer.h"
 #include "ui/base/clipboard/clipboard_constants.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 #include "ui/base/dragdrop/file_info/file_info.h"
 #include "ui/base/dragdrop/os_exchange_data.h"
 #include "url/gurl.h"
diff --git a/components/exo/seat.cc b/components/exo/seat.cc
index b9c07852..1d13db1d 100644
--- a/components/exo/seat.cc
+++ b/components/exo/seat.cc
@@ -29,8 +29,8 @@
 #include "services/data_decoder/public/cpp/decode_image.h"
 #include "ui/aura/client/focus_client.h"
 #include "ui/base/clipboard/clipboard_monitor.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
 #include "ui/base/clipboard/scoped_clipboard_writer.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 #include "ui/events/event_utils.h"
 #include "ui/events/platform/platform_event_source.h"
 
diff --git a/components/feed/core/v2/feed_stream_unittest.cc b/components/feed/core/v2/feed_stream_unittest.cc
index 89e006b8..ffbb96cc 100644
--- a/components/feed/core/v2/feed_stream_unittest.cc
+++ b/components/feed/core/v2/feed_stream_unittest.cc
@@ -1447,10 +1447,6 @@
   histograms.ExpectUniqueSample(
       "ContentSuggestions.Feed.ActivityLoggingEnabled", 1, 1);
 
-  // The response has a privacy_notice_fulfilled=true.
-  histograms.ExpectUniqueSample("ContentSuggestions.Feed.NoticeCardFulfilled",
-                                1, 1);
-
   // A request schedule with two entries was in the response. The first entry
   // should have already been scheduled/consumed, leaving only the second
   // entry still in the the refresh_offsets vector.
@@ -1779,6 +1775,40 @@
   ASSERT_TRUE(stream_->CanUploadActions());
 }
 
+TEST_F(FeedStreamTest, LoadStreamUpdateNoticeCardFulfillmentHistogram) {
+  base::HistogramTester histograms;
+
+  // Trigger a stream refresh that updates the histogram.
+  {
+    auto model_state = MakeTypicalInitialModelState();
+    model_state->stream_data.set_privacy_notice_fulfilled(false);
+    response_translator_.InjectResponse(std::move(model_state));
+
+    refresh_scheduler_.Clear();
+    stream_->ExecuteRefreshTask();
+    WaitForIdleTaskQueue();
+  }
+
+  UnloadModel();
+
+  // Trigger another stream refresh that updates the histogram.
+  {
+    auto model_state = MakeTypicalInitialModelState();
+    model_state->stream_data.set_privacy_notice_fulfilled(true);
+    response_translator_.InjectResponse(std::move(model_state));
+
+    refresh_scheduler_.Clear();
+    stream_->ExecuteRefreshTask();
+    WaitForIdleTaskQueue();
+  }
+
+  // Verify that the notice card fulfillment histogram was properly recorded.
+  histograms.ExpectBucketCount("ContentSuggestions.Feed.NoticeCardFulfilled2",
+                               0, 1);
+  histograms.ExpectBucketCount("ContentSuggestions.Feed.NoticeCardFulfilled2",
+                               1, 1);
+}
+
 TEST_F(FeedStreamTest, LoadStreamFromNetworkUploadsActions) {
   stream_->UploadAction(MakeFeedAction(99ul), false, base::DoNothing());
   WaitForIdleTaskQueue();
@@ -1870,7 +1900,7 @@
 }
 
 TEST_F(FeedStreamConditionalActionsUploadTest,
-       LoadMoreDoesntUpdateNoticeCardPref) {
+       LoadMoreDoesntUpdateNoticeCardPrefAndHistogram) {
   // The initial stream load has the notice card.
   response_translator_.InjectResponse(MakeTypicalInitialModelState());
   TestSurface surface(stream_.get());
@@ -1884,6 +1914,11 @@
       /* signed_in= */ true,
       /* logging_enabled= */ true,
       /* privacy_notice_fulfilled= */ false));
+
+  // Start tracking histograms after the initial stream load to isolate the
+  // effect of load more.
+  base::HistogramTester histograms;
+
   stream_->LoadMore(surface.GetSurfaceId(), base::DoNothing());
   WaitForIdleTaskQueue();
 
@@ -1898,6 +1933,11 @@
 
   // Verify that there were no uploads.
   EXPECT_EQ(0, network_.action_request_call_count);
+
+  // Verify that the notice card fulfillment histogram isn't recorded for load
+  // more.
+  histograms.ExpectTotalCount("ContentSuggestions.Feed.NoticeCardFulfilled2",
+                              0);
 }
 
 TEST_F(FeedStreamTest, BackgroundingAppUploadsActions) {
diff --git a/components/feed/core/v2/metrics_reporter.cc b/components/feed/core/v2/metrics_reporter.cc
index d477c58..d23a99f1 100644
--- a/components/feed/core/v2/metrics_reporter.cc
+++ b/components/feed/core/v2/metrics_reporter.cc
@@ -476,6 +476,12 @@
 }
 
 void MetricsReporter::NoticeCardFulfilled(bool response_has_notice_card) {
+  base::UmaHistogramBoolean("ContentSuggestions.Feed.NoticeCardFulfilled2",
+                            response_has_notice_card);
+}
+
+void MetricsReporter::NoticeCardFulfilledObsolete(
+    bool response_has_notice_card) {
   base::UmaHistogramBoolean("ContentSuggestions.Feed.NoticeCardFulfilled",
                             response_has_notice_card);
 }
diff --git a/components/feed/core/v2/metrics_reporter.h b/components/feed/core/v2/metrics_reporter.h
index f13347f..3148945 100644
--- a/components/feed/core/v2/metrics_reporter.h
+++ b/components/feed/core/v2/metrics_reporter.h
@@ -125,6 +125,7 @@
 
   static void ActivityLoggingEnabled(bool response_has_logging_enabled);
   static void NoticeCardFulfilled(bool response_has_notice_card);
+  static void NoticeCardFulfilledObsolete(bool response_has_notice_card);
 
  private:
   base::WeakPtr<MetricsReporter> GetWeakPtr() {
diff --git a/components/feed/core/v2/protocol_translator.cc b/components/feed/core/v2/protocol_translator.cc
index 6b2d800..db12874 100644
--- a/components/feed/core/v2/protocol_translator.cc
+++ b/components/feed/core/v2/protocol_translator.cc
@@ -307,7 +307,7 @@
       response_metadata.privacy_notice_fulfilled());
 
   MetricsReporter::ActivityLoggingEnabled(response_metadata.logging_enabled());
-  MetricsReporter::NoticeCardFulfilled(
+  MetricsReporter::NoticeCardFulfilledObsolete(
       response_metadata.privacy_notice_fulfilled());
 
   RefreshResponseData response_data;
diff --git a/components/feed/core/v2/tasks/load_stream_task.cc b/components/feed/core/v2/tasks/load_stream_task.cc
index 14d75666..c061f9d 100644
--- a/components/feed/core/v2/tasks/load_stream_task.cc
+++ b/components/feed/core/v2/tasks/load_stream_task.cc
@@ -167,9 +167,10 @@
           *response_data.model_update_request),
       base::DoNothing());
 
-  stream_->SetLastStreamLoadHadNoticeCard(
-      response_data.model_update_request->stream_data
-          .privacy_notice_fulfilled());
+  bool isNoticeCardFulfilled = response_data.model_update_request->stream_data
+                                   .privacy_notice_fulfilled();
+  stream_->SetLastStreamLoadHadNoticeCard(isNoticeCardFulfilled);
+  MetricsReporter::NoticeCardFulfilled(isNoticeCardFulfilled);
 
   if (load_type_ != LoadType::kBackgroundRefresh) {
     auto model = std::make_unique<StreamModel>();
diff --git a/components/gwp_asan/client/sampling_partitionalloc_shims_unittest.cc b/components/gwp_asan/client/sampling_partitionalloc_shims_unittest.cc
index 9b89505d..ff52cd1 100644
--- a/components/gwp_asan/client/sampling_partitionalloc_shims_unittest.cc
+++ b/components/gwp_asan/client/sampling_partitionalloc_shims_unittest.cc
@@ -11,6 +11,7 @@
 #include <string>
 
 #include "base/allocator/partition_allocator/partition_alloc.h"
+#include "base/allocator/partition_allocator/partition_root.h"
 #include "base/bind_helpers.h"
 #include "base/logging.h"
 #include "base/partition_alloc_buildflags.h"
@@ -51,6 +52,11 @@
 constexpr int kSuccess = 0;
 constexpr int kFailure = 1;
 
+constexpr base::PartitionOptions kAllocatorOptions = {
+    base::PartitionOptions::Alignment::kRegular,
+    base::PartitionOptions::ThreadCache::kDisabled,
+    base::PartitionOptions::PCScan::kAlwaysDisabled};
+
 static void HandleOOM(size_t unused_size) {
   LOG(FATAL) << "Out of memory.";
 }
@@ -79,7 +85,7 @@
     BasicFunctionality,
     SamplingPartitionAllocShimsTest::multiprocessTestSetup) {
   base::PartitionAllocator allocator;
-  allocator.init();
+  allocator.init(kAllocatorOptions);
   for (size_t i = 0; i < kLoopIterations; i++) {
     void* ptr = allocator.root()->Alloc(1, kFakeType);
     if (GetPartitionAllocGpaForTesting().PointerIsMine(ptr))
@@ -99,7 +105,7 @@
     Realloc,
     SamplingPartitionAllocShimsTest::multiprocessTestSetup) {
   base::PartitionAllocator allocator;
-  allocator.init();
+  allocator.init(kAllocatorOptions);
 
   void* alloc = GetPartitionAllocGpaForTesting().Allocate(base::GetPageSize());
   CHECK_NE(alloc, nullptr);
@@ -128,7 +134,7 @@
     DifferentTypesDontOverlap,
     SamplingPartitionAllocShimsTest::multiprocessTestSetup) {
   base::PartitionAllocator allocator;
-  allocator.init();
+  allocator.init(kAllocatorOptions);
 
   std::set<void*> type1, type2;
   for (size_t i = 0; i < kLoopIterations * AllocatorState::kMaxSlots; i++) {
diff --git a/components/heap_profiling/multi_process/test_driver.cc b/components/heap_profiling/multi_process/test_driver.cc
index fb67ecb..6eaf09d 100644
--- a/components/heap_profiling/multi_process/test_driver.cc
+++ b/components/heap_profiling/multi_process/test_driver.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 #include <string>
 
+#include "base/allocator/partition_allocator/partition_root.h"
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
@@ -342,7 +343,9 @@
     : wait_for_ui_thread_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
                           base::WaitableEvent::InitialState::NOT_SIGNALED) {
   base::PartitionAllocGlobalInit(HandleOOM);
-  partition_allocator_.init();
+  partition_allocator_.init({base::PartitionOptions::Alignment::kRegular,
+                             base::PartitionOptions::ThreadCache::kDisabled,
+                             base::PartitionOptions::PCScan::kAlwaysDisabled});
 }
 TestDriver::~TestDriver() {
   base::PartitionAllocGlobalUninitForTesting();
diff --git a/components/omnibox/browser/in_memory_url_index.cc b/components/omnibox/browser/in_memory_url_index.cc
index 5519395..bb93f5c 100644
--- a/components/omnibox/browser/in_memory_url_index.cc
+++ b/components/omnibox/browser/in_memory_url_index.cc
@@ -250,6 +250,10 @@
   auto* dump = process_memory_dump->CreateAllocatorDump(dump_name);
   dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
                   base::trace_event::MemoryAllocatorDump::kUnitsBytes, res);
+
+  // TODO(https://crbug.com/1068883): Remove this code when the bug is fixed.
+  private_data_->OnMemoryAllocatorDump(dump);
+
   return true;
 }
 
diff --git a/components/omnibox/browser/url_index_private_data.cc b/components/omnibox/browser/url_index_private_data.cc
index 33307a8..46e6f69 100644
--- a/components/omnibox/browser/url_index_private_data.cc
+++ b/components/omnibox/browser/url_index_private_data.cc
@@ -24,6 +24,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
+#include "base/trace_event/memory_allocator_dump.h"
 #include "base/trace_event/memory_usage_estimator.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/browser/bookmark_utils.h"
@@ -523,6 +524,75 @@
   return res;
 }
 
+// TODO(https://crbug.com/1068883): Remove this code when the bug is fixed.
+// This code should be deprecated and removed before M90. This method is not
+// merged with EstimateMemoryUsage(...) since it is intended to be removed.
+void URLIndexPrivateData::OnMemoryAllocatorDump(
+    base::trace_event::MemoryAllocatorDump* dump) const {
+  dump->AddScalar("search_term_cache",
+                  base::trace_event::MemoryAllocatorDump::kUnitsObjects,
+                  search_term_cache_.size());
+  dump->AddScalar("search_term_cache",
+                  base::trace_event::MemoryAllocatorDump::kUnitsBytes,
+                  base::trace_event::EstimateMemoryUsage(search_term_cache_));
+
+  dump->AddScalar("word_list",
+                  base::trace_event::MemoryAllocatorDump::kUnitsObjects,
+                  word_list_.size());
+  dump->AddScalar("word_list",
+                  base::trace_event::MemoryAllocatorDump::kUnitsBytes,
+                  base::trace_event::EstimateMemoryUsage(word_list_));
+
+  dump->AddScalar("available_words",
+                  base::trace_event::MemoryAllocatorDump::kUnitsObjects,
+                  available_words_.size());
+  dump->AddScalar("available_words",
+                  base::trace_event::MemoryAllocatorDump::kUnitsBytes,
+                  base::trace_event::EstimateMemoryUsage(available_words_));
+
+  dump->AddScalar("word_map",
+                  base::trace_event::MemoryAllocatorDump::kUnitsObjects,
+                  word_map_.size());
+  dump->AddScalar("word_map",
+                  base::trace_event::MemoryAllocatorDump::kUnitsBytes,
+                  base::trace_event::EstimateMemoryUsage(word_map_));
+
+  dump->AddScalar("char_word_map",
+                  base::trace_event::MemoryAllocatorDump::kUnitsObjects,
+                  char_word_map_.size());
+  dump->AddScalar("char_word_map",
+                  base::trace_event::MemoryAllocatorDump::kUnitsBytes,
+                  base::trace_event::EstimateMemoryUsage(char_word_map_));
+
+  dump->AddScalar("word_id_history_map",
+                  base::trace_event::MemoryAllocatorDump::kUnitsObjects,
+                  word_id_history_map_.size());
+  dump->AddScalar("word_id_history_map",
+                  base::trace_event::MemoryAllocatorDump::kUnitsBytes,
+                  base::trace_event::EstimateMemoryUsage(word_id_history_map_));
+
+  dump->AddScalar("history_id_word_map",
+                  base::trace_event::MemoryAllocatorDump::kUnitsObjects,
+                  history_id_word_map_.size());
+  dump->AddScalar("history_id_word_map",
+                  base::trace_event::MemoryAllocatorDump::kUnitsBytes,
+                  base::trace_event::EstimateMemoryUsage(history_id_word_map_));
+
+  dump->AddScalar("history_info_map",
+                  base::trace_event::MemoryAllocatorDump::kUnitsObjects,
+                  history_info_map_.size());
+  dump->AddScalar("history_info_map",
+                  base::trace_event::MemoryAllocatorDump::kUnitsBytes,
+                  base::trace_event::EstimateMemoryUsage(history_info_map_));
+
+  dump->AddScalar("word_starts_map",
+                  base::trace_event::MemoryAllocatorDump::kUnitsObjects,
+                  word_starts_map_.size());
+  dump->AddScalar("word_starts_map",
+                  base::trace_event::MemoryAllocatorDump::kUnitsBytes,
+                  base::trace_event::EstimateMemoryUsage(word_starts_map_));
+}
+
 bool URLIndexPrivateData::IsUrlRowIndexed(const history::URLRow& row) const {
   return history_info_map_.count(row.id()) > 0;
 }
diff --git a/components/omnibox/browser/url_index_private_data.h b/components/omnibox/browser/url_index_private_data.h
index 95f73ec..e5ca7453 100644
--- a/components/omnibox/browser/url_index_private_data.h
+++ b/components/omnibox/browser/url_index_private_data.h
@@ -36,6 +36,12 @@
 class InMemoryURLIndex;
 }
 
+namespace base {
+namespace trace_event {
+class MemoryAllocatorDump;
+}
+}  // namespace base
+
 // Current version of the cache file.
 static const int kCurrentCacheFileVersion = 5;
 
@@ -145,6 +151,8 @@
   // Estimates dynamic memory usage.
   // See base/trace_event/memory_usage_estimator.h for more info.
   size_t EstimateMemoryUsage() const;
+  void OnMemoryAllocatorDump(
+      base::trace_event::MemoryAllocatorDump* dump) const;
 
   // Returns true if |row| is indexed.
   bool IsUrlRowIndexed(const history::URLRow& row) const;
diff --git a/components/open_from_clipboard/DEPS b/components/open_from_clipboard/DEPS
index 8f338be..9ce97fe 100644
--- a/components/open_from_clipboard/DEPS
+++ b/components/open_from_clipboard/DEPS
@@ -3,6 +3,7 @@
   "+net",
   "+third_party/skia",
   "+ui/base/clipboard",
+  "+ui/base/data_transfer_policy",
   "+ui/base/test",
   "+ui/gfx/image",
 ]
diff --git a/components/open_from_clipboard/clipboard_recent_content_generic.cc b/components/open_from_clipboard/clipboard_recent_content_generic.cc
index a3fe25f..b729d63 100644
--- a/components/open_from_clipboard/clipboard_recent_content_generic.cc
+++ b/components/open_from_clipboard/clipboard_recent_content_generic.cc
@@ -10,7 +10,7 @@
 #include "base/strings/string_util.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/clipboard/clipboard.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 
 namespace {
 // Schemes appropriate for suggestion by ClipboardRecentContent.
diff --git a/components/performance_manager/execution_context/execution_context_impl.cc b/components/performance_manager/execution_context/execution_context_impl.cc
index a95cf40..b3a6321c 100644
--- a/components/performance_manager/execution_context/execution_context_impl.cc
+++ b/components/performance_manager/execution_context/execution_context_impl.cc
@@ -77,15 +77,11 @@
 
   const FrameNode* GetFrameNode() const override {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-    if (std::is_same<FrameNodeImpl, NodeImplType>::value)
-      return reinterpret_cast<const FrameNode*>(node_);
     return nullptr;
   }
 
   const WorkerNode* GetWorkerNode() const override {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-    if (std::is_same<WorkerNodeImpl, NodeImplType>::value)
-      return reinterpret_cast<const WorkerNodeImpl*>(node_);
     return nullptr;
   }
 
@@ -120,6 +116,11 @@
     return blink::ExecutionContextToken(node_->frame_token());
   }
 
+  const FrameNode* GetFrameNode() const override {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    return node_;
+  }
+
  protected:
   friend class NodeAttachedDataImpl<FrameExecutionContext>;
   explicit FrameExecutionContext(const FrameNodeImpl* frame_node)
@@ -143,6 +144,11 @@
     return ToExecutionContextToken(node_->worker_token());
   }
 
+  const WorkerNode* GetWorkerNode() const override {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    return node_;
+  }
+
  protected:
   friend class NodeAttachedDataImpl<WorkerExecutionContext>;
   explicit WorkerExecutionContext(const WorkerNodeImpl* worker_node)
diff --git a/components/performance_manager/execution_context_priority/max_vote_aggregator.cc b/components/performance_manager/execution_context_priority/max_vote_aggregator.cc
index 51c80bb..55408e2 100644
--- a/components/performance_manager/execution_context_priority/max_vote_aggregator.cc
+++ b/components/performance_manager/execution_context_priority/max_vote_aggregator.cc
@@ -10,6 +10,14 @@
 namespace performance_manager {
 namespace execution_context_priority {
 
+// static
+MaxVoteAggregator::StampedVote*
+MaxVoteAggregator::StampedVote::FromAcceptedVote(AcceptedVote* accepted_vote) {
+  static_assert(offsetof(StampedVote, vote) == 0,
+                "AcceptedVote is expected to be at offset 0 of StampedVote");
+  return reinterpret_cast<StampedVote*>(accepted_vote);
+}
+
 MaxVoteAggregator::MaxVoteAggregator() : factory_(this) {}
 
 MaxVoteAggregator::~MaxVoteAggregator() = default;
@@ -138,9 +146,7 @@
 }
 
 size_t MaxVoteAggregator::VoteData::GetVoteIndex(AcceptedVote* vote) {
-  static_assert(offsetof(StampedVote, vote) == 0,
-                "AcceptedVote is expected to be at offset 0 of StampedVote");
-  StampedVote* stamped_vote = reinterpret_cast<StampedVote*>(vote);
+  StampedVote* stamped_vote = StampedVote::FromAcceptedVote(vote);
   DCHECK_NE(0u, votes_.size());
   DCHECK_LE(votes_.data(), stamped_vote);
   DCHECK_LT(stamped_vote, votes_.data() + votes_.size());
diff --git a/components/performance_manager/execution_context_priority/max_vote_aggregator_unittest.cc b/components/performance_manager/execution_context_priority/max_vote_aggregator_unittest.cc
index d217d93d..18b9d16d 100644
--- a/components/performance_manager/execution_context_priority/max_vote_aggregator_unittest.cc
+++ b/components/performance_manager/execution_context_priority/max_vote_aggregator_unittest.cc
@@ -15,8 +15,10 @@
 class MaxVoteAggregatorTestAccess {
  public:
   using VoteData = MaxVoteAggregator::VoteData;
+  using StampedVote = MaxVoteAggregator::StampedVote;
 };
 using VoteData = MaxVoteAggregatorTestAccess::VoteData;
+using StampedVote = MaxVoteAggregatorTestAccess::StampedVote;
 
 namespace {
 
@@ -76,6 +78,12 @@
 
 }  // namespace
 
+TEST(MaxVoteAggregatorTest, StampedVoteCast) {
+  StampedVote stamped_vote;
+
+  EXPECT_EQ(&stamped_vote, StampedVote::FromAcceptedVote(&stamped_vote.vote));
+}
+
 TEST(MaxVoteAggregatorTest, VoteDataHeapStressTest) {
   // Build a simple consumer/voter chain so that we generate an actual VoterId.
   FakeVoteConsumer consumer;
diff --git a/components/performance_manager/public/execution_context_priority/max_vote_aggregator.h b/components/performance_manager/public/execution_context_priority/max_vote_aggregator.h
index 6b1cbc7..8c09522 100644
--- a/components/performance_manager/public/execution_context_priority/max_vote_aggregator.h
+++ b/components/performance_manager/public/execution_context_priority/max_vote_aggregator.h
@@ -61,6 +61,10 @@
       return vote_id > rhs.vote_id;
     }
 
+    // Given an AcceptedVote that's embedded in a StampedVote::vote, retrieve
+    // the embedding StampedVote instance.
+    static StampedVote* FromAcceptedVote(AcceptedVote* accepted_vote);
+
     // IntrusiveHeap contract. We actually don't need HeapHandles, as we already
     // know the positions of the elements in the heap directly, as they are
     // tracked with explicit back pointers.
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index ca39a1b2..522f7bf 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -4691,6 +4691,10 @@
               'blocked_install_message': {
                 'type': 'string',
                 'description': '''text that will be displayed to the user in the chrome webstore if installation is blocked.''',
+              },
+              'toolbar_pin': {
+                'type': 'string',
+                'enum': ['force_pinned', 'default_unpinned'],
               }
             },
           },
@@ -4751,6 +4755,7 @@
           'installation_mode': 'allowed',
           'blocked_permissions': ['history'],
           'minimum_version_required': '1.0.1',
+          'toolbar_pin': 'force_pinned',
         },
         'bcdefghijklmnopabcdefghijklmnopa' : {
           'installation_mode': 'force_installed',
@@ -6711,7 +6716,7 @@
         'type': 'array',
         'items': { 'type': 'string' },
       },
-      'supported_on': ['chrome.*:11-', 'chrome_os:11-'],
+      'supported_on': ['chrome.*:11-87', 'chrome_os:11-87'],
       'features': {
         'dynamic_refresh': True,
         'per_profile': True,
@@ -6720,7 +6725,8 @@
       'id': 73,
       'caption': '''Allow the <ph name="FLASH_PLUGIN_NAME">Flash</ph> plugin on these sites''',
       'tags': [],
-      'desc': '''Setting the policy lets you set a list of URL patterns that specify the sites that can run the <ph name="FLASH_PLUGIN_NAME">Flash</ph> plugin.
+      'deprecated': True,
+      'desc': '''This policy is deprecated in M88, Flash is no longer supported by Chrome. Setting the policy lets you set a list of URL patterns that specify the sites that can run the <ph name="FLASH_PLUGIN_NAME">Flash</ph> plugin.
 
       Leaving the policy unset means <ph name="DEFAULT_PLUGINS_SETTING_POLICY_NAME">DefaultPluginsSetting</ph> applies for all sites, if it's set. If not, the user's personal setting applies.
 
@@ -6734,7 +6740,7 @@
         'type': 'array',
         'items': { 'type': 'string' },
       },
-      'supported_on': ['chrome.*:11-', 'chrome_os:11-'],
+      'supported_on': ['chrome.*:11-87', 'chrome_os:11-87'],
       'features': {
         'dynamic_refresh': True,
         'per_profile': True,
@@ -6743,7 +6749,8 @@
       'id': 74,
       'caption': '''Block the <ph name="FLASH_PLUGIN_NAME">Flash</ph> plugin on these sites''',
       'tags': [],
-      'desc': '''Setting the policy lets you set a list of URL patterns that specify the sites that can't run the <ph name="FLASH_PLUGIN_NAME">Flash</ph> plugin.
+      'deprecated': True,
+      'desc': '''This policy is deprecated in M88, Flash is no longer supported by Chrome. Setting the policy lets you set a list of URL patterns that specify the sites that can't run the <ph name="FLASH_PLUGIN_NAME">Flash</ph> plugin.
 
       Leaving the policy unset means <ph name="DEFAULT_PLUGINS_SETTING_POLICY_NAME">DefaultPluginsSetting</ph> applies for all sites, if it's set. If not, the user's personal setting applies.
 
@@ -7516,7 +7523,7 @@
       'owners': ['file://components/policy/resources/OWNERS'],
       'type': 'main',
       'schema': { 'type': 'boolean' },
-      'supported_on': ['chrome.*:12-', 'chrome_os:12-'],
+      'supported_on': ['chrome.*:12-87', 'chrome_os:12-87'],
       'features': {
         'dynamic_refresh': True,
         'per_profile': True,
@@ -7525,7 +7532,8 @@
       'id': 81,
       'caption': '''Allow running plugins that are outdated''',
       'tags': ['system-security'],
-      'desc': '''Setting the policy to Enabled means outdated plugins are used as normal plugins. Setting the policy to Disabled means outdated plugins aren't used.
+      'deprecated': True,
+      'desc': '''This policy is deprecated in M88, Flash is no longer supported by Chrome. Setting the policy to Enabled means outdated plugins are used as normal plugins. Setting the policy to Disabled means outdated plugins aren't used.
 
       Leaving the policy unset means users will be asked for permission to run outdated plugins.''',
     },
diff --git a/components/reading_list/features/reading_list_switches.cc b/components/reading_list/features/reading_list_switches.cc
index 3fa3a1bc..4823ece 100644
--- a/components/reading_list/features/reading_list_switches.cc
+++ b/components/reading_list/features/reading_list_switches.cc
@@ -15,7 +15,11 @@
 const base::Feature kReadLater{"ReadLater", base::FEATURE_DISABLED_BY_DEFAULT};
 
 bool IsReadingListEnabled() {
+#if defined(OS_IOS)
   return BUILDFLAG(ENABLE_READING_LIST);
+#else
+  return base::FeatureList::IsEnabled(kReadLater);
+#endif
 }
 }  // namespace switches
 }  // namespace reading_list
diff --git a/components/shared_highlighting/core/common/text_fragments_utils.cc b/components/shared_highlighting/core/common/text_fragments_utils.cc
index cc450f5..2c9ab5e 100644
--- a/components/shared_highlighting/core/common/text_fragments_utils.cc
+++ b/components/shared_highlighting/core/common/text_fragments_utils.cc
@@ -83,9 +83,10 @@
   if (new_ref.find(kFragmentsUrlDelimiter) == std::string::npos) {
     new_ref += kFragmentsUrlDelimiter;
   } else {
-    // The URL already had the :~: delimiter, so prepare appending the new
-    // fragments by appending an ampersand beforehand.
-    new_ref += "&";
+    // The URL already had the :~: delimiter, so remove what comes after before
+    // adding the new fragment(s).
+    new_ref = new_ref.substr(0, new_ref.find(kFragmentsUrlDelimiter) +
+                                    strlen(kFragmentsUrlDelimiter));
   }
 
   new_ref += fragments_string;
diff --git a/components/shared_highlighting/core/common/text_fragments_utils_unittest.cc b/components/shared_highlighting/core/common/text_fragments_utils_unittest.cc
index 4809e0b..99a6d25e 100644
--- a/components/shared_highlighting/core/common/text_fragments_utils_unittest.cc
+++ b/components/shared_highlighting/core/common/text_fragments_utils_unittest.cc
@@ -73,13 +73,25 @@
 
 TEST(TextFragmentsUtilsTest,
      AppendFragmentDirectivesURLWithPoundAndExistingFragment) {
+  GURL base_url("https://www.chromium.org/#:~:text=some%20value");
+  TextFragment test_fragment("only start");
+
+  GURL created_url = AppendFragmentDirectives(base_url, {test_fragment});
+  EXPECT_EQ(
+      "https://www.chromium.org/"
+      "#:~:text=only%20start",
+      created_url.spec());
+}
+
+TEST(TextFragmentsUtilsTest,
+     AppendFragmentDirectivesURLWithPoundAndExistingFragmentAndAnchor) {
   GURL base_url("https://www.chromium.org/#SomeAnchor:~:text=some%20value");
   TextFragment test_fragment("only start");
 
   GURL created_url = AppendFragmentDirectives(base_url, {test_fragment});
   EXPECT_EQ(
       "https://www.chromium.org/"
-      "#SomeAnchor:~:text=some%20value&text=only%20start",
+      "#SomeAnchor:~:text=only%20start",
       created_url.spec());
 }
 
diff --git a/components/subresource_filter/content/renderer/subresource_filter_agent.cc b/components/subresource_filter/content/renderer/subresource_filter_agent.cc
index 90cb56c5..1238524 100644
--- a/components/subresource_filter/content/renderer/subresource_filter_agent.cc
+++ b/components/subresource_filter/content/renderer/subresource_filter_agent.cc
@@ -126,11 +126,10 @@
   if (!frame_to_inherit_from || !frame_to_inherit_from->IsWebLocalFrame())
     return mojom::ActivationState();
 
-  // TODO(crbug.com/1134740): Add an IsSameOriginWith() function to
-  // WebSecurityOrigin to avoid unnecessary conversions to url::Origin.
-  url::Origin render_frame_origin =
+  blink::WebSecurityOrigin render_frame_origin =
       render_frame->GetWebFrame()->GetSecurityOrigin();
-  url::Origin inherited_origin = frame_to_inherit_from->GetSecurityOrigin();
+  blink::WebSecurityOrigin inherited_origin =
+      frame_to_inherit_from->GetSecurityOrigin();
 
   // Only inherit from same-origin frames.
   if (render_frame_origin.IsSameOriginWith(inherited_origin)) {
diff --git a/components/sync/driver/data_type_controller.h b/components/sync/driver/data_type_controller.h
index 579ec2d..58dcfb3 100644
--- a/components/sync/driver/data_type_controller.h
+++ b/components/sync/driver/data_type_controller.h
@@ -21,6 +21,7 @@
 namespace syncer {
 
 struct ConfigureContext;
+struct TypeEntitiesCount;
 class ModelTypeConfigurer;
 class SyncError;
 
@@ -124,6 +125,11 @@
   // Used for populating nodes in Sync Node Browser of chrome://sync-internals.
   virtual void GetAllNodes(AllNodesCallback callback) = 0;
 
+  // Collects TypeEntitiesCount for this datatype and passes them to |callback|.
+  // Used to display entity counts in chrome://sync-internals.
+  virtual void GetTypeEntitiesCount(
+      base::OnceCallback<void(const TypeEntitiesCount&)> callback) const = 0;
+
   // Records entities count and estimated memory usage of the type into
   // histograms. Can be called only if state() != NOT_RUNNING.
   virtual void RecordMemoryUsageAndCountsHistograms() = 0;
diff --git a/components/sync/driver/model_type_controller.cc b/components/sync/driver/model_type_controller.cc
index c417309f..2a131fa 100644
--- a/components/sync/driver/model_type_controller.cc
+++ b/components/sync/driver/model_type_controller.cc
@@ -16,6 +16,7 @@
 #include "components/sync/engine/model_type_configurer.h"
 #include "components/sync/model/data_type_activation_request.h"
 #include "components/sync/model/data_type_error_handler_impl.h"
+#include "components/sync/model/type_entities_count.h"
 
 namespace syncer {
 namespace {
@@ -221,6 +222,15 @@
   delegate_->GetAllNodesForDebugging(std::move(callback));
 }
 
+void ModelTypeController::GetTypeEntitiesCount(
+    base::OnceCallback<void(const TypeEntitiesCount&)> callback) const {
+  if (delegate_) {
+    delegate_->GetTypeEntitiesCountForDebugging(std::move(callback));
+  } else {
+    std::move(callback).Run(TypeEntitiesCount(type()));
+  }
+}
+
 void ModelTypeController::RecordMemoryUsageAndCountsHistograms() {
   DCHECK(delegate_);
   delegate_->RecordMemoryUsageAndCountsHistograms();
diff --git a/components/sync/driver/model_type_controller.h b/components/sync/driver/model_type_controller.h
index dadf2c2..c9d52fb 100644
--- a/components/sync/driver/model_type_controller.h
+++ b/components/sync/driver/model_type_controller.h
@@ -55,6 +55,8 @@
   State state() const override;
   bool ShouldRunInTransportOnlyMode() const override;
   void GetAllNodes(AllNodesCallback callback) override;
+  void GetTypeEntitiesCount(base::OnceCallback<void(const TypeEntitiesCount&)>
+                                callback) const override;
   void RecordMemoryUsageAndCountsHistograms() override;
 
   ModelTypeControllerDelegate* GetDelegateForTesting(SyncMode sync_mode);
diff --git a/components/sync/driver/model_type_controller_unittest.cc b/components/sync/driver/model_type_controller_unittest.cc
index 996aa9d1..67034e2 100644
--- a/components/sync/driver/model_type_controller_unittest.cc
+++ b/components/sync/driver/model_type_controller_unittest.cc
@@ -23,6 +23,7 @@
 #include "components/sync/engine/model_type_configurer.h"
 #include "components/sync/engine/model_type_processor_proxy.h"
 #include "components/sync/model/data_type_activation_request.h"
+#include "components/sync/model/type_entities_count.h"
 #include "components/sync/model_impl/forwarding_model_type_controller_delegate.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -60,6 +61,10 @@
               GetAllNodesForDebugging,
               (AllNodesCallback callback),
               (override));
+  MOCK_METHOD(void,
+              GetTypeEntitiesCountForDebugging,
+              (base::OnceCallback<void(const TypeEntitiesCount&)> callback),
+              (const override));
   MOCK_METHOD(void, RecordMemoryUsageAndCountsHistograms, (), (override));
 };
 
diff --git a/components/sync/driver/profile_sync_service.cc b/components/sync/driver/profile_sync_service.cc
index 53aea83a..db02738 100644
--- a/components/sync/driver/profile_sync_service.cc
+++ b/components/sync/driver/profile_sync_service.cc
@@ -7,6 +7,7 @@
 #include <cstddef>
 #include <utility>
 
+#include "base/barrier_closure.h"
 #include "base/base64.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
@@ -1471,8 +1472,37 @@
 void ProfileSyncService::GetEntityCountsForDebugging(
     base::OnceCallback<void(const std::vector<TypeEntitiesCount>&)> callback)
     const {
-  // TODO(crbug.com/1138535): Retrieve counts from |data_type_controllers_|.
-  std::move(callback).Run({});
+  // The method must respond with the TypeEntitiesCount of all data types, but
+  // each count request is async. The strategy is to use base::BarrierClosure()
+  // to only send the final response once all types are done.
+  using EntityCountsVector = std::vector<TypeEntitiesCount>;
+  auto all_types_counts = std::make_unique<EntityCountsVector>();
+  EntityCountsVector* all_types_counts_ptr = all_types_counts.get();
+  // |respond_all_counts_callback| owns |all_types_counts|.
+  auto respond_all_counts_callback = base::BindOnce(
+      [](base::OnceCallback<void(const EntityCountsVector&)> callback,
+         std::unique_ptr<EntityCountsVector> all_types_counts) {
+        std::move(callback).Run(*all_types_counts);
+      },
+      std::move(callback), std::move(all_types_counts));
+
+  // |all_types_done_barrier| runs |respond_all_counts_callback| once it's been
+  // called for all types.
+  base::RepeatingClosure all_types_done_barrier = base::BarrierClosure(
+      data_type_controllers_.size(), std::move(respond_all_counts_callback));
+
+  // Callbacks passed to the controllers get a non-owning reference to the
+  // counts vector, which they use to push the count for their individual type.
+  for (const auto& type_and_controller : data_type_controllers_) {
+    type_and_controller.second->GetTypeEntitiesCount(base::BindOnce(
+        [](const base::RepeatingClosure& all_types_done_barrier,
+           EntityCountsVector* all_types_counts_ptr,
+           const TypeEntitiesCount& count) {
+          all_types_counts_ptr->push_back(count);
+          all_types_done_barrier.Run();
+        },
+        all_types_done_barrier, all_types_counts_ptr));
+  }
 }
 
 void ProfileSyncService::OnSyncManagedPrefChange(bool is_sync_managed) {
diff --git a/components/sync/driver/syncable_service_based_model_type_controller.cc b/components/sync/driver/syncable_service_based_model_type_controller.cc
index 02b66ff..b3a29d2c 100644
--- a/components/sync/driver/syncable_service_based_model_type_controller.cc
+++ b/components/sync/driver/syncable_service_based_model_type_controller.cc
@@ -52,12 +52,18 @@
     GetBridgeDelegate()->GetAllNodesForDebugging(std::move(callback));
   }
 
+  void GetTypeEntitiesCountForDebugging(
+      base::OnceCallback<void(const TypeEntitiesCount&)> callback)
+      const override {
+    GetBridgeDelegate()->GetTypeEntitiesCountForDebugging(std::move(callback));
+  }
+
   void RecordMemoryUsageAndCountsHistograms() override {
     GetBridgeDelegate()->RecordMemoryUsageAndCountsHistograms();
   }
 
  private:
-  ModelTypeControllerDelegate* GetBridgeDelegate() {
+  ModelTypeControllerDelegate* GetBridgeDelegate() const {
     DCHECK(bridge_);
     return bridge_->change_processor()->GetControllerDelegate().get();
   }
diff --git a/components/sync/model/model_type_controller_delegate.h b/components/sync/model/model_type_controller_delegate.h
index 8518f1e2..976bbdd5 100644
--- a/components/sync/model/model_type_controller_delegate.h
+++ b/components/sync/model/model_type_controller_delegate.h
@@ -18,6 +18,7 @@
 namespace syncer {
 
 struct DataTypeActivationRequest;
+struct TypeEntitiesCount;
 
 // The ModelTypeControllerDelegate handles communication of ModelTypeController
 // with the data type. Unlike the controller which lives on the UI thread, the
@@ -46,6 +47,11 @@
   // Used for populating nodes in Sync Node Browser of chrome://sync-internals.
   virtual void GetAllNodesForDebugging(AllNodesCallback callback) = 0;
 
+  // Returns TypeEntitiesCount for the type to |callback|.
+  // Used for updating data type counts in chrome://sync-internals.
+  virtual void GetTypeEntitiesCountForDebugging(
+      base::OnceCallback<void(const TypeEntitiesCount&)> callback) const = 0;
+
   // Records entities count and estimated memory usage of the type into
   // histograms.
   virtual void RecordMemoryUsageAndCountsHistograms() = 0;
diff --git a/components/sync/model/type_entities_count.h b/components/sync/model/type_entities_count.h
index ea136a4..73fc8da 100644
--- a/components/sync/model/type_entities_count.h
+++ b/components/sync/model/type_entities_count.h
@@ -11,7 +11,9 @@
 
 // Used to track per data-type entity counts for debugging purposes.
 struct TypeEntitiesCount {
-  ModelType type = UNSPECIFIED;
+  explicit TypeEntitiesCount(ModelType type) : type(type) {}
+
+  ModelType type;
 
   int entities = 0;
 
diff --git a/components/sync/model_impl/client_tag_based_model_type_processor.cc b/components/sync/model_impl/client_tag_based_model_type_processor.cc
index a8fa88c..93d62b0 100644
--- a/components/sync/model_impl/client_tag_based_model_type_processor.cc
+++ b/components/sync/model_impl/client_tag_based_model_type_processor.cc
@@ -22,6 +22,7 @@
 #include "components/sync/engine/commit_queue.h"
 #include "components/sync/engine/data_type_activation_response.h"
 #include "components/sync/engine/model_type_processor_proxy.h"
+#include "components/sync/model/type_entities_count.h"
 #include "components/sync/model_impl/client_tag_based_remote_update_handler.h"
 #include "components/sync/model_impl/processor_entity.h"
 #include "components/sync/protocol/proto_value_conversions.h"
@@ -1204,6 +1205,16 @@
   DCHECK(!entity_tracker_);
 }
 
+void ClientTagBasedModelTypeProcessor::GetTypeEntitiesCountForDebugging(
+    base::OnceCallback<void(const TypeEntitiesCount&)> callback) const {
+  TypeEntitiesCount count(type_);
+  if (entity_tracker_) {
+    count.entities = entity_tracker_->size();
+    count.non_tombstone_entities = entity_tracker_->CountNonTombstoneEntries();
+  }
+  std::move(callback).Run(count);
+}
+
 void ClientTagBasedModelTypeProcessor::RecordMemoryUsageAndCountsHistograms() {
   SyncRecordModelTypeMemoryHistogram(type_, EstimateMemoryUsage());
   const size_t non_tombstone_entries_count =
diff --git a/components/sync/model_impl/client_tag_based_model_type_processor.h b/components/sync/model_impl/client_tag_based_model_type_processor.h
index 84307327..44c57067 100644
--- a/components/sync/model_impl/client_tag_based_model_type_processor.h
+++ b/components/sync/model_impl/client_tag_based_model_type_processor.h
@@ -102,6 +102,9 @@
                       StartCallback callback) override;
   void OnSyncStopping(SyncStopMetadataFate metadata_fate) override;
   void GetAllNodesForDebugging(AllNodesCallback callback) override;
+  void GetTypeEntitiesCountForDebugging(
+      base::OnceCallback<void(const TypeEntitiesCount&)> callback)
+      const override;
   void RecordMemoryUsageAndCountsHistograms() override;
 
   // Returns the estimate of dynamically allocated memory in bytes.
diff --git a/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc b/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc
index aee83d6..3942988 100644
--- a/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc
+++ b/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc
@@ -27,6 +27,7 @@
 #include "components/sync/engine/data_type_activation_response.h"
 #include "components/sync/model/conflict_resolution.h"
 #include "components/sync/model/data_type_activation_request.h"
+#include "components/sync/model/type_entities_count.h"
 #include "components/sync/test/engine/mock_model_type_worker.h"
 #include "components/sync/test/model/fake_model_type_sync_bridge.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -76,6 +77,11 @@
   *dst = std::move(src);
 }
 
+void CaptureTypeEntitiesCount(TypeEntitiesCount* dst,
+                              const TypeEntitiesCount& count) {
+  *dst = count;
+}
+
 class TestModelTypeSyncBridge : public FakeModelTypeSyncBridge {
  public:
   explicit TestModelTypeSyncBridge(bool commit_only,
@@ -2219,6 +2225,10 @@
   worker()->AckOnePendingCommit();
 
   // Check the processor tracks the entity.
+  TypeEntitiesCount count(GetModelType());
+  type_processor()->GetTypeEntitiesCountForDebugging(
+      base::BindOnce(&CaptureTypeEntitiesCount, &count));
+  ASSERT_EQ(1, count.non_tombstone_entities);
   ASSERT_NE(nullptr, GetEntityForStorageKey(kKey1));
 
   // The bridge deletes the data locally and does not want to sync the deletion.
@@ -2228,6 +2238,9 @@
   // The deletion is not synced up.
   worker()->VerifyPendingCommits({});
   // The processor tracks no entity any more.
+  type_processor()->GetTypeEntitiesCountForDebugging(
+      base::BindOnce(&CaptureTypeEntitiesCount, &count));
+  EXPECT_EQ(0, count.non_tombstone_entities);
   EXPECT_EQ(nullptr, GetEntityForStorageKey(kKey1));
 }
 
@@ -2244,6 +2257,10 @@
   // No deletion is not synced up.
   worker()->VerifyPendingCommits({});
   // The processor tracks no entity.
+  TypeEntitiesCount count(GetModelType());
+  type_processor()->GetTypeEntitiesCountForDebugging(
+      base::BindOnce(&CaptureTypeEntitiesCount, &count));
+  EXPECT_EQ(0, count.non_tombstone_entities);
   EXPECT_EQ(nullptr, GetEntityForStorageKey(kKey1));
 }
 
@@ -2259,6 +2276,10 @@
   worker()->AckOnePendingCommit();
 
   // Check the processor tracks the entity.
+  TypeEntitiesCount count(GetModelType());
+  type_processor()->GetTypeEntitiesCountForDebugging(
+      base::BindOnce(&CaptureTypeEntitiesCount, &count));
+  ASSERT_EQ(1, count.non_tombstone_entities);
   ASSERT_NE(nullptr, GetEntityForStorageKey(kKey1));
 
   // The bridge deletes the data locally and does not want to sync the deletion.
@@ -2268,6 +2289,9 @@
   // The deletion is not synced up.
   worker()->VerifyPendingCommits({});
   // The processor tracks no entity any more.
+  type_processor()->GetTypeEntitiesCountForDebugging(
+      base::BindOnce(&CaptureTypeEntitiesCount, &count));
+  EXPECT_EQ(0, count.non_tombstone_entities);
   EXPECT_EQ(nullptr, GetEntityForStorageKey(kKey1));
 }
 
diff --git a/components/sync/model_impl/forwarding_model_type_controller_delegate.cc b/components/sync/model_impl/forwarding_model_type_controller_delegate.cc
index dbee450e..2886bdd 100644
--- a/components/sync/model_impl/forwarding_model_type_controller_delegate.cc
+++ b/components/sync/model_impl/forwarding_model_type_controller_delegate.cc
@@ -34,6 +34,11 @@
   other_->GetAllNodesForDebugging(std::move(callback));
 }
 
+void ForwardingModelTypeControllerDelegate::GetTypeEntitiesCountForDebugging(
+    base::OnceCallback<void(const TypeEntitiesCount&)> callback) const {
+  other_->GetTypeEntitiesCountForDebugging(std::move(callback));
+}
+
 void ForwardingModelTypeControllerDelegate::
     RecordMemoryUsageAndCountsHistograms() {
   other_->RecordMemoryUsageAndCountsHistograms();
diff --git a/components/sync/model_impl/forwarding_model_type_controller_delegate.h b/components/sync/model_impl/forwarding_model_type_controller_delegate.h
index 207f415..ee45f06 100644
--- a/components/sync/model_impl/forwarding_model_type_controller_delegate.h
+++ b/components/sync/model_impl/forwarding_model_type_controller_delegate.h
@@ -28,6 +28,9 @@
                       StartCallback callback) override;
   void OnSyncStopping(SyncStopMetadataFate metadata_fate) override;
   void GetAllNodesForDebugging(AllNodesCallback callback) override;
+  void GetTypeEntitiesCountForDebugging(
+      base::OnceCallback<void(const TypeEntitiesCount&)> callback)
+      const override;
   void RecordMemoryUsageAndCountsHistograms() override;
 
  private:
diff --git a/components/sync/model_impl/proxy_model_type_controller_delegate.cc b/components/sync/model_impl/proxy_model_type_controller_delegate.cc
index 4d3cb9c9..cfca4b7 100644
--- a/components/sync/model_impl/proxy_model_type_controller_delegate.cc
+++ b/components/sync/model_impl/proxy_model_type_controller_delegate.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "components/sync/base/bind_to_task_runner.h"
 #include "components/sync/model/data_type_activation_request.h"
+#include "components/sync/model/type_entities_count.h"
 
 namespace syncer {
 namespace {
@@ -29,6 +30,15 @@
   delegate->GetAllNodesForDebugging(std::move(callback_bound_to_ui_thread));
 }
 
+void GetTypeEntitiesCountForDebuggingHelperOnModelThread(
+    base::OnceCallback<void(const TypeEntitiesCount&)>
+        callback_bound_to_ui_thread,
+    base::WeakPtr<ModelTypeControllerDelegate> delegate) {
+  DCHECK(delegate);
+  delegate->GetTypeEntitiesCountForDebugging(
+      std::move(callback_bound_to_ui_thread));
+}
+
 void StopSyncHelperOnModelThread(
     SyncStopMetadataFate metadata_fate,
     base::WeakPtr<ModelTypeControllerDelegate> delegate) {
@@ -86,6 +96,13 @@
                           BindToCurrentSequence(std::move(callback))));
 }
 
+void ProxyModelTypeControllerDelegate::GetTypeEntitiesCountForDebugging(
+    base::OnceCallback<void(const TypeEntitiesCount&)> callback) const {
+  PostTask(FROM_HERE,
+           base::BindOnce(&GetTypeEntitiesCountForDebuggingHelperOnModelThread,
+                          BindToCurrentSequence(std::move(callback))));
+}
+
 void ProxyModelTypeControllerDelegate::RecordMemoryUsageAndCountsHistograms() {
   PostTask(
       FROM_HERE,
@@ -94,7 +111,8 @@
 
 void ProxyModelTypeControllerDelegate::PostTask(
     const base::Location& location,
-    base::OnceCallback<void(base::WeakPtr<ModelTypeControllerDelegate>)> task) {
+    base::OnceCallback<void(base::WeakPtr<ModelTypeControllerDelegate>)> task)
+    const {
   task_runner_->PostTask(
       location,
       base::BindOnce(&RunModelTask, delegate_provider_, std::move(task)));
diff --git a/components/sync/model_impl/proxy_model_type_controller_delegate.h b/components/sync/model_impl/proxy_model_type_controller_delegate.h
index 6bfea31d..622e8bf 100644
--- a/components/sync/model_impl/proxy_model_type_controller_delegate.h
+++ b/components/sync/model_impl/proxy_model_type_controller_delegate.h
@@ -34,6 +34,9 @@
                       StartCallback callback) override;
   void OnSyncStopping(SyncStopMetadataFate metadata_fate) override;
   void GetAllNodesForDebugging(AllNodesCallback callback) override;
+  void GetTypeEntitiesCountForDebugging(
+      base::OnceCallback<void(const TypeEntitiesCount&)> callback)
+      const override;
   void RecordMemoryUsageAndCountsHistograms() override;
 
  private:
@@ -41,8 +44,8 @@
   // |task_runner_|.
   void PostTask(
       const base::Location& location,
-      base::OnceCallback<void(base::WeakPtr<ModelTypeControllerDelegate>)>
-          task);
+      base::OnceCallback<void(base::WeakPtr<ModelTypeControllerDelegate>)> task)
+      const;
 
   const scoped_refptr<base::SequencedTaskRunner> task_runner_;
   const DelegateProvider delegate_provider_;
diff --git a/components/sync/nigori/nigori_model_type_processor.cc b/components/sync/nigori/nigori_model_type_processor.cc
index 3e21f4ff..e90d56f 100644
--- a/components/sync/nigori/nigori_model_type_processor.cc
+++ b/components/sync/nigori/nigori_model_type_processor.cc
@@ -11,6 +11,7 @@
 #include "components/sync/base/time.h"
 #include "components/sync/engine/commit_queue.h"
 #include "components/sync/engine/forwarding_model_type_processor.h"
+#include "components/sync/model/type_entities_count.h"
 #include "components/sync/model_impl/processor_entity.h"
 #include "components/sync/nigori/nigori_sync_bridge.h"
 #include "components/sync/protocol/proto_memory_estimations.h"
@@ -262,6 +263,15 @@
   std::move(callback).Run(syncer::NIGORI, std::move(all_nodes));
 }
 
+void NigoriModelTypeProcessor::GetTypeEntitiesCountForDebugging(
+    base::OnceCallback<void(const TypeEntitiesCount&)> callback) const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  TypeEntitiesCount count(syncer::NIGORI);
+  count.non_tombstone_entities = entity_ ? 1 : 0;
+  count.entities = count.non_tombstone_entities;
+  std::move(callback).Run(count);
+}
+
 void NigoriModelTypeProcessor::RecordMemoryUsageAndCountsHistograms() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   size_t memory_usage = 0;
@@ -382,10 +392,6 @@
   return model_type_state_;
 }
 
-bool NigoriModelTypeProcessor::HasEntityForTest() const {
-  return entity_ != nullptr;
-}
-
 bool NigoriModelTypeProcessor::IsTrackingMetadata() {
   return model_type_state_.initial_sync_done();
 }
diff --git a/components/sync/nigori/nigori_model_type_processor.h b/components/sync/nigori/nigori_model_type_processor.h
index a3ef36f..2ac6a38 100644
--- a/components/sync/nigori/nigori_model_type_processor.h
+++ b/components/sync/nigori/nigori_model_type_processor.h
@@ -45,6 +45,9 @@
                       StartCallback callback) override;
   void OnSyncStopping(SyncStopMetadataFate metadata_fate) override;
   void GetAllNodesForDebugging(AllNodesCallback callback) override;
+  void GetTypeEntitiesCountForDebugging(
+      base::OnceCallback<void(const TypeEntitiesCount&)> callback)
+      const override;
   void RecordMemoryUsageAndCountsHistograms() override;
 
   // NigoriLocalChangeProcessor implementation.
@@ -59,8 +62,6 @@
 
   bool IsConnectedForTest() const;
   const sync_pb::ModelTypeState& GetModelTypeStateForTest();
-  // Whether |entity_| is non-null.
-  bool HasEntityForTest() const;
 
  private:
   // Returns true if the handshake with sync thread is complete.
diff --git a/components/sync/nigori/nigori_model_type_processor_unittest.cc b/components/sync/nigori/nigori_model_type_processor_unittest.cc
index 2a19e0dc..6750e1e 100644
--- a/components/sync/nigori/nigori_model_type_processor_unittest.cc
+++ b/components/sync/nigori/nigori_model_type_processor_unittest.cc
@@ -15,6 +15,7 @@
 #include "components/sync/base/sync_base_switches.h"
 #include "components/sync/base/time.h"
 #include "components/sync/engine/commit_queue.h"
+#include "components/sync/model/type_entities_count.h"
 #include "components/sync/nigori/nigori_sync_bridge.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -148,6 +149,15 @@
 
   NigoriModelTypeProcessor* processor() { return &processor_; }
 
+  bool ProcessorHasEntity() {
+    TypeEntitiesCount count(NIGORI);
+    base::MockCallback<base::OnceCallback<void(const TypeEntitiesCount&)>>
+        capture_callback;
+    EXPECT_CALL(capture_callback, Run).WillOnce(testing::SaveArg<0>(&count));
+    processor()->GetTypeEntitiesCountForDebugging(capture_callback.Get());
+    return count.non_tombstone_entities > 0;
+  }
+
  private:
   testing::NiceMock<MockNigoriSyncBridge> mock_nigori_sync_bridge_;
   std::unique_ptr<testing::NiceMock<MockCommitQueue>> mock_commit_queue_;
@@ -503,7 +513,7 @@
 
 TEST_F(NigoriModelTypeProcessorTest, ShouldResetDataOnCacheGuidMismatch) {
   SimulateModelReadyToSync(/*initial_sync_done=*/true);
-  ASSERT_TRUE(processor()->HasEntityForTest());
+  ASSERT_TRUE(ProcessorHasEntity());
 
   syncer::DataTypeActivationRequest request;
   request.error_handler = base::DoNothing();
@@ -520,7 +530,7 @@
   EXPECT_EQ(processor()->GetModelTypeStateForTest().cache_guid(),
             kOtherCacheGuid);
 
-  EXPECT_FALSE(processor()->HasEntityForTest());
+  EXPECT_FALSE(ProcessorHasEntity());
 
   // Check that sync can be started.
   const std::string kDecryptorTokenKeyName = "key_name";
@@ -543,7 +553,7 @@
       switches::kSyncNigoriRemoveMetadataOnCacheGuidMismatch);
 
   SimulateModelReadyToSync(/*initial_sync_done=*/true);
-  ASSERT_TRUE(processor()->HasEntityForTest());
+  ASSERT_TRUE(ProcessorHasEntity());
 
   syncer::DataTypeActivationRequest request;
   request.error_handler = base::DoNothing();
@@ -559,7 +569,7 @@
   EXPECT_TRUE(processor()->IsTrackingMetadata());
   EXPECT_EQ(processor()->GetModelTypeStateForTest().cache_guid(), kCacheGuid);
 
-  EXPECT_TRUE(processor()->HasEntityForTest());
+  EXPECT_TRUE(ProcessorHasEntity());
 }
 
 TEST_F(NigoriModelTypeProcessorTest, ShouldDisconnectWhenMergeSyncDataFails) {
diff --git a/components/sync/test/model/fake_model_type_controller_delegate.cc b/components/sync/test/model/fake_model_type_controller_delegate.cc
index 3b039468..e03ab31a 100644
--- a/components/sync/test/model/fake_model_type_controller_delegate.cc
+++ b/components/sync/test/model/fake_model_type_controller_delegate.cc
@@ -10,6 +10,7 @@
 #include "base/run_loop.h"
 #include "components/sync/engine/data_type_activation_response.h"
 #include "components/sync/model/data_type_activation_request.h"
+#include "components/sync/model/type_entities_count.h"
 
 namespace syncer {
 
@@ -86,6 +87,11 @@
 
 void FakeModelTypeControllerDelegate::RecordMemoryUsageAndCountsHistograms() {}
 
+void FakeModelTypeControllerDelegate::GetTypeEntitiesCountForDebugging(
+    base::OnceCallback<void(const TypeEntitiesCount&)> callback) const {
+  std::move(callback).Run(TypeEntitiesCount(type_));
+}
+
 base::WeakPtr<ModelTypeControllerDelegate>
 FakeModelTypeControllerDelegate::GetWeakPtr() {
   return weak_ptr_factory_.GetWeakPtr();
diff --git a/components/sync/test/model/fake_model_type_controller_delegate.h b/components/sync/test/model/fake_model_type_controller_delegate.h
index e0f8c800..9423a74 100644
--- a/components/sync/test/model/fake_model_type_controller_delegate.h
+++ b/components/sync/test/model/fake_model_type_controller_delegate.h
@@ -42,6 +42,9 @@
   void OnSyncStopping(SyncStopMetadataFate metadata_fate) override;
   void GetAllNodesForDebugging(AllNodesCallback callback) override;
   void RecordMemoryUsageAndCountsHistograms() override;
+  void GetTypeEntitiesCountForDebugging(
+      base::OnceCallback<void(const TypeEntitiesCount&)> callback)
+      const override;
 
   base::WeakPtr<ModelTypeControllerDelegate> GetWeakPtr();
 
diff --git a/components/sync_bookmarks/bookmark_model_type_processor.cc b/components/sync_bookmarks/bookmark_model_type_processor.cc
index 5cf50e9..c4da638 100644
--- a/components/sync_bookmarks/bookmark_model_type_processor.cc
+++ b/components/sync_bookmarks/bookmark_model_type_processor.cc
@@ -24,6 +24,7 @@
 #include "components/sync/engine/commit_queue.h"
 #include "components/sync/engine/model_type_processor_proxy.h"
 #include "components/sync/model/data_type_activation_request.h"
+#include "components/sync/model/type_entities_count.h"
 #include "components/sync/protocol/bookmark_model_metadata.pb.h"
 #include "components/sync/protocol/proto_value_conversions.h"
 #include "components/sync_bookmarks/bookmark_local_changes_builder.h"
@@ -565,6 +566,18 @@
     AppendNodeAndChildrenForDebugging(child.get(), i++, all_nodes);
 }
 
+void BookmarkModelTypeProcessor::GetTypeEntitiesCountForDebugging(
+    base::OnceCallback<void(const syncer::TypeEntitiesCount&)> callback) const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  syncer::TypeEntitiesCount count(syncer::BOOKMARKS);
+  if (bookmark_tracker_) {
+    count.non_tombstone_entities = bookmark_tracker_->TrackedBookmarksCount();
+    count.entities = count.non_tombstone_entities +
+                     bookmark_tracker_->TrackedUncommittedTombstonesCount();
+  }
+  std::move(callback).Run(count);
+}
+
 void BookmarkModelTypeProcessor::RecordMemoryUsageAndCountsHistograms() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   SyncRecordModelTypeMemoryHistogram(syncer::BOOKMARKS, EstimateMemoryUsage());
diff --git a/components/sync_bookmarks/bookmark_model_type_processor.h b/components/sync_bookmarks/bookmark_model_type_processor.h
index da6bb55b..f6753c7 100644
--- a/components/sync_bookmarks/bookmark_model_type_processor.h
+++ b/components/sync_bookmarks/bookmark_model_type_processor.h
@@ -57,6 +57,9 @@
                       StartCallback start_callback) override;
   void OnSyncStopping(syncer::SyncStopMetadataFate metadata_fate) override;
   void GetAllNodesForDebugging(AllNodesCallback callback) override;
+  void GetTypeEntitiesCountForDebugging(
+      base::OnceCallback<void(const syncer::TypeEntitiesCount&)> callback)
+      const override;
   void RecordMemoryUsageAndCountsHistograms() override;
 
   // Encodes all sync metadata into a string, representing a state that can be
diff --git a/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc b/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
index 0a590c3f..f7f8914 100644
--- a/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
+++ b/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
@@ -21,6 +21,7 @@
 #include "components/sync/base/unique_position.h"
 #include "components/sync/engine/commit_queue.h"
 #include "components/sync/model/data_type_activation_request.h"
+#include "components/sync/model/type_entities_count.h"
 #include "components/sync_bookmarks/switches.h"
 #include "components/undo/bookmark_undo_service.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -626,6 +627,21 @@
 }
 
 TEST_F(BookmarkModelTypeProcessorTest,
+       ShouldReportNoCountersWhenModelIsNotLoaded) {
+  SimulateOnSyncStarting();
+  ASSERT_THAT(processor()->GetTrackerForTest(), IsNull());
+  syncer::TypeEntitiesCount count(syncer::BOOKMARKS);
+  // Assign an arbitrary non-zero number of entities to be able to check that
+  // actually a 0 has been written to it later.
+  count.non_tombstone_entities = 1000;
+  processor()->GetTypeEntitiesCountForDebugging(base::BindLambdaForTesting(
+      [&](const syncer::TypeEntitiesCount& returned_count) {
+        count = returned_count;
+      }));
+  EXPECT_EQ(0, count.non_tombstone_entities);
+}
+
+TEST_F(BookmarkModelTypeProcessorTest,
        ShouldNotCommitEntitiesWithoutLoadedFavicons) {
   base::test::ScopedFeatureList features;
   features.InitAndEnableFeature(
diff --git a/components/sync_bookmarks/synced_bookmark_tracker.cc b/components/sync_bookmarks/synced_bookmark_tracker.cc
index 7640beaf..325775d 100644
--- a/components/sync_bookmarks/synced_bookmark_tracker.cc
+++ b/components/sync_bookmarks/synced_bookmark_tracker.cc
@@ -883,12 +883,12 @@
   return bookmark_node_to_entities_map_.size();
 }
 
-size_t SyncedBookmarkTracker::TrackedEntitiesCountForTest() const {
-  return sync_id_to_entities_map_.size();
+size_t SyncedBookmarkTracker::TrackedUncommittedTombstonesCount() const {
+  return ordered_local_tombstones_.size();
 }
 
-size_t SyncedBookmarkTracker::TrackedUncommittedTombstonesCountForTest() const {
-  return ordered_local_tombstones_.size();
+size_t SyncedBookmarkTracker::TrackedEntitiesCountForTest() const {
+  return sync_id_to_entities_map_.size();
 }
 
 void SyncedBookmarkTracker::ClearSpecificsHashForTest(const Entity* entity) {
diff --git a/components/sync_bookmarks/synced_bookmark_tracker.h b/components/sync_bookmarks/synced_bookmark_tracker.h
index 5798cfc..0f734f6 100644
--- a/components/sync_bookmarks/synced_bookmark_tracker.h
+++ b/components/sync_bookmarks/synced_bookmark_tracker.h
@@ -273,12 +273,12 @@
   // Returns number of tracked bookmarks that aren't deleted.
   size_t TrackedBookmarksCount() const;
 
-  // Returns number of tracked entities. Used only in test.
-  size_t TrackedEntitiesCountForTest() const;
-
   // Returns number of bookmarks that have been deleted but the server hasn't
   // confirmed the deletion yet.
-  size_t TrackedUncommittedTombstonesCountForTest() const;
+  size_t TrackedUncommittedTombstonesCount() const;
+
+  // Returns number of tracked entities. Used only in test.
+  size_t TrackedEntitiesCountForTest() const;
 
   // Clears the specifics hash for |entity|, useful for testing.
   void ClearSpecificsHashForTest(const Entity* entity);
diff --git a/components/sync_bookmarks/synced_bookmark_tracker_unittest.cc b/components/sync_bookmarks/synced_bookmark_tracker_unittest.cc
index f5c9062..82899530 100644
--- a/components/sync_bookmarks/synced_bookmark_tracker_unittest.cc
+++ b/components/sync_bookmarks/synced_bookmark_tracker_unittest.cc
@@ -463,20 +463,20 @@
       tracker->Add(&node, kSyncId, kServerVersion, kModificationTime,
                    unique_position, specifics);
 
-  ASSERT_THAT(tracker->TrackedUncommittedTombstonesCountForTest(), Eq(0U));
+  ASSERT_THAT(tracker->TrackedUncommittedTombstonesCount(), Eq(0U));
 
   // Delete the bookmark, leading to a pending deletion (local tombstone).
   tracker->MarkDeleted(tracker->GetEntityForSyncId(kSyncId));
   ASSERT_THAT(entity->bookmark_node(), IsNull());
   ASSERT_TRUE(entity->metadata()->is_deleted());
-  ASSERT_THAT(tracker->TrackedUncommittedTombstonesCountForTest(), Eq(1U));
+  ASSERT_THAT(tracker->TrackedUncommittedTombstonesCount(), Eq(1U));
 
   // Undelete it.
   tracker->UndeleteTombstoneForBookmarkNode(entity, &node);
 
   EXPECT_THAT(entity->bookmark_node(), NotNull());
   EXPECT_FALSE(entity->metadata()->is_deleted());
-  EXPECT_THAT(tracker->TrackedUncommittedTombstonesCountForTest(), Eq(0U));
+  EXPECT_THAT(tracker->TrackedUncommittedTombstonesCount(), Eq(0U));
 }
 
 TEST(SyncedBookmarkTrackerTest,
diff --git a/components/sync_sessions/proxy_tabs_data_type_controller.cc b/components/sync_sessions/proxy_tabs_data_type_controller.cc
index 3f868e0..81a04be3 100644
--- a/components/sync_sessions/proxy_tabs_data_type_controller.cc
+++ b/components/sync_sessions/proxy_tabs_data_type_controller.cc
@@ -9,6 +9,7 @@
 #include "base/values.h"
 #include "components/sync/driver/configure_context.h"
 #include "components/sync/engine/model_type_configurer.h"
+#include "components/sync/model/type_entities_count.h"
 
 namespace sync_sessions {
 
@@ -77,6 +78,11 @@
   std::move(callback).Run(type(), std::make_unique<base::ListValue>());
 }
 
+void ProxyTabsDataTypeController::GetTypeEntitiesCount(
+    base::OnceCallback<void(const syncer::TypeEntitiesCount&)> callback) const {
+  std::move(callback).Run(syncer::TypeEntitiesCount(type()));
+}
+
 void ProxyTabsDataTypeController::RecordMemoryUsageAndCountsHistograms() {}
 
 }  // namespace sync_sessions
diff --git a/components/sync_sessions/proxy_tabs_data_type_controller.h b/components/sync_sessions/proxy_tabs_data_type_controller.h
index 62a1d8f..f44e9ebc 100644
--- a/components/sync_sessions/proxy_tabs_data_type_controller.h
+++ b/components/sync_sessions/proxy_tabs_data_type_controller.h
@@ -34,6 +34,9 @@
   bool ShouldRunInTransportOnlyMode() const override;
   void DeactivateDataType(syncer::ModelTypeConfigurer* configurer) override;
   void GetAllNodes(AllNodesCallback callback) override;
+  void GetTypeEntitiesCount(
+      base::OnceCallback<void(const syncer::TypeEntitiesCount&)> callback)
+      const override;
   void RecordMemoryUsageAndCountsHistograms() override;
 
  private:
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
index 35b7b7c..61ffd2af 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -1015,11 +1015,6 @@
   }
   promise_image_access_helper_.EndAccess();
   output_device_->ScheduleOverlays(std::move(overlays));
-
-  // Release any backings which are not reused by the current frame, probably
-  // because the properties of render passes are changed or render passes are
-  // removed.
-  available_render_pass_overlay_backings_.clear();
 #else
   DCHECK(image_contexts.empty());
   output_device_->ScheduleOverlays(std::move(overlays));
@@ -1356,9 +1351,16 @@
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(output_device_);
 
+#if defined(OS_APPLE)
+  // Release any backings which are not reused by the current frame, probably
+  // because the properties of render passes are changed or render passes are
+  // removed.
+  available_render_pass_overlay_backings_.clear();
+#endif
+
   if (context_is_lost_)
     return;
-
+ 
   ResetStateOfImages();
   output_device_->PreGrContextSubmit();
   gr_context()->submit();
@@ -1460,7 +1462,7 @@
 
 #if defined(OS_APPLE)
   // |available_render_pass_overlay_backings_| are used or released in
-  // ScheduleOverlays() for every frames.
+  // SwapBuffers() for every frames.
   DCHECK(available_render_pass_overlay_backings_.empty());
 
   // Erase mailboxes of render pass overlays from |params.released_overlays| and
diff --git a/components/viz/service/surfaces/surface_dependency_deadline.cc b/components/viz/service/surfaces/surface_dependency_deadline.cc
index ee71400..e193c56 100644
--- a/components/viz/service/surfaces/surface_dependency_deadline.cc
+++ b/components/viz/service/surfaces/surface_dependency_deadline.cc
@@ -4,7 +4,6 @@
 
 #include "components/viz/service/surfaces/surface_dependency_deadline.h"
 
-#include "base/metrics/histogram_macros.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/time/tick_clock.h"
 #include "components/viz/common/quads/frame_deadline.h"
@@ -38,12 +37,7 @@
 
   deadline_.reset();
 
-  base::TimeDelta duration = tick_clock_->NowTicks() - start_time_;
-
-  UMA_HISTOGRAM_TIMES("Compositing.SurfaceDependencyDeadline.Duration",
-                      duration);
-
-  return duration;
+  return tick_clock_->NowTicks() - start_time_;
 }
 
 bool SurfaceDependencyDeadline::operator==(
diff --git a/components/viz/service/surfaces/surface_manager.cc b/components/viz/service/surfaces/surface_manager.cc
index 3228503..df98c59 100644
--- a/components/viz/service/surfaces/surface_manager.cc
+++ b/components/viz/service/surfaces/surface_manager.cc
@@ -13,7 +13,6 @@
 #include "base/containers/adapters.h"
 #include "base/containers/queue.h"
 #include "base/logging.h"
-#include "base/metrics/histogram_macros.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/time/default_tick_clock.h"
 #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
@@ -30,8 +29,6 @@
 namespace viz {
 namespace {
 
-const char kUmaAliveSurfaces[] = "Compositing.SurfaceManager.AliveSurfaces";
-
 constexpr base::TimeDelta kExpireInterval = base::TimeDelta::FromSeconds(10);
 
 }  // namespace
@@ -185,11 +182,6 @@
   }
 
   SurfaceIdSet reachable_surfaces = GetLiveSurfaces();
-
-  // Log the number of reachable surfaces after a garbage collection.
-  UMA_HISTOGRAM_CUSTOM_COUNTS(kUmaAliveSurfaces, reachable_surfaces.size(), 1,
-                              200, 50);
-
   std::vector<SurfaceId> surfaces_to_delete;
 
   // Delete all destroyed and unreachable surfaces.
diff --git a/content/browser/back_forward_cache_browsertest.cc b/content/browser/back_forward_cache_browsertest.cc
index 1915f290..d89ef2e8 100644
--- a/content/browser/back_forward_cache_browsertest.cc
+++ b/content/browser/back_forward_cache_browsertest.cc
@@ -34,6 +34,7 @@
 #include "content/browser/renderer_host/frame_tree_node.h"
 #include "content/browser/renderer_host/page_lifecycle_state_manager.h"
 #include "content/browser/renderer_host/render_frame_host_impl.h"
+#include "content/browser/renderer_host/should_swap_browsing_instance.h"
 #include "content/browser/web_contents/file_chooser_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/content_navigation_policy.h"
@@ -376,6 +377,30 @@
         << location.ToString();
   }
 
+  void ExpectBrowsingInstanceNotSwappedReason(ShouldSwapBrowsingInstance reason,
+                                              base::Location location) {
+    base::HistogramBase::Sample sample = base::HistogramBase::Sample(reason);
+    AddSampleToBuckets(&expected_browsing_instance_not_swapped_reasons_,
+                       sample);
+
+    EXPECT_THAT(histogram_tester_.GetAllSamples(
+                    "BackForwardCache.HistoryNavigationOutcome."
+                    "BrowsingInstanceNotSwappedReason"),
+                UnorderedElementsAreArray(
+                    expected_browsing_instance_not_swapped_reasons_))
+        << location.ToString();
+
+    if (!check_all_sites_)
+      return;
+
+    EXPECT_THAT(histogram_tester_.GetAllSamples(
+                    "BackForwardCache.AllSites.HistoryNavigationOutcome."
+                    "BrowsingInstanceNotSwappedReason"),
+                UnorderedElementsAreArray(
+                    expected_browsing_instance_not_swapped_reasons_))
+        << location.ToString();
+  }
+
   void ExpectEvictedAfterCommitted(
       std::vector<BackForwardCacheMetrics::EvictedAfterDocumentRestoredReason>
           reasons,
@@ -503,6 +528,7 @@
   std::vector<base::Bucket> expected_not_restored_;
   std::vector<base::Bucket> expected_blocklisted_features_;
   std::vector<base::Bucket> expected_disabled_reasons_;
+  std::vector<base::Bucket> expected_browsing_instance_not_swapped_reasons_;
   std::vector<base::Bucket> expected_eviction_after_committing_;
   std::unique_ptr<net::EmbeddedTestServer> https_server_;
   std::unordered_map<base::Feature,
@@ -2494,6 +2520,23 @@
         {blink::scheduler::WebSchedulerTrackedFeature::kWebRTC,
          blink::scheduler::WebSchedulerTrackedFeature::kKeyboardLock},
         FROM_HERE);
+    ExpectBrowsingInstanceNotSwappedReason(
+        ShouldSwapBrowsingInstance::kNo_NotNeededForBackForwardCache,
+        FROM_HERE);
+
+    web_contents()->GetController().GoForward();
+    EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+    ExpectBrowsingInstanceNotSwappedReason(
+        ShouldSwapBrowsingInstance::kNo_AlreadyHasMatchingBrowsingInstance,
+        FROM_HERE);
+
+    web_contents()->GetController().GoBack();
+    EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+    ExpectBrowsingInstanceNotSwappedReason(
+        ShouldSwapBrowsingInstance::kNo_AlreadyHasMatchingBrowsingInstance,
+        FROM_HERE);
   } else {
     ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
                            kRenderFrameHostReused_CrossSite},
diff --git a/content/browser/child_process_security_policy_impl.cc b/content/browser/child_process_security_policy_impl.cc
index 1bb9dc8..c3f22af 100644
--- a/content/browser/child_process_security_policy_impl.cc
+++ b/content/browser/child_process_security_policy_impl.cc
@@ -2104,8 +2104,7 @@
   // Note: we cannot check the feature flags and early-out here, because the
   // origin trial might be active (in which case no feature flags are active).
 
-  // We only isolate HTTPS, so early-out if we see other schemes.
-  if (!origin.GetURL().SchemeIs(url::kHttpsScheme))
+  if (!IsolatedOriginUtil::IsValidOriginForOptInIsolation(origin))
     return false;
 
   base::AutoLock origins_isolation_opt_in_lock(origins_isolation_opt_in_lock_);
@@ -2153,9 +2152,7 @@
     const url::Origin& origin,
     bool is_global_walk_or_frame_removal) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  // Origin Policy only exists for HTTPS, and header-based opt-in requests are
-  // also HTTPS-only, so nothing we isolate will be HTTP.
-  if (!origin.GetURL().SchemeIs(url::kHttpsScheme))
+  if (!IsolatedOriginUtil::IsValidOriginForOptInIsolation(origin))
     return;
 
   BrowsingInstanceId browsing_instance_id(
@@ -2223,9 +2220,7 @@
 void ChildProcessSecurityPolicyImpl::AddOptInIsolatedOriginForBrowsingInstance(
     const IsolationContext& isolation_context,
     const url::Origin& origin) {
-  // Origin Policy only exists for HTTPS, so nothing we isolate will be HTTP.
-  if (!origin.GetURL().SchemeIs(url::kHttpsScheme))
-    return;
+  DCHECK(IsolatedOriginUtil::IsValidOriginForOptInIsolation(origin));
 
   BrowsingInstanceId browsing_instance_id(
       isolation_context.browsing_instance_id());
@@ -2252,11 +2247,8 @@
 
 bool ChildProcessSecurityPolicyImpl::UpdateOriginIsolationOptInListIfNecessary(
     const url::Origin& origin) {
-  // Avoid dealing with non-HTTPS and other non-valid-for-isolation origins.
-  if (!origin.GetURL().SchemeIs(url::kHttpsScheme) ||
-      !IsolatedOriginUtil::IsValidIsolatedOrigin(origin)) {
+  if (!IsolatedOriginUtil::IsValidOriginForOptInIsolation(origin))
     return false;
-  }
 
   base::AutoLock origins_isolation_opt_in_lock(origins_isolation_opt_in_lock_);
 
diff --git a/content/browser/isolated_origin_browsertest.cc b/content/browser/isolated_origin_browsertest.cc
index e607959..5fa9d0bb 100644
--- a/content/browser/isolated_origin_browsertest.cc
+++ b/content/browser/isolated_origin_browsertest.cc
@@ -297,6 +297,57 @@
   DISALLOW_COPY_AND_ASSIGN(OriginIsolationOptInHeaderTest);
 };
 
+// Used for a few tests that check non-HTTPS secure context behavior.
+class OriginIsolationOptInHttpServerHeaderTest : public IsolatedOriginTestBase {
+ public:
+  OriginIsolationOptInHttpServerHeaderTest() = default;
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    IsolatedOriginTestBase::SetUpCommandLine(command_line);
+    ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
+
+    // This is needed for this test to run properly on platforms where
+    //  --site-per-process isn't the default, such as Android.
+    IsolateAllSitesForTesting(command_line);
+
+    feature_list_.InitAndEnableFeature(features::kOriginIsolationHeader);
+
+    embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
+        &OriginIsolationOptInHttpServerHeaderTest::HandleResponse,
+        base::Unretained(this)));
+  }
+
+  void SetUpOnMainThread() override {
+    host_resolver()->AddRule("*", "127.0.0.1");
+    embedded_test_server()->StartAcceptingConnections();
+  }
+
+  bool ShouldOriginGetOptInIsolation(const url::Origin& origin) {
+    auto* site_instance = static_cast<SiteInstanceImpl*>(
+        shell()->web_contents()->GetMainFrame()->GetSiteInstance());
+
+    return ChildProcessSecurityPolicyImpl::GetInstance()
+        ->ShouldOriginGetOptInIsolation(site_instance->GetIsolationContext(),
+                                        origin,
+                                        false /* origin_requests_isolation */);
+  }
+
+ private:
+  std::unique_ptr<net::test_server::HttpResponse> HandleResponse(
+      const net::test_server::HttpRequest& request) {
+    auto response = std::make_unique<net::test_server::BasicHttpResponse>();
+    response->set_code(net::HTTP_OK);
+    response->set_content_type("text/html");
+    response->AddCustomHeader("Origin-Isolation", "?1");
+
+    response->set_content("isolate me!");
+    return std::move(response);
+  }
+
+  base::test::ScopedFeatureList feature_list_;
+  DISALLOW_COPY_AND_ASSIGN(OriginIsolationOptInHttpServerHeaderTest);
+};
+
 // This class allows testing the interaction of OptIn isolation and command-line
 // isolation for origins. Tests using this class will isolate foo.com and
 // bar.com by default using command-line isolation, but any opt-in isolation
@@ -414,6 +465,37 @@
   EXPECT_TRUE(ShouldOriginGetOptInIsolation(origin));
 }
 
+// These tests ensure that non-HTTPS secure contexts (see
+// https://w3c.github.io/webappsec-secure-contexts/#is-origin-trustworthy) are
+// able to use origin isolation.
+IN_PROC_BROWSER_TEST_F(OriginIsolationOptInHttpServerHeaderTest, Localhost) {
+  GURL url(embedded_test_server()->GetURL("localhost", "/"));
+  url::Origin origin(url::Origin::Create(url));
+
+  EXPECT_FALSE(ShouldOriginGetOptInIsolation(origin));
+  EXPECT_TRUE(NavigateToURL(shell(), url));
+  EXPECT_TRUE(ShouldOriginGetOptInIsolation(origin));
+}
+
+IN_PROC_BROWSER_TEST_F(OriginIsolationOptInHttpServerHeaderTest, DotLocalhost) {
+  GURL url(embedded_test_server()->GetURL("test.localhost", "/"));
+  url::Origin origin(url::Origin::Create(url));
+
+  EXPECT_FALSE(ShouldOriginGetOptInIsolation(origin));
+  EXPECT_TRUE(NavigateToURL(shell(), url));
+  EXPECT_TRUE(ShouldOriginGetOptInIsolation(origin));
+}
+
+IN_PROC_BROWSER_TEST_F(OriginIsolationOptInHttpServerHeaderTest,
+                       OneTwentySeven) {
+  GURL url(embedded_test_server()->GetURL("127.0.0.1", "/"));
+  url::Origin origin(url::Origin::Create(url));
+
+  EXPECT_FALSE(ShouldOriginGetOptInIsolation(origin));
+  EXPECT_TRUE(NavigateToURL(shell(), url));
+  EXPECT_TRUE(ShouldOriginGetOptInIsolation(origin));
+}
+
 // Further tests deep-dive into various scenarios for the isolation opt-ins.
 // They use the origin policy mechanism, under the assumption that it will be
 // the same for the header mechanism since they both trigger the same behavior
diff --git a/content/browser/isolated_origin_util.cc b/content/browser/isolated_origin_util.cc
index 570491a..82d72f1c 100644
--- a/content/browser/isolated_origin_util.cc
+++ b/content/browser/isolated_origin_util.cc
@@ -9,6 +9,7 @@
 #include "base/logging.h"
 #include "base/strings/string_util.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "services/network/public/cpp/is_potentially_trustworthy.h"
 #include "url/gurl.h"
 
 const char* kAllSubdomainsWildcard = "[*.]";
@@ -107,6 +108,22 @@
 
 // static
 bool IsolatedOriginUtil::IsValidIsolatedOrigin(const url::Origin& origin) {
+  return IsValidIsolatedOriginImpl(origin, true);
+}
+
+// static
+bool IsolatedOriginUtil::IsValidOriginForOptInIsolation(
+    const url::Origin& origin) {
+  // Per https://html.spec.whatwg.org/C/#initialise-the-document-object,
+  // non-secure contexts cannot be isolated via opt-in origin isolation.
+  return IsValidIsolatedOriginImpl(origin, false) &&
+         network::IsOriginPotentiallyTrustworthy(origin);
+}
+
+// static
+bool IsolatedOriginUtil::IsValidIsolatedOriginImpl(
+    const url::Origin& origin,
+    bool check_has_registry_domain) {
   if (origin.opaque())
     return false;
 
@@ -123,13 +140,19 @@
   // Disallow hosts such as http://co.uk/, which don't have a valid
   // registry-controlled domain.  This prevents subdomain matching from
   // grouping unrelated sites on a registry into the same origin.
-  const bool has_registry_domain =
-      net::registry_controlled_domains::HostHasRegistryControlledDomain(
-          origin.host(),
-          net::registry_controlled_domains::INCLUDE_UNKNOWN_REGISTRIES,
-          net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
-  if (!has_registry_domain)
-    return false;
+  //
+  // This is not relevant for opt-in origin isolation, which doesn't need to
+  // match subdomains. (And it'd be bad to check this in that case, as it
+  // prohibits http://localhost/; see https://crbug.com/1142894.)
+  if (check_has_registry_domain) {
+    const bool has_registry_domain =
+        net::registry_controlled_domains::HostHasRegistryControlledDomain(
+            origin.host(),
+            net::registry_controlled_domains::INCLUDE_UNKNOWN_REGISTRIES,
+            net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
+    if (!has_registry_domain)
+      return false;
+  }
 
   // For now, disallow hosts with a trailing dot.
   // TODO(alexmos): Enabling this would require carefully thinking about
diff --git a/content/browser/isolated_origin_util.h b/content/browser/isolated_origin_util.h
index 9486db2..4c6f4be 100644
--- a/content/browser/isolated_origin_util.h
+++ b/content/browser/isolated_origin_util.h
@@ -91,10 +91,21 @@
                                             const url::Origin& isolated_origin);
 
   // Check if |origin| is a valid isolated origin.  Invalid isolated origins
-  // include unique origins, origins that don't have an HTTP or HTTPS scheme,
+  // include opaque origins, origins that don't have an HTTP or HTTPS scheme,
   // and origins without a valid registry-controlled domain.  IP addresses are
   // allowed.
   static bool IsValidIsolatedOrigin(const url::Origin& origin);
+
+  // Check if |origin| is a valid origin for opt-in origin isolation. Invalid
+  // origins for this purpose include opaque origins, origins that don't have a
+  // HTTP or HTTPS scheme, and origins that are not secure contexts.
+  static bool IsValidOriginForOptInIsolation(const url::Origin& origin);
+
+ private:
+  // Used to implement both IsValidIsolatedOrigin and
+  // IsValidOriginForOptInIsolation.
+  static bool IsValidIsolatedOriginImpl(const url::Origin& origin,
+                                        bool check_has_registry_domain);
 };
 
 }  // namespace content
diff --git a/content/browser/loader/loader_browsertest.cc b/content/browser/loader/loader_browsertest.cc
index 5d572e86..a3f7d537 100644
--- a/content/browser/loader/loader_browsertest.cc
+++ b/content/browser/loader/loader_browsertest.cc
@@ -75,17 +75,6 @@
     host_resolver()->AddRule("*", "127.0.0.1");
   }
 
-  void WaitForTitleTest(const base::string16& expected_title,
-                        const std::vector<base::string16> additional_titles) {
-    TitleWatcher title_watcher(shell()->web_contents(), expected_title);
-
-    for (const auto& title : additional_titles) {
-      title_watcher.AlsoWaitForTitle(title);
-    }
-    base::string16 actual_title = title_watcher.WaitAndGetTitle();
-    EXPECT_EQ(expected_title, actual_title);
-  }
-
   void CheckTitleTest(const GURL& url, const std::string& expected_title) {
     base::string16 expected_title16(ASCIIToUTF16(expected_title));
     TitleWatcher title_watcher(shell()->web_contents(), expected_title16);
@@ -652,7 +641,8 @@
 // Creates a valid filesystem URL.
 GURL CreateFileSystemURL(Shell* window) {
   std::string filesystem_url_string;
-  EXPECT_TRUE(ExecuteScriptAndExtractString(window, R"(
+  EXPECT_TRUE(
+      ExecuteScriptAndExtractString(window, R"(
       var blob = new Blob(['<html><body>hello</body></html>'],
                           {type: 'text/html'});
       window.webkitRequestFileSystem(TEMPORARY, blob.size, fs => {
@@ -664,8 +654,7 @@
             }
           });
         });
-      });)",
-                                            &filesystem_url_string));
+      });)", &filesystem_url_string));
   GURL filesystem_url(filesystem_url_string);
   EXPECT_TRUE(filesystem_url.is_valid());
   EXPECT_TRUE(filesystem_url.SchemeIsFileSystem());
@@ -1277,31 +1266,4 @@
   SetBrowserClientForTesting(old_content_browser_client);
 }
 
-IN_PROC_BROWSER_TEST_F(LoaderBrowserTest, FetchUpload150MB) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-  ASSERT_TRUE(
-      NavigateToURL(shell(), embedded_test_server()->GetURL("/title2.html")));
-  EXPECT_EQ(shell()->web_contents()->GetTitle(), ASCIIToUTF16("Title Of Awesomeness"));
-
-  ASSERT_TRUE(ExecuteScript(
-      shell(), base::StringPrintf(R"JS(
-    const length = 150*1000*1000; // 150 MB;
-    async function run() {
-      const array = new Uint8Array(length);
-      const response = await fetch('%s', { method: 'POST', body: array });
-      const text = await response.text();
-      if (text != length.toString())
-        throw `Content-Length actual:${text}, expected:${length.toString()}.`
-    };
-    run().then(() => { document.title = 'PASS'; },
-            (e) => { console.log(e); document.title = 'FAIL'; });
-)JS",
-                                  embedded_test_server()
-                                      ->GetURL("/echoheader?Content-Length")
-                                      .spec()
-                                      .c_str())));
-
-  WaitForTitleTest(ASCIIToUTF16("PASS"), {ASCIIToUTF16("FAIL")});
-}
-
 }  // namespace content
diff --git a/content/browser/loader/prefetch_url_loader_service.cc b/content/browser/loader/prefetch_url_loader_service.cc
index 66fc3ba..951a6b6 100644
--- a/content/browser/loader/prefetch_url_loader_service.cc
+++ b/content/browser/loader/prefetch_url_loader_service.cc
@@ -5,7 +5,6 @@
 #include "content/browser/loader/prefetch_url_loader_service.h"
 
 #include "base/bind.h"
-#include "base/debug/dump_without_crashing.h"
 #include "base/feature_list.h"
 #include "base/time/default_tick_clock.h"
 #include "content/browser/loader/prefetch_url_loader.h"
@@ -28,14 +27,6 @@
 #include "third_party/blink/public/common/renderer_preferences/renderer_preferences.h"
 #include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h"
 
-namespace {
-void DumpWithoutCrashing(const network::ResourceRequest& request) {
-  DEBUG_ALIAS_FOR_GURL(prefetch_buf, request.url);
-  DEBUG_ALIAS_FOR_GURL(initiator_buf, request.request_initiator->GetURL());
-  base::debug::DumpWithoutCrashing();
-}
-}  // namespace
-
 namespace content {
 
 struct PrefetchURLLoaderService::BindContext {
@@ -170,18 +161,9 @@
 
   // Recursive prefetch from a cross-origin main resource prefetch.
   if (resource_request.recursive_prefetch_token) {
-    // A request's |recursive_prefetch_token| is only provided if the request is
-    // a recursive prefetch. This means it is expected that the current
-    // context's |cross_origin_factory| was already created.
+    // TODO(crbug.com/1123715): Figure out why we're seeing this condition hold
+    // true in the field.
     if (!current_context.cross_origin_factory) {
-      // This could happen due to a compromised renderer passing in a recursive
-      // prefetch token for a request that's not a recursive prefetch. Cancel
-      // the request.
-      DVLOG(1) << "Recursive prefetch token unexpectedly set.";
-      DumpWithoutCrashing(resource_request);
-      mojo::Remote<network::mojom::URLLoaderClient>(std::move(client))
-          ->OnComplete(
-              network::URLLoaderCompletionStatus(net::ERR_INVALID_ARGUMENT));
       return;
     }
 
@@ -195,8 +177,6 @@
     // a request in a special way. We'll cancel the request.
     if (isolation_info_iterator ==
         current_context.prefetch_isolation_infos.end()) {
-      DVLOG(1) << "Recursive prefetch request is missing prefetch isolation";
-      DumpWithoutCrashing(resource_request);
       mojo::Remote<network::mojom::URLLoaderClient>(std::move(client))
           ->OnComplete(
               network::URLLoaderCompletionStatus(net::ERR_INVALID_ARGUMENT));
diff --git a/content/browser/renderer_host/back_forward_cache_metrics.cc b/content/browser/renderer_host/back_forward_cache_metrics.cc
index f40cc17b..db9f089 100644
--- a/content/browser/renderer_host/back_forward_cache_metrics.cc
+++ b/content/browser/renderer_host/back_forward_cache_metrics.cc
@@ -123,6 +123,7 @@
 
     not_restored_reasons_.reset();
     blocklisted_features_ = 0;
+    browsing_instance_not_swapped_reason_.reset();
     disabled_reasons_.clear();
     previous_navigation_is_served_from_bfcache_ =
         navigation->IsServedFromBackForwardCache();
diff --git a/content/browser/renderer_host/clipboard_host_impl.cc b/content/browser/renderer_host/clipboard_host_impl.cc
index 49ef41a..4680b24 100644
--- a/content/browser/renderer_host/clipboard_host_impl.cc
+++ b/content/browser/renderer_host/clipboard_host_impl.cc
@@ -25,8 +25,8 @@
 #include "ui/base/clipboard/clipboard_constants.h"
 #include "ui/base/clipboard/clipboard_format_type.h"
 #include "ui/base/clipboard/custom_data_helper.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
 #include "ui/base/clipboard/scoped_clipboard_writer.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 #include "url/gurl.h"
 
 namespace content {
diff --git a/content/browser/renderer_host/input/touch_selection_controller_client_aura.cc b/content/browser/renderer_host/input/touch_selection_controller_client_aura.cc
index 20fe7e3..bf4d52f8 100644
--- a/content/browser/renderer_host/input/touch_selection_controller_client_aura.cc
+++ b/content/browser/renderer_host/input/touch_selection_controller_client_aura.cc
@@ -18,7 +18,7 @@
 #include "ui/aura/env.h"
 #include "ui/aura/window.h"
 #include "ui/base/clipboard/clipboard.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 #include "ui/base/pointer/touch_editing_controller.h"
 #include "ui/events/event_observer.h"
 #include "ui/gfx/geometry/point_conversions.h"
diff --git a/content/browser/renderer_host/input/touch_selection_controller_client_child_frame.cc b/content/browser/renderer_host/input/touch_selection_controller_client_child_frame.cc
index 1ef79d5..9902656 100644
--- a/content/browser/renderer_host/input/touch_selection_controller_client_child_frame.cc
+++ b/content/browser/renderer_host/input/touch_selection_controller_client_child_frame.cc
@@ -12,7 +12,7 @@
 #include "content/public/browser/touch_selection_controller_client_manager.h"
 #include "content/public/common/use_zoom_for_dsf_policy.h"
 #include "ui/base/clipboard/clipboard.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 #include "ui/base/pointer/touch_editing_controller.h"
 #include "ui/base/ui_base_types.h"
 #include "ui/gfx/geometry/point_conversions.h"
diff --git a/content/browser/renderer_host/raw_clipboard_host_impl.cc b/content/browser/renderer_host/raw_clipboard_host_impl.cc
index c8d217a..b02ba07 100644
--- a/content/browser/renderer_host/raw_clipboard_host_impl.cc
+++ b/content/browser/renderer_host/raw_clipboard_host_impl.cc
@@ -19,8 +19,8 @@
 #include "third_party/blink/public/mojom/permissions/permission_status.mojom-shared.h"
 #include "ui/base/clipboard/clipboard.h"
 #include "ui/base/clipboard/clipboard_format_type.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
 #include "ui/base/clipboard/scoped_clipboard_writer.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 
 namespace content {
 
diff --git a/content/browser/resources/appcache/appcache_internals.html b/content/browser/resources/appcache/appcache_internals.html
index f8ab596..a194894 100644
--- a/content/browser/resources/appcache/appcache_internals.html
+++ b/content/browser/resources/appcache/appcache_internals.html
@@ -126,6 +126,7 @@
     <div class="content">
       <div id="appcache-list">
       </div>
+      <script src="chrome://resources/js/assert.js"></script>
       <script src="chrome://resources/js/util.js"></script>
       <script src="chrome://resources/js/cr.js"></script>
       <script src="appcache_internals.js"></script>
diff --git a/content/browser/resources/conversions/conversion_internals.html b/content/browser/resources/conversions/conversion_internals.html
index 4513c8b..1060896f 100644
--- a/content/browser/resources/conversions/conversion_internals.html
+++ b/content/browser/resources/conversions/conversion_internals.html
@@ -7,6 +7,7 @@
   <meta charset="utf-8">
   <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
   <link rel="stylesheet" href="chrome://resources/css/roboto.css">
+  <script src="chrome://resources/js/assert.js"></script>
   <script src="chrome://resources/js/util.js"></script>
   <script src="chrome://resources/js/cr.js"></script>
   <script src="chrome://resources/js/cr/ui.js"></script>
diff --git a/content/browser/resources/gpu/gpu_internals.html b/content/browser/resources/gpu/gpu_internals.html
index 2fb72b5..d29a1a0 100644
--- a/content/browser/resources/gpu/gpu_internals.html
+++ b/content/browser/resources/gpu/gpu_internals.html
@@ -36,6 +36,7 @@
 <script src="chrome://resources/js/cr/ui.js"></script>
 <script src="chrome://resources/js/cr/ui/focus_outline_manager.js"></script>
 <script src="chrome://resources/js/load_time_data.js"></script>
+<script src="chrome://resources/js/assert.js"></script>
 <script src="chrome://resources/js/util.js"></script>
 <script src="chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js"></script>
 <script src="chrome://resources/gpu/ipc/common/vulkan_types.mojom-lite.js"></script>
diff --git a/content/browser/resources/histograms/histograms_internals.html b/content/browser/resources/histograms/histograms_internals.html
index 4e224a80..480bf33 100644
--- a/content/browser/resources/histograms/histograms_internals.html
+++ b/content/browser/resources/histograms/histograms_internals.html
@@ -6,6 +6,7 @@
 <head>
   <meta charset="utf-8">
   <script src="chrome://resources/js/cr.js"></script>
+  <script src="chrome://resources/js/assert.js"></script>
   <script src="chrome://resources/js/promise_resolver.js"></script>
   <script src="chrome://resources/js/util.js"></script>
   <script src="histograms_internals.js"></script>
diff --git a/content/browser/resources/indexed_db/indexeddb_internals.html b/content/browser/resources/indexed_db/indexeddb_internals.html
index 22846a8..c8aef91 100644
--- a/content/browser/resources/indexed_db/indexeddb_internals.html
+++ b/content/browser/resources/indexed_db/indexeddb_internals.html
@@ -166,6 +166,7 @@
     <div class="content">
         <div id="indexeddb-list">
     </div>
+    <script src="chrome://resources/js/assert.js"></script>
     <script src="chrome://resources/js/util.js"></script>
     <script src="chrome://resources/js/cr.js"></script>
     <script src="indexeddb_internals.js"></script>
diff --git a/content/browser/resources/media/media_internals.html b/content/browser/resources/media/media_internals.html
index 290a90a..763af3f 100644
--- a/content/browser/resources/media/media_internals.html
+++ b/content/browser/resources/media/media_internals.html
@@ -13,6 +13,7 @@
   <script src="chrome://resources/js/cr.js"></script>
   <script src="chrome://resources/js/cr/ui.js"></script>
   <script src="chrome://resources/js/cr/ui/focus_outline_manager.js"></script>
+  <script src="chrome://resources/js/assert.js"></script>
   <script src="chrome://resources/js/util.js"></script>
   <script src="chrome://resources/js/cr/ui/tabs.js"></script>
   <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
diff --git a/content/browser/resources/net/network_errors_listing.html b/content/browser/resources/net/network_errors_listing.html
index f990b33..d64c942 100644
--- a/content/browser/resources/net/network_errors_listing.html
+++ b/content/browser/resources/net/network_errors_listing.html
@@ -14,6 +14,7 @@
   <link rel="stylesheet" href="network_errors_listing.css">
   <script src="chrome://resources/js/cr.js"></script>
   <script src="chrome://resources/js/load_time_data.js"></script>
+  <script src="chrome://resources/js/assert.js"></script>
   <script src="chrome://resources/js/util.js"></script>
   <script src="strings.js"></script>
   <script src="network_errors_listing.js"></script>
diff --git a/content/browser/resources/process/process_internals.html b/content/browser/resources/process/process_internals.html
index 39d1bc8..fdebf2b 100644
--- a/content/browser/resources/process/process_internals.html
+++ b/content/browser/resources/process/process_internals.html
@@ -6,6 +6,7 @@
 <head>
   <meta charset="utf-8">
   <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
+  <script src="chrome://resources/js/assert.js"></script>
   <script src="chrome://resources/js/util.js"></script>
   <script src="chrome://resources/js/cr.js"></script>
   <script src="chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js">
diff --git a/content/browser/resources/service_worker/serviceworker_internals.html b/content/browser/resources/service_worker/serviceworker_internals.html
index 064716b..34d2927 100644
--- a/content/browser/resources/service_worker/serviceworker_internals.html
+++ b/content/browser/resources/service_worker/serviceworker_internals.html
@@ -153,6 +153,7 @@
     <div id="serviceworker-options"></div>
     <div id="serviceworker-list"></div>
   </div>
+  <script src="chrome://resources/js/assert.js"></script>
   <script src="chrome://resources/js/util.js"></script>
   <script src="chrome://resources/js/cr.js"></script>
   <script src="serviceworker_internals.js"></script>
diff --git a/content/test/data/media/peerconnection-call.html b/content/test/data/media/peerconnection-call.html
index 67e47fa..f354ed7 100644
--- a/content/test/data/media/peerconnection-call.html
+++ b/content/test/data/media/peerconnection-call.html
@@ -90,18 +90,9 @@
         .then(addStreamToBothConnectionsAndNegotiate)
         .catch(failTest);
 
-    function hasExpectedResolution(elementName) {
-      // Returns a promise that video is playing and has the expected
-      // resolution.
-      return detectVideoPlaying('remote-view-1').then(resolution => {
-        assertEquals(expected_width, resolution.width);
-        assertEquals(expected_height, resolution.height);
-      });
-    }
-
     Promise.all([
-      hasExpectedResolution('remote-view-1'),
-      hasExpectedResolution('remote-view-2')
+      detectVideoPlayingWithExpectedResolution('remote-view-1', expected_width, expected_height),
+      detectVideoPlayingWithExpectedResolution('remote-view-2', expected_width, expected_height)
     ]).then(reportTestSuccess);
   }
 
diff --git a/content/test/data/media/webrtc_test_utilities.js b/content/test/data/media/webrtc_test_utilities.js
index 9f15c92..13e4d68 100644
--- a/content/test/data/media/webrtc_test_utilities.js
+++ b/content/test/data/media/webrtc_test_utilities.js
@@ -46,6 +46,15 @@
   gPendingTimeout = null;
 }
 
+function detectVideoPlayingWithExpectedResolution(
+    videoElementName, video_width, video_height) {
+  return detectVideo(
+      videoElementName, function(pixels, previous_pixels, videoElement) {
+        return hasExpectedResolution(videoElement, video_width, video_height) &&
+            isVideoPlaying(pixels, previous_pixels);
+      });
+}
+
 function detectVideoPlaying(videoElementName) {
   return detectVideo(videoElementName, isVideoPlaying);
 }
@@ -110,7 +119,8 @@
       // that case.
       // There's a failure(?) mode here where the video generated claims to
       // have size 2x2. Don't consider that a valid video.
-      if (oldPixels.length == pixels.length && predicate(pixels, oldPixels)) {
+      if (oldPixels.length == pixels.length &&
+          predicate(pixels, oldPixels, videoElement)) {
         console.log('Done looking at video in element ' + videoElementName);
         console.log('DEBUG: video.width = ' + videoElement.videoWidth);
         console.log('DEBUG: video.height = ' + videoElement.videoHeight);
@@ -155,6 +165,11 @@
   });
 }
 
+function hasExpectedResolution(videoElement, expected_width, expected_height) {
+  return videoElement.videoWidth == expected_width &&
+      videoElement.videoHeight == expected_height;
+}
+
 // This very basic video verification algorithm will be satisfied if any
 // pixels are changed.
 function isVideoPlaying(pixels, previousPixels) {
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
index 4792726..b09671c 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
@@ -218,16 +218,16 @@
 ####################
 
 # GPU process crashes / Timed out tests
-crbug.com/1136367 [ fuchsia ] conformance/extensions/webgl-compressed-texture-size-limit.html [ Skip ]
-crbug.com/1136367 [ fuchsia ] conformance/textures/misc/texture-size.html [ Skip ]
-crbug.com/1136367 [ fuchsia ] conformance/textures/misc/texture-size-cube-maps.html [ Skip ]
-crbug.com/1136367 [ fuchsia ] conformance/textures/misc/texture-sub-image-cube-maps.html [ Skip ]
-crbug.com/1136367 [ fuchsia ] conformance/uniforms/uniform-default-values.html [ Skip ]
-crbug.com/1136369 [ fuchsia ] conformance/glsl/misc/shader-with-non-reserved-words.html [ Skip ]
-crbug.com/1136369 [ fuchsia ] conformance/uniforms/uniform-samplers-test.html [ Skip ]
-crbug.com/1136369 [ fuchsia ] deqp/data/gles2/shaders/conversions.html [ Skip ]
-crbug.com/1136369 [ fuchsia ] deqp/data/gles2/shaders/functions.html [ Skip ]
-crbug.com/1136369 [ fuchsia ] deqp/data/gles2/shaders/swizzles.html [ Skip ]
+crbug.com/1143408 [ fuchsia ] conformance/extensions/webgl-compressed-texture-size-limit.html [ Skip ]
+crbug.com/1143408 [ fuchsia ] conformance/textures/misc/texture-size.html [ Skip ]
+crbug.com/angleproject/2930 [ fuchsia ] conformance/textures/misc/texture-size-cube-maps.html [ Skip ]
+crbug.com/angleproject/3481 [ fuchsia ] conformance/textures/misc/texture-sub-image-cube-maps.html [ Skip ]
+crbug.com/angleproject/5259 [ fuchsia ] conformance/uniforms/uniform-default-values.html [ Skip ]
+crbug.com/1143392 [ fuchsia ] conformance/glsl/misc/shader-with-non-reserved-words.html [ Skip ]
+crbug.com/871352 [ fuchsia ] conformance/uniforms/uniform-samplers-test.html [ Skip ]
+crbug.com/1143424 [ fuchsia ] deqp/data/gles2/shaders/conversions.html [ Skip ]
+crbug.com/478572 [ fuchsia ] deqp/data/gles2/shaders/functions.html [ Skip ]
+crbug.com/angleproject/3111 [ fuchsia ] deqp/data/gles2/shaders/swizzles.html [ Skip ]
 
 # Video not supported on Fuchsia qemu boards.
 [ fuchsia fuchsia-board-qemu-x64 ] conformance/extensions/oes-texture-float-with-video.html [ Skip ]
@@ -283,7 +283,7 @@
 crbug.com/626524 [ win nvidia no-passthrough ] conformance/textures/misc/texture-npot-video.html [ RetryOnFailure ]
 crbug.com/630860 [ win nvidia ] conformance/textures/misc/texture-upload-size.html [ RetryOnFailure ]
 crbug.com/1045339 [ win10 debug-x64 nvidia ] conformance/extensions/oes-texture-half-float-with-video.html [ Skip ]
-crbug.com/1109977 [ win nvidia passthrough ] conformance/glsl/misc/shader-with-non-reserved-words.html [ Skip ]
+crbug.com/1143392 [ win nvidia passthrough ] conformance/glsl/misc/shader-with-non-reserved-words.html [ Skip ]
 
 # Win10 / NVIDIA Quadro P400 / D3D11 failures
 crbug.com/898674 [ win10 nvidia-0x1cb3 angle-d3d11 ] conformance/extensions/oes-texture-float-with-video.html [ RetryOnFailure ]
@@ -514,7 +514,7 @@
 crbug.com/1018028 [ linux amd-0x6613 ] conformance/rendering/bind-framebuffer-flush-bug.html [ Failure ]
 
 # Linux passthrough AMD
-crbug.com/960808 [ linux amd passthrough ] conformance/glsl/misc/shader-with-non-reserved-words.html [ Failure ]
+crbug.com/1143392 [ linux amd passthrough ] conformance/glsl/misc/shader-with-non-reserved-words.html [ Failure ]
 crbug.com/998498 [ linux amd passthrough ] conformance/textures/misc/tex-input-validation.html [ Failure ]
 
 # Linux passthrough AMD OpenGL
@@ -523,7 +523,7 @@
 crbug.com/1028639 [ linux amd angle-opengl passthrough ] conformance/ogles/GL/mat/mat_009_to_016.html [ Failure ]
 crbug.com/1028639 [ linux amd angle-opengl passthrough ] conformance/ogles/GL/log2/log2_009_to_012.html [ Failure ]
 crbug.com/1060632 [ linux amd angle-opengl passthrough ] conformance/more/functions/bindBuffer.html [ RetryOnFailure ]
-crbug.com/angleproject/5213 [ linux amd-0x6613 angle-opengl passthrough ] conformance/context/deleted-object-behavior.html [ RetryOnFailure ]
+crbug.com/angleproject/5213 [ linux amd-0x6613 angle-opengl passthrough ] conformance/context/deleted-object-behavior.html [ Failure ]
 crbug.com/angleproject/5213 [ linux amd-0x6613 angle-opengl passthrough ] conformance/renderbuffers/renderbuffer-initialization.html [ Failure ]
 
 ####################
@@ -710,6 +710,7 @@
 crbug.com/981579 [ android angle-opengles ] conformance/textures/misc/tex-video-using-tex-unit-non-zero.html [ RetryOnFailure ]
 crbug.com/906724 [ android angle-opengles ] conformance/textures/video/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html [ Failure ]
 crbug.com/906724 [ android angle-opengles ] conformance/textures/video/tex-2d-luminance-luminance-unsigned_byte.html [ Failure ]
+crbug.com/1143323 [ android angle-opengles ] conformance/rendering/draw-arrays-out-of-bounds.html [ Failure ]
 
 # Misc failures
 crbug.com/angleproject/2988 [ android angle-opengles ] conformance/context/context-size-change.html [ Failure ]
diff --git a/content/web_test/browser/web_test_control_host.cc b/content/web_test/browser/web_test_control_host.cc
index 053b789..0f5e6ad 100644
--- a/content/web_test/browser/web_test_control_host.cc
+++ b/content/web_test/browser/web_test_control_host.cc
@@ -36,6 +36,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "cc/paint/skia_paint_canvas.h"
+#include "content/browser/renderer_host/navigation_request.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/child_process_security_policy.h"
 #include "content/public/browser/child_process_termination_info.h"
@@ -619,7 +620,7 @@
   main_window_->ActivateContents(main_window_->web_contents());
 
   RenderViewHost* main_render_view_host =
-      main_window_->web_contents()->GetRenderViewHost();
+      main_window_->web_contents()->GetMainFrame()->GetRenderViewHost();
   {
     TRACE_EVENT0("shell", "WebTestControlHost::PrepareForWebTest::Flush");
     // Round-trip through the InputHandler mojom interface to the compositor
@@ -836,8 +837,10 @@
 }
 
 void WebTestControlHost::TestFinishedInSecondaryRenderer() {
-  GetWebTestRenderThreadRemote(
-      main_window_->web_contents()->GetRenderViewHost()->GetProcess())
+  GetWebTestRenderThreadRemote(main_window_->web_contents()
+                                   ->GetMainFrame()
+                                   ->GetRenderViewHost()
+                                   ->GetProcess())
       ->TestFinishedFromSecondaryRenderer();
 }
 
@@ -1076,10 +1079,25 @@
   }
 }
 
+void WebTestControlHost::RenderViewHostChanged(RenderViewHost* old_host,
+                                               RenderViewHost* new_host) {
+  // Notifies the main frame of |old_host| that it is deactivated while it's
+  // kept alive in back-forward cache.
+  GetWebTestRenderFrameRemote(old_host->GetMainFrame())->OnDeactivated();
+}
+
 void WebTestControlHost::RenderViewDeleted(RenderViewHost* render_view_host) {
   main_window_render_view_hosts_.erase(render_view_host);
 }
 
+void WebTestControlHost::DidFinishNavigation(
+    NavigationHandle* navigation_handle) {
+  NavigationRequest* request = NavigationRequest::From(navigation_handle);
+  RenderFrameHostImpl* rfh = request->rfh_restored_from_back_forward_cache();
+  if (rfh)
+    GetWebTestRenderFrameRemote(rfh)->OnReactivated();
+}
+
 void WebTestControlHost::RenderProcessHostDestroyed(
     RenderProcessHost* render_process_host) {
   render_process_host_observer_.Remove(render_process_host);
@@ -1768,8 +1786,10 @@
   if (main_window_) {
     main_window_->web_contents()->Stop();
 
-    RenderProcessHost* main_frame_process =
-        main_window_->web_contents()->GetRenderViewHost()->GetProcess();
+    RenderProcessHost* main_frame_process = main_window_->web_contents()
+                                                ->GetMainFrame()
+                                                ->GetRenderViewHost()
+                                                ->GetProcess();
     GetWebTestRenderThreadRemote(main_frame_process)
         ->ResetRendererAfterWebTest(
             base::BindOnce(&WebTestControlHost::ResetRendererAfterWebTestDone,
@@ -1789,7 +1809,8 @@
     if (!check_for_leaked_windows_)
       CloseTestOpenedWindows();
 
-    RenderViewHost* rvh = main_window_->web_contents()->GetRenderViewHost();
+    RenderViewHost* rvh =
+        main_window_->web_contents()->GetMainFrame()->GetRenderViewHost();
     RenderProcessHost* rph = rvh->GetProcess();
     CHECK(rph->GetProcess().IsValid());
     leak_detector_->TryLeakDetection(
diff --git a/content/web_test/browser/web_test_control_host.h b/content/web_test/browser/web_test_control_host.h
index 1bf370c..87aabadf 100644
--- a/content/web_test/browser/web_test_control_host.h
+++ b/content/web_test/browser/web_test_control_host.h
@@ -159,7 +159,10 @@
   void DidUpdateFaviconURL(
       RenderFrameHost* render_frame_host,
       const std::vector<blink::mojom::FaviconURLPtr>& candidates) override;
+  void RenderViewHostChanged(RenderViewHost* old_host,
+                             RenderViewHost* new_host) override;
   void RenderViewDeleted(RenderViewHost* render_view_host) override;
+  void DidFinishNavigation(NavigationHandle* navigation_handle) override;
 
   // RenderProcessHostObserver implementation.
   void RenderProcessHostDestroyed(
diff --git a/content/web_test/common/web_test.mojom b/content/web_test/common/web_test.mojom
index 8a83c41..499b6b06 100644
--- a/content/web_test/common/web_test.mojom
+++ b/content/web_test/common/web_test.mojom
@@ -109,6 +109,14 @@
   // RenderViews created to host frames for the main window, either as OOPIFs or
   // to handle cross-site navigations.
   SetTestConfiguration(WebTestRunTestConfiguration config, bool starting_test);
+
+  // Notifies a frame that has been navigated away. This is called only on main
+  // frames to remove the frame from TestRunner's management list.
+  OnDeactivated();
+
+  // Notifies a frame that has been restored from backward/forward cache.
+  // This is called on main frames to add them to TestRunner's management list.
+  OnReactivated();
 };
 
 // Web test messages related runtime flags sent from the browser process to the
diff --git a/content/web_test/renderer/test_runner.cc b/content/web_test/renderer/test_runner.cc
index 8b98e331..dcf08b7 100644
--- a/content/web_test/renderer/test_runner.cc
+++ b/content/web_test/renderer/test_runner.cc
@@ -2564,6 +2564,38 @@
     work_queue_.RequestWork();
 }
 
+void TestRunner::OnFrameDeactivated(WebFrameTestProxy* frame) {
+  if (!test_is_running_)
+    return;
+
+  DCHECK(frame->IsMainFrame());
+  RemoveMainFrame(frame);
+  RemoveRenderView(frame->GetWebViewTestProxy());
+}
+
+void TestRunner::OnFrameReactivated(WebFrameTestProxy* frame) {
+  if (!test_is_running_)
+    return;
+
+  DCHECK(frame->IsMainFrame());
+
+  // A WorkQueueItem that navigates reports that it will start a load, but when
+  // a frame comes from the back/forward cache, it is already loaded so
+  // AddLoadingFrame() will not occur. This informs the system that the load is
+  // complete, or will in fact not start so that the TestRunner does not wait
+  // for this frame to end the test. At this point the frame has already had a
+  // chance to run script and insert further WorkQueueItems or other state that
+  // would delay ending the test, if it wished to.
+  frame_will_start_load_ = false;
+
+  AddMainFrame(frame);
+  WebViewTestProxy* view_proxy = frame->GetWebViewTestProxy();
+  AddRenderView(view_proxy);
+  if (view_proxy->is_main_window()) {
+    work_queue_.RequestWork();
+  }
+}
+
 void TestRunner::FinishTestIfReady() {
   if (!test_is_running_)
     return;
diff --git a/content/web_test/renderer/test_runner.h b/content/web_test/renderer/test_runner.h
index 25ba0aa..3e9c0ad 100644
--- a/content/web_test/renderer/test_runner.h
+++ b/content/web_test/renderer/test_runner.h
@@ -211,6 +211,12 @@
   // requests in WorkQueue.
   void RemoveLoadingFrame(blink::WebFrame* frame);
 
+  // Called when a main frame has been navigated away.
+  void OnFrameDeactivated(WebFrameTestProxy* frame);
+
+  // Called when a main frame has been restored from backward/forward cache.
+  void OnFrameReactivated(WebFrameTestProxy* frame);
+
   void PolicyDelegateDone();
   bool PolicyDelegateEnabled() const;
   bool PolicyDelegateIsPermissive() const;
diff --git a/content/web_test/renderer/web_frame_test_proxy.cc b/content/web_test/renderer/web_frame_test_proxy.cc
index 8b48994..8833d4f 100644
--- a/content/web_test/renderer/web_frame_test_proxy.cc
+++ b/content/web_test/renderer/web_frame_test_proxy.cc
@@ -715,6 +715,14 @@
   RenderFrameImpl::DidClearWindowObject();
 }
 
+void WebFrameTestProxy::OnDeactivated() {
+  test_runner()->OnFrameDeactivated(this);
+}
+
+void WebFrameTestProxy::OnReactivated() {
+  test_runner()->OnFrameReactivated(this);
+}
+
 WebWidgetTestProxy* WebFrameTestProxy::GetLocalRootWebWidgetTestProxy() {
   return static_cast<WebWidgetTestProxy*>(GetLocalRootRenderWidget());
 }
diff --git a/content/web_test/renderer/web_frame_test_proxy.h b/content/web_test/renderer/web_frame_test_proxy.h
index e9c7d60..cce82d6 100644
--- a/content/web_test/renderer/web_frame_test_proxy.h
+++ b/content/web_test/renderer/web_frame_test_proxy.h
@@ -82,14 +82,16 @@
       blink::WebSetSinkIdCompleteCallback completion_callback) override;
   void DidClearWindowObject() override;
 
- private:
   // mojom::WebTestRenderFrame implementation.
   void SynchronouslyCompositeAfterTest(
       SynchronouslyCompositeAfterTestCallback callback) override;
   void DumpFrameLayout(DumpFrameLayoutCallback callback) override;
   void SetTestConfiguration(mojom::WebTestRunTestConfigurationPtr config,
                             bool starting_test) override;
+  void OnDeactivated() override;
+  void OnReactivated() override;
 
+ private:
   void BindReceiver(
       mojo::PendingAssociatedReceiver<mojom::WebTestRenderFrame> receiver);
 
diff --git a/docs/fuchsia_build_instructions.md b/docs/fuchsia_build_instructions.md
index 542b7b28..ba27e01 100644
--- a/docs/fuchsia_build_instructions.md
+++ b/docs/fuchsia_build_instructions.md
@@ -161,7 +161,7 @@
 `use_goma=true` is fine to use also if you're a Googler.
 
 Architecture options are x64 (default) and arm64. This can be set with
-`target_cpu=arm64`.
+`target_cpu=\"arm64\"`.
 
 ## Build
 
diff --git a/docs/ios/working_with_files.md b/docs/ios/working_with_files.md
index 37a74a8..f794979 100644
--- a/docs/ios/working_with_files.md
+++ b/docs/ios/working_with_files.md
@@ -111,16 +111,16 @@
 internally in the XCode project. As with adding a file, different tools are used
 for each of these. Unlike creating a file, which starts with actually adding a
 file to the filesystem, a rename starts with updating git (via `git mv`), then
-using the `mass_rename` tool to update file contents.
+using the `mass-rename` tool to update file contents.
 
-`tools/git/mass_rename.py` works by looking at _uncommitted_ file moves in git,
+`tools/git/mass-rename.py` works by looking at _uncommitted_ file moves in git,
 and then updating all includes, header guards, and BUILD.gn entries to use the
 new name. It doesn't update some other files, such as `Contents.json` files for
 image assets. It also doesn't change any symbols in code, so class and variable
 names won't be changed.
 
 For many file moves, it will be simpler to use another tool,
-`tools/git/move_source_file.py`, which combines `git mv` and `mass_rename` in a
+`tools/git/move_source_file.py`, which combines `git mv` and `mass-rename` in a
 single action. For example, renaming `feature_class` to `renamed_class` would be
 done like this:
 ```bash
@@ -152,7 +152,7 @@
 1.  Commit all changes (`git commit -a -m <your comment>`).
 
 A move—where a file is moved to a different directory—is in most respects
-performed using the same steps as a rename. However, while `mass_rename.py` (and
+performed using the same steps as a rename. However, while `mass-rename.py` (and
 thus `move_source_file.py`) will update existing file names in `BUILD.gn` files,
 it won't move entries from one `BUILD.gn` file to another. To move files to a
 different directory, the preceding procedure is used, but between steps 2 and 3
@@ -165,7 +165,7 @@
 files without renaming to a new directory in a single command:
 
 ```bash
-$ tools/git/mass_rename.py ios/chrome/browser/some_feature/feature_class.* \
+$ tools/git/mass-rename.py ios/chrome/browser/some_feature/feature_class.* \
     ios/chrome/browser/some_feature/feature_class_unittest.mm \
     ios/chrome/browser/other_feature/
 ```
diff --git a/docs/security/side-channel-threat-model.md b/docs/security/side-channel-threat-model.md
index 888baad..afe54be 100644
--- a/docs/security/side-channel-threat-model.md
+++ b/docs/security/side-channel-threat-model.md
@@ -208,11 +208,7 @@
 ###### Flash
 
 Click To Play greatly reduces the risk that Flash-borne Spectre (and other)
-exploits will be effective at scale.  Additionally, the enterprise policies
-[PluginsBlockedForUrls](https://cloud.google.com/docs/chrome-enterprise/policies/?policy=PluginsBlockedForUrls)
-and
-[PluginsAllowedForUrls](https://cloud.google.com/docs/chrome-enterprise/policies/?policy=PluginsAllowedForUrls)
-can be combined to restrict Flash to specific websites.
+exploits will be effective at scale.
 Even so,
 [we might want to consider teaching CORB about Flash flavour of CORS](https://crbug.com/816318).
 
diff --git a/docs/speed/metrics_changelog/2020_10_cls.md b/docs/speed/metrics_changelog/2020_10_cls.md
index 12d3ce4..62212c3 100644
--- a/docs/speed/metrics_changelog/2020_10_cls.md
+++ b/docs/speed/metrics_changelog/2020_10_cls.md
@@ -58,6 +58,19 @@
 viewport will see large regressions in their Cumulative Layout Shift scores
 until the fix rolls out to stable.
 
+### My CLS score regressed in M86. Is that a result of the above-mentioned issue?
+
+You can test the fix on [Chrome Canary](https://www.google.com/chrome/canary/) version
+88.0.4307.0 or later. You can navigate to `chrome://version` (by typing that in
+the URL bar) to verify your browser's version. Either the
+[JavaScript implementation](https://web.dev/cls/#measure-cls-in-javascript) or the
+[Chrome Extension](https://chrome.google.com/webstore/detail/web-vitals/ahfhijdlegdabablpippeagghigmibma?hl=en)
+can be used to check the Cumulative Layout Shift score on both canary and stable
+channels.
+
+If your CLS score returns to expected levels with the fix, there is no need to
+make changes to your site to address the metric changes in Chrome 86.
+
 ## When were users affected?
 
 Most users were updated to Chrome 86 the week of October 19, 2020.
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index 8a57c4d..2051360 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -1585,6 +1585,7 @@
   DECLARATIVENETREQUEST_GETAVAILABLESTATICRULECOUNT = 1522,
   CHROMEOSINFOPRIVATE_ISTABLETMODEENABLED = 1523,
   FILEMANAGERPRIVATEINTERNAL_GETARCDOCUMENTSPROVIDERTHUMBNAIL = 1524,
+  ACCESSIBILITY_PRIVATE_ISFEATUREENABLED = 1525,
   // Last entry: Add new entries above, then run:
   // python tools/metrics/histograms/update_extension_histograms.py
   ENUM_BOUNDARY
diff --git a/extensions/browser/renderer_startup_helper.cc b/extensions/browser/renderer_startup_helper.cc
index 2bb249f..8709079 100644
--- a/extensions/browser/renderer_startup_helper.cc
+++ b/extensions/browser/renderer_startup_helper.cc
@@ -158,7 +158,7 @@
   const ExtensionSet& extensions =
       ExtensionRegistry::Get(browser_context_)->enabled_extensions();
   for (const auto& ext : extensions) {
-    // OnLoadedExtension should have already been called for the extension.
+    // OnExtensionLoaded should have already been called for the extension.
     DCHECK(base::Contains(extension_process_map_, ext->id()));
     DCHECK(!base::Contains(extension_process_map_[ext->id()], process));
 
diff --git a/gpu/ipc/service/gpu_watchdog_thread.cc b/gpu/ipc/service/gpu_watchdog_thread.cc
index 1e955e6..1017b9f 100644
--- a/gpu/ipc/service/gpu_watchdog_thread.cc
+++ b/gpu/ipc/service/gpu_watchdog_thread.cc
@@ -138,16 +138,16 @@
   int restart_factor = kRestartFactor;
   int max_extra_cycles_before_kill = kMaxExtraCyclesBeforeKill;
 
+#if defined(OS_WIN)
+  gpu_watchdog_timeout = GetGpuWatchdogTimeoutBasedOnCpuCores();
+#endif
+
   if (base::FeatureList::IsEnabled(features::kGpuWatchdogV2NewTimeout)) {
     const char kNewTimeOutParam[] = "new_time_out";
     const char kMaxExtraCyclesBeforeKillParam[] =
         "max_extra_cycles_before_kill";
 
 #if defined(OS_WIN)
-    // The purpose of finch on Windows is to know the impact of the number of
-    // CPU cores while the rest of platforms are to try a different watchdog
-    // timeout length.
-    gpu_watchdog_timeout = GetGpuWatchdogTimeoutBasedOnCpuCores();
     constexpr int kFinchMaxExtraCyclesBeforeKill = 0;
 #elif defined(OS_ANDROID)
     constexpr int kFinchMaxExtraCyclesBeforeKill = 0;
diff --git a/headless/lib/browser/headless_clipboard.cc b/headless/lib/browser/headless_clipboard.cc
index f73fea1..c9acecd 100644
--- a/headless/lib/browser/headless_clipboard.cc
+++ b/headless/lib/browser/headless_clipboard.cc
@@ -8,7 +8,7 @@
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "ui/base/clipboard/clipboard_constants.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 
 namespace headless {
 
diff --git a/headless/lib/browser/headless_clipboard.h b/headless/lib/browser/headless_clipboard.h
index 7e88498..f3f2f98d 100644
--- a/headless/lib/browser/headless_clipboard.h
+++ b/headless/lib/browser/headless_clipboard.h
@@ -13,7 +13,7 @@
 #include "base/macros.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/clipboard/clipboard.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 
 namespace headless {
 
diff --git a/ios/build/bots/scripts/xcode_log_parser.py b/ios/build/bots/scripts/xcode_log_parser.py
index 6605480..87b364c1 100644
--- a/ios/build/bots/scripts/xcode_log_parser.py
+++ b/ios/build/bots/scripts/xcode_log_parser.py
@@ -229,6 +229,15 @@
         'failed': {}
     }
 
+    # Xcodebuild writes staging data to |output_path| folder during test
+    # execution. If |output_path| doesn't exist, it means tests didn't start at
+    # all.
+    if not os.path.exists(output_path):
+      test_results['failed']['TESTS_DID_NOT_START'] = [
+          '%s with staging data does not exist.' % output_path
+      ]
+      return test_results
+
     # During a run `xcodebuild .. -resultBundlePath %output_path%`
     # that generates output_path folder,
     # but Xcode 11+ generates `output_path.xcresult` and `output_path`
@@ -238,16 +247,13 @@
     # on bots. This piece of code uses .xcresult folder.
     xcresult = output_path + '.xcresult'
 
+    # |output_path|.xcresult folder is created at the end of tests. If
+    # |output_path| folder exists but |output_path|.xcresult folder doesn't
+    # exist, it means xcodebuild exited or was killed half way during tests.
     if not os.path.exists(xcresult):
-      test_results['failed']['TESTS_DID_NOT_START'] = [
-          '%s with test results does not exist.' % xcresult
-      ]
-      return test_results
-
-    plist_path = os.path.join(xcresult, 'Info.plist')
-    if not os.path.exists(plist_path):
       test_results['failed']['BUILD_INTERRUPTED'] = [
-          '%s with test results does not exist.' % plist_path] + output
+          '%s with test results does not exist.' % xcresult
+      ] + output
       test_results['passed'] = parse_passed_tests_for_interrupted_run(output)
       return test_results
 
diff --git a/ios/build/bots/scripts/xcode_log_parser_test.py b/ios/build/bots/scripts/xcode_log_parser_test.py
index 81a4ec4..c205bd0f 100644
--- a/ios/build/bots/scripts/xcode_log_parser_test.py
+++ b/ios/build/bots/scripts/xcode_log_parser_test.py
@@ -492,7 +492,7 @@
         'passed': [],
         'failed': {
             'TESTS_DID_NOT_START': [
-                '%s.xcresult with test results does not exist.' % OUTPUT_PATH
+                '%s with staging data does not exist.' % OUTPUT_PATH
             ]
         }
     }
@@ -508,8 +508,7 @@
         'passed': [],
         'failed': {
             'BUILD_INTERRUPTED': [
-                '%s with test results does not exist.' %
-                os.path.join(OUTPUT_PATH + '.xcresult', 'Info.plist')
+                '%s with test results does not exist.' % XCRESULT_PATH
             ]
         }
     }
@@ -566,10 +565,9 @@
         '[09:09:00:INFO] Test case \'-[TestCase2 method1]\' failed on device.',
         '** BUILD INTERRUPTED **',
     ]
-    not_found_message = [
-        'Info.plist.xcresult/Info.plist with test results does not exist.']
+    not_found_message = ['%s with test results does not exist.' % XCRESULT_PATH]
     res = xcode_log_parser.Xcode11LogParser().collect_test_results(
-        'Info.plist', output)
+        OUTPUT_PATH, output)
     self.assertIn('BUILD_INTERRUPTED', res['failed'])
     self.assertEqual(not_found_message + output,
                      res['failed']['BUILD_INTERRUPTED'])
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index 1158d011..422fb910 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -549,9 +549,6 @@
      flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(
          autofill::features::kAutofillEnableCardNicknameManagement)},
-    {"password-check", flag_descriptions::kPasswordCheckName,
-     flag_descriptions::kPasswordCheckDescription, flags_ui::kOsIos,
-     FEATURE_VALUE_TYPE(password_manager::features::kPasswordCheck)},
     {"enable-ios-managed-settings-ui",
      flag_descriptions::kEnableIOSManagedSettingsUIName,
      flag_descriptions::kEnableIOSManagedSettingsUIDescription,
@@ -719,6 +716,7 @@
       base::SysUTF8ToNSString(policy::key::kDefaultSearchProviderEnabled),
       base::SysUTF8ToNSString(policy::key::kDefaultSearchProviderName),
       base::SysUTF8ToNSString(policy::key::kDefaultSearchProviderSearchURL),
+      base::SysUTF8ToNSString(policy::key::kEditBookmarksEnabled),
       base::SysUTF8ToNSString(policy::key::kPasswordManagerEnabled),
       base::SysUTF8ToNSString(policy::key::kSafeBrowsingProtectionLevel),
       base::SysUTF8ToNSString(policy::key::kSearchSuggestEnabled),
@@ -745,6 +743,8 @@
       base::SysUTF8ToNSString(policy::key::kDefaultSearchProviderName) :
           @"TestEngine",
 
+      base::SysUTF8ToNSString(policy::key::kEditBookmarksEnabled) : @NO,
+
       base::SysUTF8ToNSString(policy::key::kPasswordManagerEnabled) : @NO,
 
       base::SysUTF8ToNSString(policy::key::kTranslateEnabled) : @NO,
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
index 93e596d..e690621 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -397,10 +397,6 @@
     "the tools menu or after pressing the 'Open in downloads' button invoked "
     "by pressing 'Open In...' after download completes.";
 
-const char kPasswordCheckName[] = "Bulk Password Check";
-const char kPasswordCheckDescription[] =
-    "Enables the Bulk Password Check feature for signed-in users.";
-
 const char kPageInfoRefactoringName[] = "New design of the page info";
 const char kPageInfoRefactoringDescription[] =
     "Uses the new design for the page security info.";
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
index f90c252..d2bb255 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -347,11 +347,6 @@
 extern const char kOpenDownloadsInFilesAppName[];
 extern const char kOpenDownloadsInFilesAppDescription[];
 
-// Title and description for the flag to provide user with Password Check
-// feature in Settings.
-extern const char kPasswordCheckName[];
-extern const char kPasswordCheckDescription[];
-
 // Title and description for the flag to enable the new design of the page info.
 extern const char kPageInfoRefactoringName[];
 extern const char kPageInfoRefactoringDescription[];
diff --git a/ios/chrome/browser/ui/link_to_text/link_to_text_mediator.mm b/ios/chrome/browser/ui/link_to_text/link_to_text_mediator.mm
index 687d5aa..6709835b 100644
--- a/ios/chrome/browser/ui/link_to_text/link_to_text_mediator.mm
+++ b/ios/chrome/browser/ui/link_to_text/link_to_text_mediator.mm
@@ -74,11 +74,13 @@
 
 - (void)shareLinkToText:(LinkToTextPayload*)payload {
   DCHECK(payload);
+  shared_highlighting::LogLinkGenerationStatus(true);
   [self.consumer generatedPayload:payload];
 }
 
 - (void)linkGenerationFailedWithError:(LinkGenerationError)error {
-  // TODO(crbug.com/1136043): Log appropriate failure metric.
+  shared_highlighting::LogLinkGenerationStatus(false);
+  shared_highlighting::LogLinkGenerationErrorReason(error);
   [self.consumer linkGenerationFailed];
 }
 
diff --git a/ios/chrome/browser/ui/link_to_text/link_to_text_mediator_unittest.mm b/ios/chrome/browser/ui/link_to_text/link_to_text_mediator_unittest.mm
index 003365f..3fd940d 100644
--- a/ios/chrome/browser/ui/link_to_text/link_to_text_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/link_to_text/link_to_text_mediator_unittest.mm
@@ -11,8 +11,10 @@
 #import "base/run_loop.h"
 #import "base/strings/sys_string_conversions.h"
 #import "base/test/ios/wait_util.h"
+#import "base/test/metrics/histogram_tester.h"
 #import "base/test/scoped_feature_list.h"
 #import "base/values.h"
+#import "components/shared_highlighting/core/common/shared_highlighting_metrics.h"
 #import "components/shared_highlighting/core/common/text_fragment.h"
 #import "ios/chrome/browser/link_to_text/link_generation_outcome.h"
 #import "ios/chrome/browser/link_to_text/link_to_text_payload.h"
@@ -36,6 +38,7 @@
 using web::TestWebState;
 using base::test::ios::WaitUntilConditionOrTimeout;
 using base::test::ios::kWaitForJSCompletionTimeout;
+using shared_highlighting::LinkGenerationError;
 
 namespace {
 const CGFloat kCaretWidth = 4.0;
@@ -157,6 +160,8 @@
 // Tests that the shareHighlight command is triggered with the right parameters
 // when the view is not zoomed in.
 TEST_F(LinkToTextMediatorTest, HandleLinkToTextSelectionTriggersCommandNoZoom) {
+  base::HistogramTester histogram_tester;
+
   CGFloat zoom = 1;
   CGRect selection_rect = CGRectMake(100, 150, 250, 250);
   CGRect expected_client_rect = CGRectMake(150, 250, 250 + kCaretWidth, 250);
@@ -187,12 +192,18 @@
   }));
 
   [mocked_consumer_ verify];
+
+  // Make sure the correct metric were recorded.
+  histogram_tester.ExpectUniqueSample("SharedHighlights.LinkGenerated", true,
+                                      1);
 }
 
 // Tests that the shareHighlight command is triggered with the right parameters
 // when the current view is zoomed in.
 TEST_F(LinkToTextMediatorTest,
        HandleLinkToTextSelectionTriggersCommandWithZoom) {
+  base::HistogramTester histogram_tester;
+
   CGFloat zoom = 1.5;
   CGRect selection_rect = CGRectMake(100, 150, 250, 250);
   CGRect expected_client_rect = CGRectMake(200, 325, 375 + kCaretWidth, 375);
@@ -223,11 +234,17 @@
   }));
 
   [mocked_consumer_ verify];
+
+  // Make sure the correct metric were recorded.
+  histogram_tester.ExpectUniqueSample("SharedHighlights.LinkGenerated", true,
+                                      1);
 }
 
 // Tests that the consumer is informed of a failure to generate a link when an
 // error is returned from JavaScript.
 TEST_F(LinkToTextMediatorTest, LinkGenerationError) {
+  base::HistogramTester histogram_tester;
+
   std::unique_ptr<base::Value> error_response =
       CreateErrorResponse(LinkGenerationOutcome::kInvalidSelection);
   SetLinkToTextResponse(std::move(error_response), /*zoom=*/1.0);
@@ -245,11 +262,20 @@
   }));
 
   [mocked_consumer_ verify];
+
+  // Make sure the correct metric were recorded.
+  histogram_tester.ExpectUniqueSample("SharedHighlights.LinkGenerated", false,
+                                      1);
+  histogram_tester.ExpectBucketCount("SharedHighlights.LinkGenerated.Error",
+                                     LinkGenerationError::kIncorrectSelector,
+                                     1);
 }
 
 // Tests that the consumer is informed of a failure to generate a link when an
 // an empty response is returned from JavaScript.
 TEST_F(LinkToTextMediatorTest, EmptyResponseLinkGenerationError) {
+  base::HistogramTester histogram_tester;
+
   std::unique_ptr<base::Value> empty_response = std::make_unique<base::Value>();
   SetLinkToTextResponse(std::move(empty_response), /*zoom=*/1.0);
 
@@ -266,11 +292,19 @@
   }));
 
   [mocked_consumer_ verify];
+
+  // Make sure the correct metric were recorded.
+  histogram_tester.ExpectUniqueSample("SharedHighlights.LinkGenerated", false,
+                                      1);
+  histogram_tester.ExpectBucketCount("SharedHighlights.LinkGenerated.Error",
+                                     LinkGenerationError::kUnknown, 1);
 }
 
 // Tests that the consumer is informed of a failure to generate a link when an
 // a malformed response is returned from JavaScript.
 TEST_F(LinkToTextMediatorTest, BadResponseLinkGenerationError) {
+  base::HistogramTester histogram_tester;
+
   std::unique_ptr<base::Value> malformed_response =
       std::make_unique<base::Value>(base::Value::Type::DICTIONARY);
   malformed_response->SetStringKey("somethingElse", "abc");
@@ -289,11 +323,19 @@
   }));
 
   [mocked_consumer_ verify];
+
+  // Make sure the correct metric were recorded.
+  histogram_tester.ExpectUniqueSample("SharedHighlights.LinkGenerated", false,
+                                      1);
+  histogram_tester.ExpectBucketCount("SharedHighlights.LinkGenerated.Error",
+                                     LinkGenerationError::kUnknown, 1);
 }
 
 // Tests that the consumer is informed of a failure to generate a link when an
 // a string response is returned from JavaScript.
 TEST_F(LinkToTextMediatorTest, StringResponseLinkGenerationError) {
+  base::HistogramTester histogram_tester;
+
   std::unique_ptr<base::Value> string_response =
       std::make_unique<base::Value>("someValue");
   SetLinkToTextResponse(std::move(string_response), /*zoom=*/1.0);
@@ -311,11 +353,19 @@
   }));
 
   [mocked_consumer_ verify];
+
+  // Make sure the correct metric were recorded.
+  histogram_tester.ExpectUniqueSample("SharedHighlights.LinkGenerated", false,
+                                      1);
+  histogram_tester.ExpectBucketCount("SharedHighlights.LinkGenerated.Error",
+                                     LinkGenerationError::kUnknown, 1);
 }
 
 // Tests that the consumer is informed of a failure to generate a link when a
 // success status is returned, but no payload.
 TEST_F(LinkToTextMediatorTest, LinkGenerationSuccessButNoPayload) {
+  base::HistogramTester histogram_tester;
+
   std::unique_ptr<base::Value> success_response =
       CreateErrorResponse(LinkGenerationOutcome::kSuccess);
   SetLinkToTextResponse(std::move(success_response), /*zoom=*/1.0);
@@ -333,4 +383,10 @@
   }));
 
   [mocked_consumer_ verify];
+
+  // Make sure the correct metric were recorded.
+  histogram_tester.ExpectUniqueSample("SharedHighlights.LinkGenerated", false,
+                                      1);
+  histogram_tester.ExpectBucketCount("SharedHighlights.LinkGenerated.Error",
+                                     LinkGenerationError::kUnknown, 1);
 }
diff --git a/ios/chrome/browser/ui/passwords/password_breach_coordinator.mm b/ios/chrome/browser/ui/passwords/password_breach_coordinator.mm
index b686b16..10b631af 100644
--- a/ios/chrome/browser/ui/passwords/password_breach_coordinator.mm
+++ b/ios/chrome/browser/ui/passwords/password_breach_coordinator.mm
@@ -63,12 +63,9 @@
   if (@available(iOS 13, *)) {
     self.viewController.modalInPresentation = YES;
   }
-  id<ApplicationCommands> handler = HandlerForProtocol(
-      self.browser->GetCommandDispatcher(), ApplicationCommands);
   self.mediator =
       [[PasswordBreachMediator alloc] initWithConsumer:self.viewController
                                              presenter:self
-                                               handler:handler
                                                    URL:_url
                                               leakType:self.leakType];
   self.viewController.actionHandler = self.mediator;
diff --git a/ios/chrome/browser/ui/passwords/password_breach_egtest.mm b/ios/chrome/browser/ui/passwords/password_breach_egtest.mm
index 1fdb4f0..ae89cc46 100644
--- a/ios/chrome/browser/ui/passwords/password_breach_egtest.mm
+++ b/ios/chrome/browser/ui/passwords/password_breach_egtest.mm
@@ -63,11 +63,6 @@
 
 // Tests that Check password button redirects to the Passwords List.
 - (void)testPasswordBreachRedirectToPasswords {
-  // TODO(crbug.com/1096986): Remove it once feature is enabled by default.
-  AppLaunchConfiguration config;
-  config.features_enabled.push_back(password_manager::features::kPasswordCheck);
-  [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config];
-
   [PasswordBreachAppInterface showPasswordBreachWithCheckButton:YES];
   [[EarlGrey selectElementWithMatcher:PasswordBreachMatcher()]
       assertWithMatcher:grey_notNil()];
diff --git a/ios/chrome/browser/ui/passwords/password_breach_mediator.h b/ios/chrome/browser/ui/passwords/password_breach_mediator.h
index ab11bb40..71172c3 100644
--- a/ios/chrome/browser/ui/passwords/password_breach_mediator.h
+++ b/ios/chrome/browser/ui/passwords/password_breach_mediator.h
@@ -21,7 +21,6 @@
 
 - (instancetype)initWithConsumer:(id<PasswordBreachConsumer>)consumer
                        presenter:(id<PasswordBreachPresenter>)presenter
-                         handler:(id<ApplicationCommands>)handler
                              URL:(const GURL&)URL
                         leakType:(password_manager::CredentialLeakType)leakType;
 
diff --git a/ios/chrome/browser/ui/passwords/password_breach_mediator.mm b/ios/chrome/browser/ui/passwords/password_breach_mediator.mm
index c6d9028..d9f74e9 100644
--- a/ios/chrome/browser/ui/passwords/password_breach_mediator.mm
+++ b/ios/chrome/browser/ui/passwords/password_breach_mediator.mm
@@ -42,22 +42,17 @@
 // The presenter of the feature.
 @property(nonatomic, weak) id<PasswordBreachPresenter> presenter;
 
-// Dispatcher.
-@property(nonatomic, weak) id<ApplicationCommands> handler;
-
 @end
 
 @implementation PasswordBreachMediator
 
 - (instancetype)initWithConsumer:(id<PasswordBreachConsumer>)consumer
                        presenter:(id<PasswordBreachPresenter>)presenter
-                         handler:(id<ApplicationCommands>)handler
                              URL:(const GURL&)URL
                         leakType:(CredentialLeakType)leakType {
   self = [super init];
   if (self) {
     _presenter = presenter;
-    _handler = handler;
     _leakType = GetLeakDialogType(leakType);
     _dismissReason = LeakDialogDismissalReason::kNoDirectInteraction;
 
@@ -85,18 +80,9 @@
 
 - (void)confirmationAlertPrimaryAction {
   self.dismissReason = LeakDialogDismissalReason::kClickedCheckPasswords;
-  if (base::FeatureList::IsEnabled(
-          password_manager::features::kPasswordCheck)) {
-    // Opening Password page will stop the presentation in the presenter.
-    // No need to send |stop|.
-    [self.presenter startPasswordCheck];
-  } else {
-    // Opening a new tab already stops the presentation in the presenter.
-    // No need to send |stop|.
-    OpenNewTabCommand* newTabCommand =
-        [OpenNewTabCommand commandWithURLFromChrome:GetPasswordCheckupURL()];
-    [self.handler openURLInNewTab:newTabCommand];
-  }
+  // Opening Password page will stop the presentation in the presenter.
+  // No need to send |stop|.
+  [self.presenter startPasswordCheck];
 }
 
 - (void)confirmationAlertSecondaryAction {
diff --git a/ios/chrome/browser/ui/settings/password/BUILD.gn b/ios/chrome/browser/ui/settings/password/BUILD.gn
index 3f25afa..164b096 100644
--- a/ios/chrome/browser/ui/settings/password/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/password/BUILD.gn
@@ -44,9 +44,6 @@
 source_set("password_ui") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
-    "legacy_password_details_table_view_controller.h",
-    "legacy_password_details_table_view_controller.mm",
-    "legacy_password_details_table_view_controller_delegate.h",
     "password_exporter.h",
     "password_exporter.mm",
     "password_issue.h",
@@ -116,10 +113,7 @@
 source_set("test_support") {
   configs += [ "//build/config/compiler:enable_arc" ]
   testonly = true
-  sources = [
-    "legacy_password_details_table_view_controller+testing.h",
-    "password_exporter_for_testing.h",
-  ]
+  sources = [ "password_exporter_for_testing.h" ]
   deps = [ ":password_ui" ]
 }
 
@@ -127,7 +121,6 @@
   configs += [ "//build/config/compiler:enable_arc" ]
   testonly = true
   sources = [
-    "legacy_password_details_table_view_controller_unittest.mm",
     "password_exporter_unittest.mm",
     "password_issues_mediator_unittest.mm",
     "password_issues_table_view_controller_unittest.mm",
diff --git a/ios/chrome/browser/ui/settings/password/legacy_password_details_table_view_controller+testing.h b/ios/chrome/browser/ui/settings/password/legacy_password_details_table_view_controller+testing.h
deleted file mode 100644
index be2d212c..0000000
--- a/ios/chrome/browser/ui/settings/password/legacy_password_details_table_view_controller+testing.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_LEGACY_PASSWORD_DETAILS_TABLE_VIEW_CONTROLLER_TESTING_H_
-#define IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_LEGACY_PASSWORD_DETAILS_TABLE_VIEW_CONTROLLER_TESTING_H_
-
-#import "ios/chrome/browser/ui/settings/password/legacy_password_details_table_view_controller.h"
-
-// TODO(crbug.com/943523): Refactor the PasswordTableViewController and
-// PasswordsSettingsTestCase to remove this Category file.
-@interface LegacyPasswordDetailsTableViewController (Testing)
-
-// Allows to replace a |reauthenticationModule| for a fake one in integration
-// tests, where the testing code cannot control the creation of the
-// controller.
-- (void)setReauthenticationModule:
-    (id<ReauthenticationProtocol>)reauthenticationModule;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_LEGACY_PASSWORD_DETAILS_TABLE_VIEW_CONTROLLER_TESTING_H_
diff --git a/ios/chrome/browser/ui/settings/password/legacy_password_details_table_view_controller.h b/ios/chrome/browser/ui/settings/password/legacy_password_details_table_view_controller.h
deleted file mode 100644
index d9ca930..0000000
--- a/ios/chrome/browser/ui/settings/password/legacy_password_details_table_view_controller.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_LEGACY_PASSWORD_DETAILS_TABLE_VIEW_CONTROLLER_H_
-#define IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_LEGACY_PASSWORD_DETAILS_TABLE_VIEW_CONTROLLER_H_
-
-#include "components/password_manager/core/browser/password_form_forward.h"
-#import "ios/chrome/browser/ui/settings/password/legacy_password_details_table_view_controller_delegate.h"
-#import "ios/chrome/browser/ui/settings/settings_root_table_view_controller.h"
-
-@protocol ReauthenticationProtocol;
-
-// TODO(crbug.com/1096986): Delete this view controller after Password Check
-// launch.
-
-// Displays details of a password item, including URL of the site, username and
-// password in masked state as default. User can copy the URL and username,
-// pass the iOS security check to see and copy the password , or delete the
-// password item.
-@interface LegacyPasswordDetailsTableViewController
-    : SettingsRootTableViewController
-
-// The designated initializer.
-- (nullable instancetype)
-      initWithPasswordForm:(const password_manager::PasswordForm&)passwordForm
-                  delegate:
-                      (nonnull
-                           id<LegacyPasswordDetailsTableViewControllerDelegate>)
-                          delegate
-    reauthenticationModule:
-        (nonnull id<ReauthenticationProtocol>)reauthenticationModule
-    NS_DESIGNATED_INITIALIZER;
-
-- (nullable instancetype)initWithStyle:(UITableViewStyle)style NS_UNAVAILABLE;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_LEGACY_PASSWORD_DETAILS_TABLE_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/settings/password/legacy_password_details_table_view_controller.mm b/ios/chrome/browser/ui/settings/password/legacy_password_details_table_view_controller.mm
deleted file mode 100644
index eeb601c4..0000000
--- a/ios/chrome/browser/ui/settings/password/legacy_password_details_table_view_controller.mm
+++ /dev/null
@@ -1,693 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/settings/password/legacy_password_details_table_view_controller.h"
-
-#import <MobileCoreServices/UTCoreTypes.h>
-#import <UIKit/UIKit.h>
-
-#import <MaterialComponents/MaterialSnackbar.h>
-
-#include "base/ios/ios_util.h"
-#include "base/mac/foundation_util.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/strings/sys_string_conversions.h"
-#include "components/password_manager/core/browser/password_form.h"
-#include "components/password_manager/core/browser/password_manager_metrics_util.h"
-#include "components/password_manager/core/browser/password_store.h"
-#include "components/password_manager/core/browser/password_ui_utils.h"
-#include "components/strings/grit/components_strings.h"
-#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#import "ios/chrome/browser/ui/commands/browser_commands.h"
-#import "ios/chrome/browser/ui/settings/password/passwords_table_view_constants.h"
-#import "ios/chrome/browser/ui/settings/password/passwords_table_view_controller.h"
-#import "ios/chrome/browser/ui/settings/utils/settings_utils.h"
-#import "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h"
-#import "ios/chrome/browser/ui/table_view/cells/table_view_detail_text_item.h"
-#import "ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.h"
-#import "ios/chrome/browser/ui/table_view/cells/table_view_text_item.h"
-#include "ios/chrome/browser/ui/ui_feature_flags.h"
-#include "ios/chrome/browser/ui/util/uikit_ui_util.h"
-#import "ios/chrome/common/constants.h"
-#import "ios/chrome/common/ui/colors/semantic_color_names.h"
-#import "ios/chrome/common/ui/reauthentication/reauthentication_module.h"
-#include "ios/chrome/grit/ios_strings.h"
-#include "ui/base/clipboard/clipboard_constants.h"
-#include "ui/base/l10n/l10n_util_mac.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-using password_manager::metrics_util::LogPasswordSettingsReauthResult;
-using password_manager::metrics_util::ReauthResult;
-
-namespace {
-
-typedef NS_ENUM(NSInteger, SectionIdentifier) {
-  SectionIdentifierSite = kSectionIdentifierEnumZero,
-  SectionIdentifierUsername,
-  SectionIdentifierPassword,
-  SectionIdentifierFederation,
-  SectionIdentifierDelete,
-};
-
-typedef NS_ENUM(NSInteger, ItemType) {
-  ItemTypeHeader = kItemTypeEnumZero,
-  ItemTypeSite,
-  ItemTypeCopySite,
-  ItemTypeUsername,
-  ItemTypeCopyUsername,
-  ItemTypePassword,
-  ItemTypeCopyPassword,
-  ItemTypeShowHide,
-  ItemTypeFederation,
-  ItemTypeDelete,
-};
-
-}  // namespace
-
-@interface LegacyPasswordDetailsTableViewController () {
-  // The username to which the saved password belongs.
-  NSString* _username;
-  // The saved password.
-  NSString* _password;
-  // The federation providing this credential, if any.
-  NSString* _federation;
-  // The origin site of the saved credential.
-  NSString* _site;
-  // Whether the password is shown in plain text form or in obscured form.
-  BOOL _plainTextPasswordShown;
-  // The password form.
-  password_manager::PasswordForm _passwordForm;
-  // Module containing the reauthentication mechanism for viewing and copying
-  // passwords.
-  __weak id<ReauthenticationProtocol> _weakReauthenticationModule;
-  // The password item.
-  TableViewTextItem* _passwordItem;
-}
-
-// Alert dialog to confirm deletion of passwords upon pressing the delete
-// button.
-@property(nonatomic, strong) UIAlertController* deleteConfirmation;
-
-// Instance of the parent view controller needed in order to update the
-// password list when a password is deleted.
-@property(nonatomic, weak) id<LegacyPasswordDetailsTableViewControllerDelegate>
-    delegate;
-
-@end
-
-@implementation LegacyPasswordDetailsTableViewController
-
-@synthesize deleteConfirmation = _deleteConfirmation;
-
-- (instancetype)
-      initWithPasswordForm:(const password_manager::PasswordForm&)passwordForm
-                  delegate:
-                      (id<LegacyPasswordDetailsTableViewControllerDelegate>)
-                          delegate
-    reauthenticationModule:
-        (id<ReauthenticationProtocol>)reauthenticationModule {
-  DCHECK(delegate);
-  DCHECK(reauthenticationModule);
-  UITableViewStyle style = base::FeatureList::IsEnabled(kSettingsRefresh)
-                               ? UITableViewStylePlain
-                               : UITableViewStyleGrouped;
-  self = [super initWithStyle:style];
-  if (self) {
-    _delegate = delegate;
-    _weakReauthenticationModule = reauthenticationModule;
-
-    _passwordForm = passwordForm;
-    if (!_passwordForm.blocked_by_user) {
-      _username = base::SysUTF16ToNSString(_passwordForm.username_value);
-      if (_passwordForm.federation_origin.opaque()) {
-        _password = base::SysUTF16ToNSString(_passwordForm.password_value);
-      } else {
-        _federation =
-            base::SysUTF8ToNSString(_passwordForm.federation_origin.host());
-      }
-    }
-    auto name_and_link =
-        password_manager::GetShownOriginAndLinkUrl(_passwordForm);
-    self.title = base::SysUTF8ToNSString(name_and_link.first);
-    _site = base::SysUTF8ToNSString(name_and_link.second.spec());
-    NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
-    [defaultCenter addObserver:self
-                      selector:@selector(hidePassword)
-                          name:UIApplicationDidEnterBackgroundNotification
-                        object:nil];
-  }
-  return self;
-}
-
-#pragma mark - UIViewController
-
-- (void)viewDidLoad {
-  [super viewDidLoad];
-  self.tableView.accessibilityIdentifier = kPasswordDetailsTableViewId;
-
-  [self loadModel];
-}
-
-#pragma mark - ChromeTableViewController
-
-- (void)loadModel {
-  [super loadModel];
-  TableViewModel* model = self.tableViewModel;
-
-  [model addSectionWithIdentifier:SectionIdentifierSite];
-  TableViewTextHeaderFooterItem* siteHeader =
-      [[TableViewTextHeaderFooterItem alloc] initWithType:ItemTypeHeader];
-  siteHeader.text = l10n_util::GetNSString(IDS_IOS_SHOW_PASSWORD_VIEW_SITE);
-  [model setHeader:siteHeader forSectionWithIdentifier:SectionIdentifierSite];
-  TableViewTextItem* siteItem =
-      [[TableViewTextItem alloc] initWithType:ItemTypeSite];
-  siteItem.text = _site;
-  [model addItem:siteItem toSectionWithIdentifier:SectionIdentifierSite];
-  [model addItem:[self siteCopyButtonItem]
-      toSectionWithIdentifier:SectionIdentifierSite];
-
-  if (!_passwordForm.blocked_by_user) {
-    [model addSectionWithIdentifier:SectionIdentifierUsername];
-    TableViewTextHeaderFooterItem* usernameHeader =
-        [[TableViewTextHeaderFooterItem alloc] initWithType:ItemTypeHeader];
-    usernameHeader.text =
-        l10n_util::GetNSString(IDS_IOS_SHOW_PASSWORD_VIEW_USERNAME);
-    [model setHeader:usernameHeader
-        forSectionWithIdentifier:SectionIdentifierUsername];
-    TableViewTextItem* usernameItem =
-        [[TableViewTextItem alloc] initWithType:ItemTypeUsername];
-    usernameItem.text = _username;
-    [model addItem:usernameItem
-        toSectionWithIdentifier:SectionIdentifierUsername];
-    [model addItem:[self usernameCopyButtonItem]
-        toSectionWithIdentifier:SectionIdentifierUsername];
-
-    if (_passwordForm.federation_origin.opaque()) {
-      [model addSectionWithIdentifier:SectionIdentifierPassword];
-      TableViewTextHeaderFooterItem* passwordHeader =
-          [[TableViewTextHeaderFooterItem alloc] initWithType:ItemTypeHeader];
-      passwordHeader.text =
-          l10n_util::GetNSString(IDS_IOS_SHOW_PASSWORD_VIEW_PASSWORD);
-      [model setHeader:passwordHeader
-          forSectionWithIdentifier:SectionIdentifierPassword];
-      _passwordItem = [[TableViewTextItem alloc] initWithType:ItemTypePassword];
-      _passwordItem.text = _password;
-      _passwordItem.masked = YES;
-      [model addItem:_passwordItem
-          toSectionWithIdentifier:SectionIdentifierPassword];
-
-      [model addItem:[self passwordCopyButtonItem]
-          toSectionWithIdentifier:SectionIdentifierPassword];
-      [model addItem:[self showHidePasswordButtonItem]
-          toSectionWithIdentifier:SectionIdentifierPassword];
-    } else {
-      [model addSectionWithIdentifier:SectionIdentifierFederation];
-      TableViewTextHeaderFooterItem* federationHeader =
-          [[TableViewTextHeaderFooterItem alloc] initWithType:ItemTypeHeader];
-      federationHeader.text =
-          l10n_util::GetNSString(IDS_IOS_SHOW_PASSWORD_VIEW_FEDERATION);
-      [model setHeader:federationHeader
-          forSectionWithIdentifier:SectionIdentifierFederation];
-      TableViewTextItem* federationItem =
-          [[TableViewTextItem alloc] initWithType:ItemTypeFederation];
-      federationItem.text = _federation;
-      [model addItem:federationItem
-          toSectionWithIdentifier:SectionIdentifierFederation];
-    }
-  }
-
-  [model addSectionWithIdentifier:SectionIdentifierDelete];
-  [model addItem:[self deletePasswordButtonItem]
-      toSectionWithIdentifier:SectionIdentifierDelete];
-}
-
-#pragma mark - Items
-
-// Returns the "Copy" button for site.
-- (TableViewItem*)siteCopyButtonItem {
-  TableViewTextItem* item =
-      [[TableViewTextItem alloc] initWithType:ItemTypeCopySite];
-  item.text = l10n_util::GetNSString(IDS_IOS_SETTINGS_SITE_COPY_BUTTON);
-  item.textColor = [UIColor colorNamed:kBlueColor];
-  // Accessibility label adds the header to the text, so that accessibility
-  // users do not have to rely on the visual grouping to understand which part
-  // of the credential is being copied.
-  item.accessibilityLabel = [NSString
-      stringWithFormat:@"%@: %@",
-                       l10n_util::GetNSString(IDS_IOS_SHOW_PASSWORD_VIEW_SITE),
-                       l10n_util::GetNSString(
-                           IDS_IOS_SETTINGS_SITE_COPY_BUTTON)];
-  item.accessibilityTraits |= UIAccessibilityTraitButton;
-  return item;
-}
-
-// Returns the "Copy" button for user name.
-- (TableViewItem*)usernameCopyButtonItem {
-  TableViewTextItem* item =
-      [[TableViewTextItem alloc] initWithType:ItemTypeCopyUsername];
-  item.text = l10n_util::GetNSString(IDS_IOS_SETTINGS_USERNAME_COPY_BUTTON);
-  item.textColor = [UIColor colorNamed:kBlueColor];
-  // Accessibility label adds the header to the text, so that accessibility
-  // users do not have to rely on the visual grouping to understand which part
-  // of the credential is being copied.
-  item.accessibilityLabel =
-      [NSString stringWithFormat:@"%@: %@",
-                                 l10n_util::GetNSString(
-                                     IDS_IOS_SHOW_PASSWORD_VIEW_USERNAME),
-                                 l10n_util::GetNSString(
-                                     IDS_IOS_SETTINGS_USERNAME_COPY_BUTTON)];
-  item.accessibilityTraits |= UIAccessibilityTraitButton;
-  return item;
-}
-
-// Returns the "Copy" button for password.
-- (TableViewItem*)passwordCopyButtonItem {
-  TableViewTextItem* item =
-      [[TableViewTextItem alloc] initWithType:ItemTypeCopyPassword];
-  item.text = l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_COPY_BUTTON);
-  item.textColor = [UIColor colorNamed:kBlueColor];
-  // Accessibility label adds the header to the text, so that accessibility
-  // users do not have to rely on the visual grouping to understand which part
-  // of the credential is being copied.
-  item.accessibilityLabel =
-      [NSString stringWithFormat:@"%@: %@",
-                                 l10n_util::GetNSString(
-                                     IDS_IOS_SHOW_PASSWORD_VIEW_PASSWORD),
-                                 l10n_util::GetNSString(
-                                     IDS_IOS_SETTINGS_PASSWORD_COPY_BUTTON)];
-  item.accessibilityTraits |= UIAccessibilityTraitButton;
-  return item;
-}
-
-// Returns the "Show/Hide" toggle button for password.
-- (TableViewItem*)showHidePasswordButtonItem {
-  TableViewTextItem* item =
-      [[TableViewTextItem alloc] initWithType:ItemTypeShowHide];
-  item.text = [self showHideButtonText];
-  item.textColor = [UIColor colorNamed:kBlueColor];
-  item.accessibilityTraits |= UIAccessibilityTraitButton;
-  return item;
-}
-
-// Returns the "Delete" button for password.
-- (TableViewItem*)deletePasswordButtonItem {
-  TableViewTextItem* item =
-      [[TableViewTextItem alloc] initWithType:ItemTypeDelete];
-  item.text = l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_DELETE_BUTTON);
-  item.textColor = [UIColor colorNamed:kRedColor];
-  item.accessibilityTraits |= UIAccessibilityTraitButton;
-  return item;
-}
-
-#pragma mark - Actions
-
-// Copies the site to system pasteboard and shows a toast of success.
-- (void)copySite {
-  UIPasteboard* generalPasteboard = [UIPasteboard generalPasteboard];
-  generalPasteboard.string = _site;
-  [self showToast:l10n_util::GetNSString(
-                      IDS_IOS_SETTINGS_SITE_WAS_COPIED_MESSAGE)
-       forSuccess:YES];
-}
-
-// Copies the user name to system pasteboard and shows a toast of success.
-- (void)copyUsername {
-  UIPasteboard* generalPasteboard = [UIPasteboard generalPasteboard];
-  generalPasteboard.string = _username;
-  [self showToast:l10n_util::GetNSString(
-                      IDS_IOS_SETTINGS_USERNAME_WAS_COPIED_MESSAGE)
-       forSuccess:YES];
-}
-
-// Returns the title of "Show/Hide" toggle button for password based on current
-// state of |_plainTextPasswordShown|.
-- (NSString*)showHideButtonText {
-  if (_plainTextPasswordShown) {
-    return l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_HIDE_BUTTON);
-  }
-  return l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_SHOW_BUTTON);
-}
-
-// Changes the text on the Show/Hide button appropriately according to
-// |_plainTextPasswordShown|.
-- (void)toggleShowHideButton {
-  TableViewModel* model = self.tableViewModel;
-  NSIndexPath* path = [model indexPathForItemType:ItemTypeShowHide
-                                sectionIdentifier:SectionIdentifierPassword];
-  TableViewTextItem* item = base::mac::ObjCCastStrict<TableViewTextItem>(
-      [model itemAtIndexPath:path]);
-  item.text = [self showHideButtonText];
-  [self reconfigureCellsForItems:@[ item ]];
-}
-
-// Shows the password and toggles the "Show/Hide" button if the user can
-// reauthenticate, otherwise shows the password dialog.
-- (void)showPassword {
-  if (_plainTextPasswordShown) {
-    return;
-  }
-
-  if ([_weakReauthenticationModule canAttemptReauth]) {
-    __weak LegacyPasswordDetailsTableViewController* weakSelf = self;
-    void (^showPasswordHandler)(ReauthenticationResult) =
-        ^(ReauthenticationResult result) {
-          LegacyPasswordDetailsTableViewController* strongSelf = weakSelf;
-          if (!strongSelf)
-            return;
-          [strongSelf logPasswordSettingsReauthResult:result];
-          if (result == ReauthenticationResult::kFailure)
-            return;
-          TableViewTextItem* passwordItem = strongSelf->_passwordItem;
-          passwordItem.masked = NO;
-          [strongSelf reconfigureCellsForItems:@[ passwordItem ]];
-          strongSelf->_plainTextPasswordShown = YES;
-          [strongSelf toggleShowHideButton];
-          UMA_HISTOGRAM_ENUMERATION(
-              "PasswordManager.AccessPasswordInSettings",
-              password_manager::metrics_util::ACCESS_PASSWORD_VIEWED,
-              password_manager::metrics_util::ACCESS_PASSWORD_COUNT);
-        };
-
-    [_weakReauthenticationModule
-        attemptReauthWithLocalizedReason:
-            l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_REAUTH_REASON_SHOW)
-                    canReusePreviousAuth:YES
-                                 handler:showPasswordHandler];
-  } else {
-    [self showPasscodeDialog];
-  }
-}
-
-// Hides the password and toggles the "Show/Hide" button.
-- (void)hidePassword {
-  if (!_plainTextPasswordShown) {
-    return;
-  }
-  _passwordItem.masked = YES;
-  [self reconfigureCellsForItems:@[ _passwordItem ]];
-  _plainTextPasswordShown = NO;
-  [self toggleShowHideButton];
-}
-
-// Copies the password to system pasteboard and shows a toast of success if the
-// user can reauthenticate, otherwise shows the password dialog.
-- (void)copyPassword {
-  // If the password is displayed in plain text, there is no need to
-  // re-authenticate the user when copying the password because they are already
-  // granted access to it.
-
-  NSDate* expirationDate =
-      [NSDate dateWithTimeIntervalSinceNow:kSecurePasteboardExpiration];
-  NSDictionary* options = @{UIPasteboardOptionExpirationDate : expirationDate};
-
-  if (_plainTextPasswordShown) {
-    NSDictionary* item = @{(NSString*)kUTTypePlainText : _password};
-    [[UIPasteboard generalPasteboard] setItems:@[ item ] options:options];
-
-    [self showToast:l10n_util::GetNSString(
-                        IDS_IOS_SETTINGS_PASSWORD_WAS_COPIED_MESSAGE)
-         forSuccess:YES];
-    UMA_HISTOGRAM_ENUMERATION(
-        "PasswordManager.AccessPasswordInSettings",
-        password_manager::metrics_util::ACCESS_PASSWORD_COPIED,
-        password_manager::metrics_util::ACCESS_PASSWORD_COUNT);
-    password_manager::metrics_util::LogPasswordSettingsReauthResult(
-        password_manager::metrics_util::ReauthResult::kSkipped);
-  } else if ([_weakReauthenticationModule canAttemptReauth]) {
-    __weak LegacyPasswordDetailsTableViewController* weakSelf = self;
-    void (^copyPasswordHandler)(ReauthenticationResult) = ^(
-        ReauthenticationResult result) {
-      LegacyPasswordDetailsTableViewController* strongSelf = weakSelf;
-      if (!strongSelf)
-        return;
-      [strongSelf logPasswordSettingsReauthResult:result];
-      if (result != ReauthenticationResult::kFailure) {
-        UIPasteboard* generalPasteboard = [UIPasteboard generalPasteboard];
-        [generalPasteboard
-            setItems:@[ @{
-              (NSString*)kUTTypePlainText : strongSelf->_password,
-              ui::kUTTypeConfidentialData : strongSelf->_password
-            } ]
-             options:options];
-        [strongSelf showToast:l10n_util::GetNSString(
-                                  IDS_IOS_SETTINGS_PASSWORD_WAS_COPIED_MESSAGE)
-                   forSuccess:YES];
-        UMA_HISTOGRAM_ENUMERATION(
-            "PasswordManager.AccessPasswordInSettings",
-            password_manager::metrics_util::ACCESS_PASSWORD_COPIED,
-            password_manager::metrics_util::ACCESS_PASSWORD_COUNT);
-      } else {
-        [strongSelf
-             showToast:l10n_util::GetNSString(
-                           IDS_IOS_SETTINGS_PASSWORD_WAS_NOT_COPIED_MESSAGE)
-            forSuccess:NO];
-      }
-    };
-    [_weakReauthenticationModule
-        attemptReauthWithLocalizedReason:
-            l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_REAUTH_REASON_COPY)
-                    canReusePreviousAuth:YES
-                                 handler:copyPasswordHandler];
-  } else {
-    [self showPasscodeDialog];
-  }
-}
-
-// Show a dialog offering the user to set a passcode in order to see the
-// passwords.
-- (void)showPasscodeDialog {
-  UIAlertController* alertController = [UIAlertController
-      alertControllerWithTitle:l10n_util::GetNSString(
-                                   IDS_IOS_SETTINGS_SET_UP_SCREENLOCK_TITLE)
-                       message:l10n_util::GetNSString(
-                                   IDS_IOS_SETTINGS_SET_UP_SCREENLOCK_CONTENT)
-                preferredStyle:UIAlertControllerStyleAlert];
-
-  ProceduralBlockWithURL blockOpenURL = BlockToOpenURL(self, self.dispatcher);
-  UIAlertAction* learnAction = [UIAlertAction
-      actionWithTitle:l10n_util::GetNSString(
-                          IDS_IOS_SETTINGS_SET_UP_SCREENLOCK_LEARN_HOW)
-                style:UIAlertActionStyleDefault
-              handler:^(UIAlertAction*) {
-                blockOpenURL(GURL(kPasscodeArticleURL));
-              }];
-  [alertController addAction:learnAction];
-  UIAlertAction* okAction =
-      [UIAlertAction actionWithTitle:l10n_util::GetNSString(IDS_OK)
-                               style:UIAlertActionStyleDefault
-                             handler:nil];
-  [alertController addAction:okAction];
-  alertController.preferredAction = okAction;
-
-  [self presentViewController:alertController animated:YES completion:nil];
-}
-
-// Show a MD snack bar with |message| and provide haptic feedback. The haptic
-// feedback is either for success or for error, depending on |success|.
-- (void)showToast:(NSString*)message forSuccess:(BOOL)success {
-  TriggerHapticFeedbackForNotification(success
-                                           ? UINotificationFeedbackTypeSuccess
-                                           : UINotificationFeedbackTypeError);
-  MDCSnackbarMessage* copyPasswordResultMessage =
-      [MDCSnackbarMessage messageWithText:message];
-  copyPasswordResultMessage.category = @"PasswordsSnackbarCategory";
-  [self.dispatcher showSnackbarMessage:copyPasswordResultMessage
-                          bottomOffset:0];
-}
-
-// Deletes the password with a deletion confirmation alert.
-- (void)deletePassword {
-  __weak LegacyPasswordDetailsTableViewController* weakSelf = self;
-
-  self.deleteConfirmation = [UIAlertController
-      alertControllerWithTitle:nil
-                       message:nil
-                preferredStyle:UIAlertControllerStyleActionSheet];
-  _deleteConfirmation.view.accessibilityIdentifier =
-      kPasswordDetailsDeletionAlertViewId;
-
-  UIAlertAction* cancelAction = [UIAlertAction
-      actionWithTitle:l10n_util::GetNSString(IDS_IOS_CANCEL_PASSWORD_DELETION)
-                style:UIAlertActionStyleCancel
-              handler:^(UIAlertAction* action) {
-                weakSelf.deleteConfirmation = nil;
-              }];
-  [_deleteConfirmation addAction:cancelAction];
-
-  UIAlertAction* deleteAction = [UIAlertAction
-      actionWithTitle:l10n_util::GetNSString(IDS_IOS_CONFIRM_PASSWORD_DELETION)
-                style:UIAlertActionStyleDestructive
-              handler:^(UIAlertAction* action) {
-                weakSelf.deleteConfirmation = nil;
-                [weakSelf.delegate
-                    passwordDetailsTableViewController:weakSelf
-                                        deletePassword:_passwordForm];
-              }];
-  [_deleteConfirmation addAction:deleteAction];
-
-  // Starting with iOS13, alerts of style UIAlertControllerStyleActionSheet
-  // need a sourceView or sourceRect, or this crashes.
-  if (base::ios::IsRunningOnIOS13OrLater() && IsIPadIdiom()) {
-    _deleteConfirmation.popoverPresentationController.sourceView =
-        self.tableView;
-  }
-
-  [self presentViewController:_deleteConfirmation animated:YES completion:nil];
-}
-
-// Returns an array of UIMenuItems to display in a context menu on the site
-// cell.
-- (NSArray*)getSiteMenuItems {
-  UIMenuItem* copyOption = [[UIMenuItem alloc]
-      initWithTitle:l10n_util::GetNSString(IDS_IOS_SETTINGS_SITE_COPY_MENU_ITEM)
-             action:@selector(copySite)];
-  return @[ copyOption ];
-}
-
-// Returns an array of UIMenuItems to display in a context menu on the username
-// cell.
-- (NSArray*)getUsernameMenuItems {
-  UIMenuItem* copyOption = [[UIMenuItem alloc]
-      initWithTitle:l10n_util::GetNSString(
-                        IDS_IOS_SETTINGS_USERNAME_COPY_MENU_ITEM)
-             action:@selector(copyUsername)];
-  return @[ copyOption ];
-}
-
-// Returns an array of UIMenuItems to display in a context menu on the password
-// cell.
-- (NSArray*)getPasswordMenuItems {
-  UIMenuItem* copyOption = [[UIMenuItem alloc]
-      initWithTitle:l10n_util::GetNSString(
-                        IDS_IOS_SETTINGS_PASSWORD_COPY_MENU_ITEM)
-             action:@selector(copyPassword)];
-  UIMenuItem* showOption = [[UIMenuItem alloc]
-      initWithTitle:l10n_util::GetNSString(
-                        IDS_IOS_SETTINGS_PASSWORD_SHOW_MENU_ITEM)
-             action:@selector(showPassword)];
-  UIMenuItem* hideOption = [[UIMenuItem alloc]
-      initWithTitle:l10n_util::GetNSString(
-                        IDS_IOS_SETTINGS_PASSWORD_HIDE_MENU_ITEM)
-             action:@selector(hidePassword)];
-  return @[ copyOption, showOption, hideOption ];
-}
-
-// If the context menu is not shown for a given item type, constructs that
-// menu and shows it. This method should only be called for item types
-// representing the cells with the site, username and password.
-- (void)ensureContextMenuShownForItemType:(NSInteger)itemType
-                                tableView:(UITableView*)tableView
-                              atIndexPath:(NSIndexPath*)indexPath {
-  UIMenuController* menu = [UIMenuController sharedMenuController];
-  if (![menu isMenuVisible]) {
-    NSArray* options = nil;
-    switch (itemType) {
-      case ItemTypeSite:
-        options = [self getSiteMenuItems];
-        break;
-      case ItemTypeUsername:
-        options = [self getUsernameMenuItems];
-        break;
-      case ItemTypePassword:
-        options = [self getPasswordMenuItems];
-        break;
-      default:
-        NOTREACHED();
-    }
-    [menu setMenuItems:options];
-    if (@available(iOS 13, *)) {
-      [menu showMenuFromView:tableView
-                        rect:[tableView rectForRowAtIndexPath:indexPath]];
-    } else {
-      [menu setTargetRect:[tableView rectForRowAtIndexPath:indexPath]
-                   inView:tableView];
-      [menu setMenuVisible:YES animated:YES];
-    }
-  }
-}
-
-#pragma mark - UITableViewDelegate
-
-- (void)tableView:(UITableView*)tableView
-    didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
-  [super tableView:tableView didSelectRowAtIndexPath:indexPath];
-  NSInteger itemType = [self.tableViewModel itemTypeForIndexPath:indexPath];
-  switch (itemType) {
-    case ItemTypeSite:
-    case ItemTypeUsername:
-    case ItemTypePassword:
-      [self ensureContextMenuShownForItemType:itemType
-                                    tableView:tableView
-                                  atIndexPath:indexPath];
-      break;
-    case ItemTypeCopySite:
-      [self copySite];
-      break;
-    case ItemTypeCopyUsername:
-      [self copyUsername];
-      break;
-    case ItemTypeShowHide:
-      if (_plainTextPasswordShown) {
-        [self hidePassword];
-      } else {
-        [self showPassword];
-      }
-      break;
-    case ItemTypeCopyPassword:
-      [self copyPassword];
-      break;
-    case ItemTypeDelete:
-      [self deletePassword];
-      break;
-    default:
-      break;
-  }
-  [tableView deselectRowAtIndexPath:indexPath animated:YES];
-}
-
-#pragma mark - Metrics
-
-// Logs metrics for the given reauthentication result (success, failure or
-// skipped).
-- (void)logPasswordSettingsReauthResult:(ReauthenticationResult)result {
-  switch (result) {
-    case ReauthenticationResult::kSuccess:
-      LogPasswordSettingsReauthResult(ReauthResult::kSuccess);
-      break;
-    case ReauthenticationResult::kFailure:
-      LogPasswordSettingsReauthResult(ReauthResult::kFailure);
-      break;
-    case ReauthenticationResult::kSkipped:
-      LogPasswordSettingsReauthResult(ReauthResult::kSkipped);
-      break;
-  }
-}
-
-#pragma mark - ForTesting
-
-- (void)setReauthenticationModule:
-    (id<ReauthenticationProtocol>)reauthenticationModule {
-  _weakReauthenticationModule = reauthenticationModule;
-}
-
-#pragma mark - UIResponder
-
-- (BOOL)canBecomeFirstResponder {
-  return YES;
-}
-
-- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
-  if (action == @selector(copySite) || action == @selector(copyUsername) ||
-      action == @selector(copyPassword) ||
-      (_plainTextPasswordShown && action == @selector(hidePassword)) ||
-      (!_plainTextPasswordShown && action == @selector(showPassword))) {
-    return YES;
-  }
-  return NO;
-}
-
-@end
diff --git a/ios/chrome/browser/ui/settings/password/legacy_password_details_table_view_controller_delegate.h b/ios/chrome/browser/ui/settings/password/legacy_password_details_table_view_controller_delegate.h
deleted file mode 100644
index b456ad2..0000000
--- a/ios/chrome/browser/ui/settings/password/legacy_password_details_table_view_controller_delegate.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_LEGACY_PASSWORD_DETAILS_TABLE_VIEW_CONTROLLER_DELEGATE_H_
-#define IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_LEGACY_PASSWORD_DETAILS_TABLE_VIEW_CONTROLLER_DELEGATE_H_
-
-#import <Foundation/Foundation.h>
-
-#include "components/password_manager/core/browser/password_form_forward.h"
-
-@class LegacyPasswordDetailsTableViewController;
-
-// PasswordDetailsTableViewController uses this protocol to interact with higher
-// level password controller.
-@protocol LegacyPasswordDetailsTableViewControllerDelegate
-
-- (void)passwordDetailsTableViewController:
-            (LegacyPasswordDetailsTableViewController*)controller
-                            deletePassword:
-                                (const password_manager::PasswordForm&)
-                                    passwordForm;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_LEGACY_PASSWORD_DETAILS_TABLE_VIEW_CONTROLLER_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/settings/password/legacy_password_details_table_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/password/legacy_password_details_table_view_controller_unittest.mm
deleted file mode 100644
index 87b34785..0000000
--- a/ios/chrome/browser/ui/settings/password/legacy_password_details_table_view_controller_unittest.mm
+++ /dev/null
@@ -1,302 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/settings/password/legacy_password_details_table_view_controller.h"
-
-#include "base/mac/foundation_util.h"
-#include "base/strings/sys_string_conversions.h"
-#include "components/password_manager/core/browser/password_form.h"
-#import "ios/chrome/browser/ui/table_view/cells/table_view_text_item.h"
-#import "ios/chrome/browser/ui/table_view/chrome_table_view_controller_test.h"
-#import "ios/chrome/browser/web/chrome_web_test.h"
-#import "ios/chrome/common/ui/reauthentication/reauthentication_module.h"
-#include "ios/chrome/grit/ios_strings.h"
-#include "ios/chrome/test/app/password_test_util.h"
-#include "ios/web/public/test/web_task_environment.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "third_party/ocmock/OCMock/OCMock.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "url/gurl.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-
-NSString* const kSite = @"https://testorigin.com/";
-NSString* const kUsername = @"testusername";
-NSString* const kPassword = @"testpassword";
-
-// Indices related to the layout for a non-blocked, non-federated password.
-const int kSiteSection = 0;
-const int kSiteItem = 0;
-const int kCopySiteButtonItem = 1;
-
-const int kUsernameSection = 1;
-const int kUsernameItem = 0;
-const int kCopyUsernameButtonItem = 1;
-
-const int kPasswordSection = 2;
-const int kPasswordItem = 0;
-const int kCopyPasswordButtonItem = 1;
-const int kShowHideButtonItem = 2;
-
-const int kDeleteSection = 3;
-const int kDeleteButtonItem = 0;
-
-class LegacyPasswordDetailsTableViewControllerTest
-    : public ChromeTableViewControllerTest {
- protected:
-  LegacyPasswordDetailsTableViewControllerTest() {
-    origin_ = kSite;
-    form_.username_value = base::SysNSStringToUTF16(kUsername);
-    form_.password_value = base::SysNSStringToUTF16(kPassword);
-    form_.signon_realm = base::SysNSStringToUTF8(origin_);
-    form_.url = GURL(form_.signon_realm);
-  }
-
-  void SetUp() override {
-    ChromeTableViewControllerTest::SetUp();
-    reauthentication_module_ = [[MockReauthenticationModule alloc] init];
-    reauthentication_module_.expectedResult = ReauthenticationResult::kSuccess;
-  }
-
-  ChromeTableViewController* InstantiateController() override {
-    return [[LegacyPasswordDetailsTableViewController alloc]
-          initWithPasswordForm:form_
-                      delegate:
-                          OCMProtocolMock(@protocol(
-                              LegacyPasswordDetailsTableViewControllerDelegate))
-        reauthenticationModule:reauthentication_module_];
-  }
-
-  web::WebTaskEnvironment task_environment_;
-  MockReauthenticationModule* reauthentication_module_;
-  NSString* origin_;
-  password_manager::PasswordForm form_;
-};
-
-TEST_F(LegacyPasswordDetailsTableViewControllerTest,
-       TestInitialization_NormalPassword) {
-  CreateController();
-  CheckController();
-  EXPECT_EQ(4, NumberOfSections());
-  // Site section
-  EXPECT_EQ(2, NumberOfItemsInSection(kSiteSection));
-  CheckSectionHeaderWithId(IDS_IOS_SHOW_PASSWORD_VIEW_SITE, kSiteSection);
-  TableViewTextItem* siteItem = GetTableViewItem(kSiteSection, kSiteItem);
-  EXPECT_NSEQ(origin_, siteItem.text);
-  EXPECT_FALSE(siteItem.masked);
-  CheckTextCellTextWithId(IDS_IOS_SETTINGS_SITE_COPY_BUTTON, kSiteSection,
-                          kCopySiteButtonItem);
-  // Username section
-  EXPECT_EQ(2, NumberOfItemsInSection(kUsernameSection));
-  CheckSectionHeaderWithId(IDS_IOS_SHOW_PASSWORD_VIEW_USERNAME,
-                           kUsernameSection);
-  TableViewTextItem* usernameItem =
-      GetTableViewItem(kUsernameSection, kUsernameItem);
-  EXPECT_NSEQ(kUsername, usernameItem.text);
-  EXPECT_FALSE(usernameItem.masked);
-  CheckTextCellTextWithId(IDS_IOS_SETTINGS_USERNAME_COPY_BUTTON,
-                          kUsernameSection, kCopyUsernameButtonItem);
-  // Password section
-  EXPECT_EQ(3, NumberOfItemsInSection(kPasswordSection));
-  CheckSectionHeaderWithId(IDS_IOS_SHOW_PASSWORD_VIEW_PASSWORD,
-                           kPasswordSection);
-  TableViewTextItem* passwordItem =
-      GetTableViewItem(kPasswordSection, kPasswordItem);
-  EXPECT_NSEQ(kPassword, passwordItem.text);
-  EXPECT_TRUE(passwordItem.masked);
-  CheckTextCellTextWithId(IDS_IOS_SETTINGS_PASSWORD_COPY_BUTTON,
-                          kPasswordSection, kCopyPasswordButtonItem);
-  CheckTextCellTextWithId(IDS_IOS_SETTINGS_PASSWORD_SHOW_BUTTON,
-                          kPasswordSection, kShowHideButtonItem);
-  // Delete section
-  EXPECT_EQ(1, NumberOfItemsInSection(kDeleteSection));
-  CheckTextCellTextWithId(IDS_IOS_SETTINGS_PASSWORD_DELETE_BUTTON,
-                          kDeleteSection, kDeleteButtonItem);
-}
-
-TEST_F(LegacyPasswordDetailsTableViewControllerTest,
-       TestInitialization_Blocked) {
-  constexpr int kBlockedSiteSection = 0;
-  constexpr int kBlockedSiteItem = 0;
-  constexpr int kBlockedCopySiteButtonItem = 1;
-
-  constexpr int kBlockedDeleteSection = 1;
-  constexpr int kBlockedDeleteButtonItem = 0;
-
-  form_.username_value.clear();
-  form_.password_value.clear();
-  form_.blocked_by_user = true;
-  CreateController();
-  CheckController();
-  EXPECT_EQ(2, NumberOfSections());
-  // Site section
-  EXPECT_EQ(2, NumberOfItemsInSection(kBlockedSiteSection));
-  CheckSectionHeaderWithId(IDS_IOS_SHOW_PASSWORD_VIEW_SITE,
-                           kBlockedSiteSection);
-  TableViewTextItem* siteItem =
-      GetTableViewItem(kBlockedSiteSection, kBlockedSiteItem);
-  EXPECT_NSEQ(origin_, siteItem.text);
-  EXPECT_FALSE(siteItem.masked);
-  CheckTextCellTextWithId(IDS_IOS_SETTINGS_SITE_COPY_BUTTON,
-                          kBlockedSiteSection, kBlockedCopySiteButtonItem);
-  // Delete section
-  EXPECT_EQ(1, NumberOfItemsInSection(kBlockedDeleteSection));
-  CheckTextCellTextWithId(IDS_IOS_SETTINGS_PASSWORD_DELETE_BUTTON,
-                          kBlockedDeleteSection, kBlockedDeleteButtonItem);
-}
-
-TEST_F(LegacyPasswordDetailsTableViewControllerTest,
-       TestInitialization_Federated) {
-  constexpr int kFederatedSiteSection = 0;
-  constexpr int kFederatedSiteItem = 0;
-  constexpr int kFederatedCopySiteButtonItem = 1;
-
-  constexpr int kFederatedUsernameSection = 1;
-  constexpr int kFederatedUsernameItem = 0;
-  constexpr int kFederatedCopyUsernameButtonItem = 1;
-
-  constexpr int kFederatedFederationSection = 2;
-  constexpr int kFederatedFederationItem = 0;
-
-  constexpr int kFederatedDeleteSection = 3;
-  constexpr int kFederatedDeleteButtonItem = 0;
-
-  form_.password_value.clear();
-  form_.federation_origin =
-      url::Origin::Create(GURL("https://famous.provider.net"));
-  CreateController();
-  CheckController();
-  EXPECT_EQ(4, NumberOfSections());
-  // Site section
-  EXPECT_EQ(2, NumberOfItemsInSection(kFederatedSiteSection));
-  CheckSectionHeaderWithId(IDS_IOS_SHOW_PASSWORD_VIEW_SITE,
-                           kFederatedSiteSection);
-  TableViewTextItem* siteItem =
-      GetTableViewItem(kFederatedSiteSection, kFederatedSiteItem);
-  EXPECT_NSEQ(origin_, siteItem.text);
-  EXPECT_FALSE(siteItem.masked);
-  CheckTextCellTextWithId(IDS_IOS_SETTINGS_SITE_COPY_BUTTON,
-                          kFederatedSiteSection, kFederatedCopySiteButtonItem);
-  // Username section
-  EXPECT_EQ(2, NumberOfItemsInSection(kFederatedUsernameSection));
-  CheckSectionHeaderWithId(IDS_IOS_SHOW_PASSWORD_VIEW_USERNAME,
-                           kFederatedUsernameSection);
-  TableViewTextItem* usernameItem =
-      GetTableViewItem(kFederatedUsernameSection, kFederatedUsernameItem);
-  EXPECT_NSEQ(kUsername, usernameItem.text);
-  EXPECT_FALSE(usernameItem.masked);
-  CheckTextCellTextWithId(IDS_IOS_SETTINGS_USERNAME_COPY_BUTTON,
-                          kFederatedUsernameSection,
-                          kFederatedCopyUsernameButtonItem);
-  // Federated section
-  EXPECT_EQ(1, NumberOfItemsInSection(kFederatedFederationSection));
-  CheckSectionHeaderWithId(IDS_IOS_SHOW_PASSWORD_VIEW_FEDERATION,
-                           kFederatedFederationSection);
-  TableViewTextItem* federationItem =
-      GetTableViewItem(kFederatedFederationSection, kFederatedFederationItem);
-  EXPECT_NSEQ(@"famous.provider.net", federationItem.text);
-  EXPECT_FALSE(federationItem.masked);
-  // Delete section
-  EXPECT_EQ(1, NumberOfItemsInSection(kFederatedDeleteSection));
-  CheckTextCellTextWithId(IDS_IOS_SETTINGS_PASSWORD_DELETE_BUTTON,
-                          kFederatedDeleteSection, kFederatedDeleteButtonItem);
-}
-
-struct SimplifyOriginTestData {
-  GURL origin;
-  NSString* expectedSimplifiedOrigin;
-};
-
-TEST_F(LegacyPasswordDetailsTableViewControllerTest, SimplifyOrigin) {
-  SimplifyOriginTestData test_data[] = {
-      {GURL("http://test.com/index.php"), @"test.com"},
-      {GURL("https://example.com/index.php"), @"example.com"},
-      {GURL("android://"
-            "Qllt1FacrB0NYCeSFvmudHvssWBPFfC54EbtHTpFxukvw2wClI1rafcVB3kQOMxfJg"
-            "xbVAkGXvC_A52kbPL1EQ==@com.parkingpanda.mobile/"),
-       @"mobile.parkingpanda.com"}};
-
-  for (const auto& data : test_data) {
-    origin_ = base::SysUTF8ToNSString(data.origin.spec());
-    form_.signon_realm = base::SysNSStringToUTF8(origin_);
-    form_.url = GURL(form_.signon_realm);
-    CreateController();
-    EXPECT_NSEQ(data.expectedSimplifiedOrigin, controller().title)
-        << " for origin " << data.origin;
-    ResetController();
-  }
-}
-
-TEST_F(LegacyPasswordDetailsTableViewControllerTest, CopySite) {
-  CreateController();
-  [controller() tableView:[controller() tableView]
-      didSelectRowAtIndexPath:[NSIndexPath indexPathForRow:kCopySiteButtonItem
-                                                 inSection:kSiteSection]];
-  UIPasteboard* generalPasteboard = [UIPasteboard generalPasteboard];
-  EXPECT_NSEQ(origin_, generalPasteboard.string);
-}
-
-TEST_F(LegacyPasswordDetailsTableViewControllerTest, CopyUsername) {
-  CreateController();
-  [controller() tableView:[controller() tableView]
-      didSelectRowAtIndexPath:[NSIndexPath
-                                  indexPathForRow:kCopyUsernameButtonItem
-                                        inSection:kUsernameSection]];
-  UIPasteboard* generalPasteboard = [UIPasteboard generalPasteboard];
-  EXPECT_NSEQ(kUsername, generalPasteboard.string);
-}
-
-TEST_F(LegacyPasswordDetailsTableViewControllerTest, ShowPassword) {
-  CreateController();
-  [controller() tableView:[controller() tableView]
-      didSelectRowAtIndexPath:[NSIndexPath indexPathForRow:kShowHideButtonItem
-                                                 inSection:kPasswordSection]];
-  TableViewTextItem* passwordItem =
-      GetTableViewItem(kPasswordSection, kPasswordItem);
-  EXPECT_NSEQ(kPassword, passwordItem.text);
-  EXPECT_FALSE(passwordItem.masked);
-  EXPECT_NSEQ(
-      l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_REAUTH_REASON_SHOW),
-      reauthentication_module_.localizedReasonForAuthentication);
-  CheckTextCellTextWithId(IDS_IOS_SETTINGS_PASSWORD_HIDE_BUTTON,
-                          kPasswordSection, kShowHideButtonItem);
-}
-
-TEST_F(LegacyPasswordDetailsTableViewControllerTest, HidePassword) {
-  CreateController();
-  // First show the password.
-  [controller() tableView:[controller() tableView]
-      didSelectRowAtIndexPath:[NSIndexPath indexPathForRow:kShowHideButtonItem
-                                                 inSection:kPasswordSection]];
-  // Then hide it.
-  [controller() tableView:[controller() tableView]
-      didSelectRowAtIndexPath:[NSIndexPath indexPathForRow:kShowHideButtonItem
-                                                 inSection:kPasswordSection]];
-  TableViewTextItem* passwordItem =
-      GetTableViewItem(kPasswordSection, kPasswordItem);
-  EXPECT_NSEQ(kPassword, passwordItem.text);
-  EXPECT_TRUE(passwordItem.masked);
-  CheckTextCellTextWithId(IDS_IOS_SETTINGS_PASSWORD_SHOW_BUTTON,
-                          kPasswordSection, kShowHideButtonItem);
-}
-
-TEST_F(LegacyPasswordDetailsTableViewControllerTest, CopyPassword) {
-  CreateController();
-  [controller() tableView:[controller() tableView]
-      didSelectRowAtIndexPath:[NSIndexPath
-                                  indexPathForRow:kCopyPasswordButtonItem
-                                        inSection:kPasswordSection]];
-  UIPasteboard* generalPasteboard = [UIPasteboard generalPasteboard];
-  EXPECT_NSEQ(kPassword, generalPasteboard.string);
-  EXPECT_NSEQ(
-      l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_REAUTH_REASON_COPY),
-      reauthentication_module_.localizedReasonForAuthentication);
-}
-
-}  // namespace
diff --git a/ios/chrome/browser/ui/settings/password/passwords_coordinator.mm b/ios/chrome/browser/ui/settings/password/passwords_coordinator.mm
index 37495f5..94f06e78 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_coordinator.mm
+++ b/ios/chrome/browser/ui/settings/password/passwords_coordinator.mm
@@ -17,8 +17,6 @@
 #include "ios/chrome/browser/sync/sync_setup_service_factory.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/commands/command_dispatcher.h"
-#import "ios/chrome/browser/ui/settings/password/legacy_password_details_table_view_controller.h"
-#import "ios/chrome/browser/ui/settings/password/legacy_password_details_table_view_controller_delegate.h"
 #import "ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.h"
 #import "ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator_delegate.h"
 #import "ios/chrome/browser/ui/settings/password/password_issues_coordinator.h"
@@ -35,7 +33,6 @@
 #endif
 
 @interface PasswordsCoordinator () <
-    LegacyPasswordDetailsTableViewControllerDelegate,
     PasswordDetailsCoordinatorDelegate,
     PasswordIssuesCoordinatorDelegate,
     PasswordsSettingsCommands,
@@ -152,26 +149,15 @@
 }
 
 - (void)showDetailedViewForForm:(const password_manager::PasswordForm&)form {
-  if (base::FeatureList::IsEnabled(
-          password_manager::features::kPasswordCheck)) {
-    DCHECK(!self.passwordDetailsCoordinator);
-    self.passwordDetailsCoordinator = [[PasswordDetailsCoordinator alloc]
-        initWithBaseNavigationController:self.baseNavigationController
-                                 browser:self.browser
-                                password:form
-                            reauthModule:self.reauthModule
-                    passwordCheckManager:[self passwordCheckManager].get()];
-    self.passwordDetailsCoordinator.delegate = self;
-    [self.passwordDetailsCoordinator start];
-  } else {
-    LegacyPasswordDetailsTableViewController* controller =
-        [[LegacyPasswordDetailsTableViewController alloc]
-              initWithPasswordForm:form
-                          delegate:self
-            reauthenticationModule:self.reauthModule];
-    controller.dispatcher = self.dispatcher;
-    [self.baseNavigationController pushViewController:controller animated:YES];
-  }
+  DCHECK(!self.passwordDetailsCoordinator);
+  self.passwordDetailsCoordinator = [[PasswordDetailsCoordinator alloc]
+      initWithBaseNavigationController:self.baseNavigationController
+                               browser:self.browser
+                              password:form
+                          reauthModule:self.reauthModule
+                  passwordCheckManager:[self passwordCheckManager].get()];
+  self.passwordDetailsCoordinator.delegate = self;
+  [self.passwordDetailsCoordinator start];
 }
 
 #pragma mark - PasswordsTableViewControllerPresentationDelegate
@@ -213,15 +199,6 @@
   [self.passwordsViewController deletePasswordForm:password];
 }
 
-#pragma mark LegacyPasswordDetailsTableViewControllerDelegate
-
-- (void)passwordDetailsTableViewController:
-            (LegacyPasswordDetailsTableViewController*)controller
-                            deletePassword:
-                                (const password_manager::PasswordForm&)form {
-  [self.passwordsViewController deletePasswordForm:form];
-}
-
 #pragma mark Private
 
 - (scoped_refptr<IOSChromePasswordCheckManager>)passwordCheckManager {
diff --git a/ios/chrome/browser/ui/settings/password/passwords_mediator.mm b/ios/chrome/browser/ui/settings/password/passwords_mediator.mm
index e9e87c4..c104d27 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_mediator.mm
+++ b/ios/chrome/browser/ui/settings/password/passwords_mediator.mm
@@ -93,13 +93,9 @@
     _passwordStoreObserver =
         std::make_unique<PasswordStoreObserverBridge>(self);
     _passwordStore->AddObserver(_passwordStoreObserver.get());
-
-    if (base::FeatureList::IsEnabled(
-            password_manager::features::kPasswordCheck)) {
-      _passwordCheckManager = passwordCheckManager;
-      _passwordCheckObserver = std::make_unique<PasswordCheckObserverBridge>(
-          self, _passwordCheckManager.get());
-    }
+    _passwordCheckManager = passwordCheckManager;
+    _passwordCheckObserver = std::make_unique<PasswordCheckObserverBridge>(
+        self, _passwordCheckManager.get());
   }
   return self;
 }
@@ -108,6 +104,9 @@
   if (_passwordStoreObserver) {
     _passwordStore->RemoveObserver(_passwordStoreObserver.get());
   }
+  if (_passwordCheckObserver) {
+    _passwordCheckManager->RemoveObserver(_passwordCheckObserver.get());
+  }
 }
 
 - (void)setConsumer:(id<PasswordsConsumer>)consumer {
@@ -116,15 +115,12 @@
   _consumer = consumer;
   [self loginsDidChange];
 
-  if (base::FeatureList::IsEnabled(
-          password_manager::features::kPasswordCheck)) {
-    _currentState = _passwordCheckManager->GetPasswordCheckState();
-    [self.consumer setPasswordCheckUIState:
-                       [self computePasswordCheckUIStateWith:_currentState]
-                 compromisedPasswordsCount:_passwordCheckManager
-                                               ->GetCompromisedCredentials()
-                                               .size()];
-  }
+  _currentState = _passwordCheckManager->GetPasswordCheckState();
+  [self.consumer setPasswordCheckUIState:
+                     [self computePasswordCheckUIStateWith:_currentState]
+               compromisedPasswordsCount:_passwordCheckManager
+                                             ->GetCompromisedCredentials()
+                                             .size()];
 }
 
 #pragma mark - PasswordsTableViewControllerDelegate
diff --git a/ios/chrome/browser/ui/settings/password/passwords_mediator_unittest.mm b/ios/chrome/browser/ui/settings/password/passwords_mediator_unittest.mm
index d3edffda..26e22f9 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/settings/password/passwords_mediator_unittest.mm
@@ -87,8 +87,6 @@
  protected:
   void SetUp() override {
     BlockCleanupTest::SetUp();
-    scoped_feature_list_.InitAndEnableFeature(
-        password_manager::features::kPasswordCheck);
 
     TestChromeBrowserState::Builder builder;
     builder.AddTestingFactory(
@@ -134,7 +132,6 @@
   scoped_refptr<IOSChromePasswordCheckManager> password_check_;
   FakePasswordsConsumer* consumer_;
   PasswordsMediator* mediator_;
-  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 TEST_F(PasswordsMediatorTest, ElapsedTimeSinceLastCheck) {
diff --git a/ios/chrome/browser/ui/settings/password/passwords_settings_egtest.mm b/ios/chrome/browser/ui/settings/password/passwords_settings_egtest.mm
index 3fc2544..c932150 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_settings_egtest.mm
+++ b/ios/chrome/browser/ui/settings/password/passwords_settings_egtest.mm
@@ -312,12 +312,9 @@
 - (AppLaunchConfiguration)appConfigurationForTestCase {
   AppLaunchConfiguration config;
 
-  // Password Check Feature is enabled for all tests. This is done because it
+  // Password Editing Feature is enabled by test name. This is done because it
   // is inefficient to use ensureAppLaunchedWithConfiguration for each test.
   // This should be removed once test config is modified.
-  // TODO(crbug.com/1075494): Remove this once feature is launched.
-  config.features_enabled.push_back(password_manager::features::kPasswordCheck);
-
   if ([self isRunningTest:@selector(testEditUsername)] ||
       [self isRunningTest:@selector(testEditUsernameFails)]) {
     config.features_enabled.push_back(
diff --git a/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm b/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm
index a00c3dc..765d4c9 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm
@@ -414,31 +414,28 @@
         forSectionWithIdentifier:SectionIdentifierSavePasswordsSwitch];
   }
 
-  if (base::FeatureList::IsEnabled(
-          password_manager::features::kPasswordCheck)) {
-    // Password check.
-    [model addSectionWithIdentifier:SectionIdentifierPasswordCheck];
-    if (!_passwordProblemsItem) {
-      _passwordProblemsItem = [self passwordProblemsItem];
-    }
-
-    [self updatePasswordCheckStatusLabelWithState:_passwordCheckState];
-    [model addItem:_passwordProblemsItem
-        toSectionWithIdentifier:SectionIdentifierPasswordCheck];
-
-    if (!_checkForProblemsItem) {
-      _checkForProblemsItem = [self checkForProblemsItem];
-    }
-
-    [self updatePasswordCheckButtonWithState:_passwordCheckState];
-    [model addItem:_checkForProblemsItem
-        toSectionWithIdentifier:SectionIdentifierPasswordCheck];
-
-    [self updateLastCheckTimestampWithState:_passwordCheckState
-                                  fromState:_passwordCheckState
-                                     update:NO];
+  // Password check.
+  [model addSectionWithIdentifier:SectionIdentifierPasswordCheck];
+  if (!_passwordProblemsItem) {
+    _passwordProblemsItem = [self passwordProblemsItem];
   }
 
+  [self updatePasswordCheckStatusLabelWithState:_passwordCheckState];
+  [model addItem:_passwordProblemsItem
+      toSectionWithIdentifier:SectionIdentifierPasswordCheck];
+
+  if (!_checkForProblemsItem) {
+    _checkForProblemsItem = [self checkForProblemsItem];
+  }
+
+  [self updatePasswordCheckButtonWithState:_passwordCheckState];
+  [model addItem:_checkForProblemsItem
+      toSectionWithIdentifier:SectionIdentifierPasswordCheck];
+
+  [self updateLastCheckTimestampWithState:_passwordCheckState
+                                fromState:_passwordCheckState
+                                   update:NO];
+
   // Saved passwords.
   if (!_savedForms.empty()) {
     [model addSectionWithIdentifier:SectionIdentifierSavedPasswords];
@@ -724,13 +721,11 @@
 
 - (void)setPasswordsForms:
     (std::vector<std::unique_ptr<password_manager::PasswordForm>>)results {
-  if (base::FeatureList::IsEnabled(
-          password_manager::features::kPasswordCheck)) {
-    _blockedForms.clear();
-    _savedForms.clear();
-    _savedPasswordDuplicates.clear();
-    _blockedPasswordDuplicates.clear();
-  }
+  _blockedForms.clear();
+  _savedForms.clear();
+  _savedPasswordDuplicates.clear();
+  _blockedPasswordDuplicates.clear();
+
   _didReceiveSavedForms = YES;
   [self hideLoadingSpinnerBackground];
   if (results.empty()) {
@@ -799,11 +794,8 @@
   // Remove save passwords switch section and password check section.
   [self
       performBatchTableViewUpdates:^{
-        if (base::FeatureList::IsEnabled(
-                password_manager::features::kPasswordCheck)) {
-          [self clearSectionWithIdentifier:SectionIdentifierPasswordCheck
-                          withRowAnimation:UITableViewRowAnimationTop];
-        }
+        [self clearSectionWithIdentifier:SectionIdentifierPasswordCheck
+                        withRowAnimation:UITableViewRowAnimationTop];
 
         [self clearSectionWithIdentifier:SectionIdentifierSavePasswordsSwitch
                         withRowAnimation:UITableViewRowAnimationTop];
@@ -837,25 +829,21 @@
             arrayWithObjects:[NSIndexPath indexPathForRow:0
                                                 inSection:switchSection],
                              nil];
+        [model insertSectionWithIdentifier:SectionIdentifierPasswordCheck
+                                   atIndex:1];
+        NSInteger checkSection =
+            [model sectionForSectionIdentifier:SectionIdentifierPasswordCheck];
 
-        if (base::FeatureList::IsEnabled(
-                password_manager::features::kPasswordCheck)) {
-          [model insertSectionWithIdentifier:SectionIdentifierPasswordCheck
-                                     atIndex:1];
-          NSInteger checkSection = [model
-              sectionForSectionIdentifier:SectionIdentifierPasswordCheck];
-
-          [self.tableView insertSections:[NSIndexSet indexSetWithIndex:1]
-                        withRowAnimation:UITableViewRowAnimationTop];
-          [model addItem:_passwordProblemsItem
-              toSectionWithIdentifier:SectionIdentifierPasswordCheck];
-          [model addItem:_checkForProblemsItem
-              toSectionWithIdentifier:SectionIdentifierPasswordCheck];
-          [rowsIndexPaths addObject:[NSIndexPath indexPathForRow:0
-                                                       inSection:checkSection]];
-          [rowsIndexPaths addObject:[NSIndexPath indexPathForRow:1
-                                                       inSection:checkSection]];
-        }
+        [self.tableView insertSections:[NSIndexSet indexSetWithIndex:1]
+                      withRowAnimation:UITableViewRowAnimationTop];
+        [model addItem:_passwordProblemsItem
+            toSectionWithIdentifier:SectionIdentifierPasswordCheck];
+        [model addItem:_checkForProblemsItem
+            toSectionWithIdentifier:SectionIdentifierPasswordCheck];
+        [rowsIndexPaths addObject:[NSIndexPath indexPathForRow:0
+                                                     inSection:checkSection]];
+        [rowsIndexPaths addObject:[NSIndexPath indexPathForRow:1
+                                                     inSection:checkSection]];
 
         [self.tableView insertRowsAtIndexPaths:rowsIndexPaths
                               withRowAnimation:UITableViewRowAnimationTop];
diff --git a/ios/chrome/browser/ui/settings/password/passwords_table_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/password/passwords_table_view_controller_unittest.mm
index 1ef1032..4b58d5d5 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_table_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/settings/password/passwords_table_view_controller_unittest.mm
@@ -26,7 +26,6 @@
 #include "ios/chrome/browser/passwords/password_check_observer_bridge.h"
 #include "ios/chrome/browser/passwords/save_passwords_consumer.h"
 #import "ios/chrome/browser/ui/settings/cells/settings_check_item.h"
-#import "ios/chrome/browser/ui/settings/password/legacy_password_details_table_view_controller.h"
 #import "ios/chrome/browser/ui/settings/password/passwords_consumer.h"
 #import "ios/chrome/browser/ui/settings/password/passwords_mediator.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h"
@@ -76,23 +75,11 @@
   ExportPasswordsButton,
 };
 
-class PasswordsTableViewControllerTest
-    : public ChromeTableViewControllerTest,
-      public ::testing::WithParamInterface<PasswordCheckFeatureStatus> {
+class PasswordsTableViewControllerTest : public ChromeTableViewControllerTest {
  protected:
   PasswordsTableViewControllerTest() = default;
 
   void SetUp() override {
-    // TODO(crbug.com/1096986): Remove parametrized tests once the feature is
-    // enabled.
-    if (GetParam().password_check_enabled) {
-      scoped_feature_list_.InitAndEnableFeature(
-          password_manager::features::kPasswordCheck);
-    } else {
-      scoped_feature_list_.InitAndDisableFeature(
-          password_manager::features::kPasswordCheck);
-    }
-
     browser_ = std::make_unique<TestBrowser>();
     ChromeTableViewControllerTest::SetUp();
     IOSChromePasswordStoreFactory::GetInstance()->SetTestingFactory(
@@ -135,15 +122,15 @@
       case PasswordCheck:
         return section;
       case SavedPasswords:
-        return GetParam().password_check_enabled ? 2 : 1;
+        return 2;
       case Blocked:
-        return GetParam().password_check_enabled ? 3 : 2;
+        return 3;
       case ExportPasswordsButton:
-        return GetParam().password_check_enabled ? 3 : 2;
+        return 3;
     }
   }
 
-  int SectionsOffset() { return GetParam().password_check_enabled ? 1 : 0; }
+  int SectionsOffset() { return 1; }
 
   TestPasswordStore& GetTestStore() {
     return *static_cast<TestPasswordStore*>(
@@ -173,17 +160,8 @@
 
   // Adds a form to PasswordsTableViewController.
   void AddPasswordForm(std::unique_ptr<password_manager::PasswordForm> form) {
-    if (GetParam().password_check_enabled) {
-      GetTestStore().AddLogin(*form);
-      RunUntilIdle();
-    } else {
-      PasswordsTableViewController* passwords_controller =
-          static_cast<PasswordsTableViewController*>(controller());
-      GetTestStore().AddLogin(*form);
-      std::vector<std::unique_ptr<password_manager::PasswordForm>> passwords;
-      passwords.push_back(std::move(form));
-      [passwords_controller setPasswordsForms:std::move(passwords)];
-    }
+    GetTestStore().AddLogin(*form);
+    RunUntilIdle();
   }
 
   // Creates and adds a saved password form.
@@ -297,18 +275,17 @@
 
   web::WebTaskEnvironment task_environment_;
   std::unique_ptr<TestBrowser> browser_;
-  base::test::ScopedFeatureList scoped_feature_list_;
   PasswordsMediator* mediator_;
 };
 
 // Tests default case has no saved sites and no blocked sites.
-TEST_P(PasswordsTableViewControllerTest, TestInitialization) {
+TEST_F(PasswordsTableViewControllerTest, TestInitialization) {
   CheckController();
   EXPECT_EQ(2 + SectionsOffset(), NumberOfSections());
 }
 
 // Tests adding one item in saved password section.
-TEST_P(PasswordsTableViewControllerTest, AddSavedPasswords) {
+TEST_F(PasswordsTableViewControllerTest, AddSavedPasswords) {
   AddSavedForm1();
 
   EXPECT_EQ(3 + SectionsOffset(), NumberOfSections());
@@ -316,7 +293,7 @@
 }
 
 // Tests adding one item in blocked password section.
-TEST_P(PasswordsTableViewControllerTest, AddBlockedPasswords) {
+TEST_F(PasswordsTableViewControllerTest, AddBlockedPasswords) {
   AddBlockedForm1();
 
   EXPECT_EQ(3 + SectionsOffset(), NumberOfSections());
@@ -325,7 +302,7 @@
 
 // Tests adding one item in saved password section, and two items in blocked
 // password section.
-TEST_P(PasswordsTableViewControllerTest, AddSavedAndBlocked) {
+TEST_F(PasswordsTableViewControllerTest, AddSavedAndBlocked) {
   AddSavedForm1();
   AddBlockedForm1();
   AddBlockedForm2();
@@ -340,7 +317,7 @@
 }
 
 // Tests the order in which the saved passwords are displayed.
-TEST_P(PasswordsTableViewControllerTest, TestSavedPasswordsOrder) {
+TEST_F(PasswordsTableViewControllerTest, TestSavedPasswordsOrder) {
   AddSavedForm2();
 
   CheckTextCellTextAndDetailText(@"example2.com", @"test@egmail.com",
@@ -354,7 +331,7 @@
 }
 
 // Tests the order in which the blocked passwords are displayed.
-TEST_P(PasswordsTableViewControllerTest, TestBlockedPasswordsOrder) {
+TEST_F(PasswordsTableViewControllerTest, TestBlockedPasswordsOrder) {
   AddBlockedForm2();
   CheckTextCellText(@"secret2.com", GetSectionIndex(SavedPasswords), 0);
 
@@ -365,7 +342,7 @@
 
 // Tests displaying passwords in the saved passwords section when there are
 // duplicates in the password store.
-TEST_P(PasswordsTableViewControllerTest, AddSavedDuplicates) {
+TEST_F(PasswordsTableViewControllerTest, AddSavedDuplicates) {
   AddSavedForm1();
   AddSavedForm1();
 
@@ -375,7 +352,7 @@
 
 // Tests displaying passwords in the blocked passwords section when there
 // are duplicates in the password store.
-TEST_P(PasswordsTableViewControllerTest, AddBlockedDuplicates) {
+TEST_F(PasswordsTableViewControllerTest, AddBlockedDuplicates) {
   AddBlockedForm1();
   AddBlockedForm1();
 
@@ -384,7 +361,7 @@
 }
 
 // Tests deleting items from saved passwords and blocked passwords sections.
-TEST_P(PasswordsTableViewControllerTest, DeleteItems) {
+TEST_F(PasswordsTableViewControllerTest, DeleteItems) {
   AddSavedForm1();
   AddBlockedForm1();
   AddBlockedForm2();
@@ -409,7 +386,7 @@
 
 // Tests deleting items from saved passwords and blocked passwords sections
 // when there are duplicates in the store.
-TEST_P(PasswordsTableViewControllerTest, DeleteItemsWithDuplicates) {
+TEST_F(PasswordsTableViewControllerTest, DeleteItemsWithDuplicates) {
   AddSavedForm1();
   AddSavedForm1();
   AddBlockedForm1();
@@ -434,7 +411,7 @@
   }));
 }
 
-TEST_P(PasswordsTableViewControllerTest,
+TEST_F(PasswordsTableViewControllerTest,
        TestExportButtonDisabledNoSavedPasswords) {
   PasswordsTableViewController* passwords_controller =
       static_cast<PasswordsTableViewController*>(controller());
@@ -458,7 +435,7 @@
               UIAccessibilityTraitNotEnabled);
 }
 
-TEST_P(PasswordsTableViewControllerTest,
+TEST_F(PasswordsTableViewControllerTest,
        TestExportButtonEnabledWithSavedPasswords) {
   PasswordsTableViewController* passwords_controller =
       static_cast<PasswordsTableViewController*>(controller());
@@ -477,7 +454,7 @@
 }
 
 // Tests that the "Export Passwords..." button is greyed out in edit mode.
-TEST_P(PasswordsTableViewControllerTest, TestExportButtonDisabledEditMode) {
+TEST_F(PasswordsTableViewControllerTest, TestExportButtonDisabledEditMode) {
   PasswordsTableViewController* passwords_controller =
       static_cast<PasswordsTableViewController*>(controller());
   AddSavedForm1();
@@ -497,7 +474,7 @@
 
 // Tests that the "Export Passwords..." button is enabled after exiting
 // edit mode.
-TEST_P(PasswordsTableViewControllerTest,
+TEST_F(PasswordsTableViewControllerTest,
        TestExportButtonEnabledWhenEdittingFinished) {
   PasswordsTableViewController* passwords_controller =
       static_cast<PasswordsTableViewController*>(controller());
@@ -518,7 +495,7 @@
 }
 
 // Tests filtering of items.
-TEST_P(PasswordsTableViewControllerTest, FilterItems) {
+TEST_F(PasswordsTableViewControllerTest, FilterItems) {
   AddSavedForm1();
   AddSavedForm2();
   AddBlockedForm1();
@@ -566,9 +543,7 @@
 }
 
 // Test verifies disabled state of password check cell.
-TEST_P(PasswordsTableViewControllerTest, PasswordCheckStateDisabled) {
-  if (!GetParam().password_check_enabled)
-    return;
+TEST_F(PasswordsTableViewControllerTest, PasswordCheckStateDisabled) {
   ChangePasswordCheckState(PasswordCheckStateDisabled);
 
   CheckDetailItemTextWithIds(IDS_IOS_CHECK_PASSWORDS,
@@ -582,10 +557,7 @@
 }
 
 // Test verifies default state of password check cell.
-TEST_P(PasswordsTableViewControllerTest, PasswordCheckStateDefault) {
-  if (!GetParam().password_check_enabled)
-    return;
-
+TEST_F(PasswordsTableViewControllerTest, PasswordCheckStateDefault) {
   ChangePasswordCheckState(PasswordCheckStateDefault);
 
   CheckTextCellTextWithId(IDS_IOS_CHECK_PASSWORDS_NOW_BUTTON,
@@ -601,10 +573,7 @@
 }
 
 // Test verifies safe state of password check cell.
-TEST_P(PasswordsTableViewControllerTest, PasswordCheckStateSafe) {
-  if (!GetParam().password_check_enabled)
-    return;
-
+TEST_F(PasswordsTableViewControllerTest, PasswordCheckStateSafe) {
   ChangePasswordCheckState(PasswordCheckStateSafe);
 
   CheckTextCellTextWithId(IDS_IOS_CHECK_PASSWORDS_NOW_BUTTON,
@@ -620,9 +589,7 @@
 }
 
 // Test verifies unsafe state of password check cell.
-TEST_P(PasswordsTableViewControllerTest, PasswordCheckStateUnSafe) {
-  if (!GetParam().password_check_enabled)
-    return;
+TEST_F(PasswordsTableViewControllerTest, PasswordCheckStateUnSafe) {
   AddSavedForm1();
   AddCompromisedCredential1();
   ChangePasswordCheckState(PasswordCheckStateUnSafe);
@@ -640,10 +607,7 @@
 }
 
 // Test verifies running state of password check cell.
-TEST_P(PasswordsTableViewControllerTest, PasswordCheckStateRunning) {
-  if (!GetParam().password_check_enabled)
-    return;
-
+TEST_F(PasswordsTableViewControllerTest, PasswordCheckStateRunning) {
   ChangePasswordCheckState(PasswordCheckStateRunning);
 
   CheckTextCellTextWithId(IDS_IOS_CHECK_PASSWORDS_NOW_BUTTON,
@@ -659,10 +623,7 @@
 }
 
 // Test verifies error state of password check cell.
-TEST_P(PasswordsTableViewControllerTest, PasswordCheckStateError) {
-  if (!GetParam().password_check_enabled)
-    return;
-
+TEST_F(PasswordsTableViewControllerTest, PasswordCheckStateError) {
   ChangePasswordCheckState(PasswordCheckStateError);
 
   CheckTextCellTextWithId(IDS_IOS_CHECK_PASSWORDS_NOW_BUTTON,
@@ -679,10 +640,7 @@
 }
 
 // Test verifies tapping start with no saved passwords has no effect.
-TEST_P(PasswordsTableViewControllerTest, DisabledPasswordCheck) {
-  if (!GetParam().password_check_enabled)
-    return;
-
+TEST_F(PasswordsTableViewControllerTest, DisabledPasswordCheck) {
   PasswordsTableViewController* passwords_controller =
       static_cast<PasswordsTableViewController*>(controller());
 
@@ -698,9 +656,7 @@
 }
 
 // Test verifies tapping start triggers correct function in service.
-TEST_P(PasswordsTableViewControllerTest, StartPasswordCheck) {
-  if (!GetParam().password_check_enabled)
-    return;
+TEST_F(PasswordsTableViewControllerTest, StartPasswordCheck) {
   AddSavedForm1();
   RunUntilIdle();
 
@@ -717,10 +673,7 @@
 }
 
 // Test verifies changes to the password store are reflected on UI.
-TEST_P(PasswordsTableViewControllerTest, PasswordStoreListener) {
-  if (!GetParam().password_check_enabled)
-    return;
-
+TEST_F(PasswordsTableViewControllerTest, PasswordStoreListener) {
   AddSavedForm1();
   EXPECT_EQ(1, NumberOfItemsInSection(GetSectionIndex(SavedPasswords)));
   AddSavedForm2();
@@ -734,9 +687,7 @@
 }
 
 // Test verifies Passwords View Controller handles deletion of passwords.
-TEST_P(PasswordsTableViewControllerTest, PasswordIssuesDeletion) {
-  if (!GetParam().password_check_enabled)
-    return;
+TEST_F(PasswordsTableViewControllerTest, PasswordIssuesDeletion) {
   AddSavedForm1();
   AddSavedForm2();
   EXPECT_EQ(2, NumberOfItemsInSection(GetSectionIndex(SavedPasswords)));
@@ -750,14 +701,4 @@
   EXPECT_EQ(1, NumberOfItemsInSection(GetSectionIndex(SavedPasswords)));
 }
 
-const std::vector<PasswordCheckFeatureStatus> kPasswordCheckFeatureStatusCases{
-    // Password check disabled
-    {FALSE},
-    // Password check enabled
-    {TRUE}};
-
-INSTANTIATE_TEST_SUITE_P(PasswordCheckDisabledAndEnabled,
-                         PasswordsTableViewControllerTest,
-                         ::testing::ValuesIn(kPasswordCheckFeatureStatusCases));
-
 }  // namespace
diff --git a/ios/chrome/test/app/password_test_util.mm b/ios/chrome/test/app/password_test_util.mm
index f93ae119..79435d6 100644
--- a/ios/chrome/test/app/password_test_util.mm
+++ b/ios/chrome/test/app/password_test_util.mm
@@ -5,7 +5,6 @@
 #include "ios/chrome/test/app/password_test_util.h"
 
 #include "base/mac/foundation_util.h"
-#import "ios/chrome/browser/ui/settings/password/legacy_password_details_table_view_controller+testing.h"
 #import "ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.h"
 #import "ios/chrome/browser/ui/settings/password/passwords_table_view_controller.h"
 #import "ios/chrome/browser/ui/settings/settings_navigation_controller.h"
diff --git a/ios/public/provider/chrome/browser/signin/chrome_identity_service.h b/ios/public/provider/chrome/browser/signin/chrome_identity_service.h
index d9234750..fa1eeae 100644
--- a/ios/public/provider/chrome/browser/signin/chrome_identity_service.h
+++ b/ios/public/provider/chrome/browser/signin/chrome_identity_service.h
@@ -9,6 +9,7 @@
 #include <string>
 #include <vector>
 
+#include "base/callback.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
 
@@ -157,19 +158,43 @@
 
   // Returns the chrome identity having the gaia ID equal to |gaia_id| or |nil|
   // if no matching identity is found.
+  // Before calling this method, the identity cache need to be populated.
+  // See RunAfterCacheIsPopulated() or WaitUntilCacheIsPopulated().
   virtual ChromeIdentity* GetIdentityWithGaiaID(const std::string& gaia_id);
 
   // Returns true if there is at least one identity.
+  // Before calling this method, the identity cache need to be populated.
+  // See RunAfterCacheIsPopulated() or WaitUntilCacheIsPopulated().
   virtual bool HasIdentities();
 
   // Returns all ChromeIdentity objects in an array.
+  // Before calling this method, the identity cache need to be populated.
+  // See RunAfterCacheIsPopulated() or WaitUntilCacheIsPopulated().
   virtual NSArray* GetAllIdentities();
 
   // Returns all ChromeIdentity objects sorted by the ordering used in the
   // account manager, which is typically based on the keychain ordering of
   // accounts.
+  // Before calling this method, the identity cache need to be populated.
+  // See RunAfterCacheIsPopulated() or WaitUntilCacheIsPopulated().
   virtual NSArray* GetAllIdentitiesSortedForDisplay();
 
+  // Invokes |callback| after the cache of identities is populated:
+  // * if cache is already populated, then |callback| is called on the next run
+  //   loop.
+  // * if cache is not populated, then |callback| is called once the cache of
+  //   identities is populated.
+  // If this method is call multiple times, the callbacks will be invoked in the
+  // same order.
+  virtual void RunAfterCacheIsPopulated(base::OnceClosure callback);
+
+  // Waits until the identity cache is populated. Does nothing if the cache is
+  // already populated.
+  // Note: This method blocks the main thread until the cache of identities if
+  // populated. RunAfterCacheIsPopulated() is highly suggested instead of this
+  // method.
+  virtual void WaitUntilCacheIsPopulated();
+
   // Forgets the given identity on the device. This method logs the user out.
   // It is asynchronous because it needs to contact the server to revoke the
   // authentication token.
diff --git a/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm b/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm
index 98e31ab..9d11980 100644
--- a/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm
+++ b/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm
@@ -82,6 +82,14 @@
   return nil;
 }
 
+void ChromeIdentityService::RunAfterCacheIsPopulated(
+    base::OnceClosure callback) {
+  if (!callback.is_null())
+    std::move(callback).Run();
+}
+
+void ChromeIdentityService::WaitUntilCacheIsPopulated() {}
+
 void ChromeIdentityService::ForgetIdentity(ChromeIdentity* identity,
                                            ForgetIdentityCallback callback) {}
 
diff --git a/ios/web/navigation/crw_wk_navigation_handler.mm b/ios/web/navigation/crw_wk_navigation_handler.mm
index 63cb684..2fc7d18 100644
--- a/ios/web/navigation/crw_wk_navigation_handler.mm
+++ b/ios/web/navigation/crw_wk_navigation_handler.mm
@@ -1052,14 +1052,6 @@
     didFinishNavigation:(WKNavigation*)navigation {
   [self didReceiveWKNavigationDelegateCallback];
 
-  NSUInteger forwardItemCount = webView.backForwardList.forwardList.count;
-  base::UmaHistogramBoolean("Session.WebStates.HasForwardItemsAfterNavigation",
-                            forwardItemCount > 0);
-  if (forwardItemCount > 0) {
-    base::UmaHistogramCounts100(
-        "Session.WebStates.ForwardItemsCountAfterNavigation", forwardItemCount);
-  }
-
   // Sometimes |webView:didFinishNavigation| arrives before
   // |webView:didCommitNavigation|. Explicitly trigger post-commit processing.
   bool navigationCommitted =
diff --git a/ios/web/web_state/js/resources/text_fragments.js b/ios/web/web_state/js/resources/text_fragments.js
index d5bd4405..b1fc6a48 100644
--- a/ios/web/web_state/js/resources/text_fragments.js
+++ b/ios/web/web_state/js/resources/text_fragments.js
@@ -57,11 +57,14 @@
     if (scroll && marks.length > 0)
       utils.scrollElementIntoView(marks[0]);
 
-    for (const mark of marks) {
-      mark.addEventListener("click", () => {
-        utils.removeMarks(marks);
-      });
-    }
+    // Clean-up marks whenever the user taps somewhere on the page. Use capture
+    // to make sure the event listener is executed immediately and cannot be
+    // prevented by the event target (during bubble phase).
+    document.addEventListener("click", function removeMarksFunction() {
+      utils.removeMarks(marks);
+      document.removeEventListener("click", removeMarksFunction,
+                                   /*useCapture=*/true);
+    }, /*useCapture=*/true);
 
     __gCrWeb.message.invokeOnHost({
       command: 'textFragments.response',
diff --git a/media/fuchsia/cdm/service/fuchsia_cdm_manager.cc b/media/fuchsia/cdm/service/fuchsia_cdm_manager.cc
index 856ce1ca..5e6546fa 100644
--- a/media/fuchsia/cdm/service/fuchsia_cdm_manager.cc
+++ b/media/fuchsia/cdm/service/fuchsia_cdm_manager.cc
@@ -17,10 +17,7 @@
 #include "base/fuchsia/fuchsia_logging.h"
 #include "base/hash/hash.h"
 #include "base/logging.h"
-#include "base/optional.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/task/task_traits.h"
-#include "base/task/thread_pool.h"
 #include "media/fuchsia/cdm/service/provisioning_fetcher_impl.h"
 #include "url/origin.h"
 
@@ -33,16 +30,6 @@
   return base::HexEncode(&hash, sizeof(uint32_t));
 }
 
-// Returns a nullopt if storage was created successfully.
-base::Optional<base::File::Error> CreateStorageDirectory(base::FilePath path) {
-  base::File::Error error;
-  bool success = base::CreateDirectoryAndGetError(path, &error);
-  if (!success) {
-    return error;
-  }
-  return {};
-}
-
 }  // namespace
 
 // Manages individual KeySystem connections. Provides data stores and
@@ -187,14 +174,24 @@
         request) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
-  base::FilePath storage_path = GetStoragePath(key_system, origin);
+  KeySystemClient* key_system_client = GetOrCreateKeySystemClient(key_system);
+  if (!key_system_client) {
+    // GetOrCreateKeySystemClient will log the reason for failure.
+    return;
+  }
 
-  base::ThreadPool::PostTaskAndReplyWithResult(
-      FROM_HERE, {base::MayBlock()},
-      base::BindOnce(&CreateStorageDirectory, storage_path),
-      base::BindOnce(&FuchsiaCdmManager::CreateCdm, weak_factory_.GetWeakPtr(),
-                     key_system, std::move(create_fetcher_cb),
-                     std::move(request), storage_path));
+  base::FilePath storage_path = GetStoragePath(key_system, origin);
+  base::File::Error error;
+  bool success = base::CreateDirectoryAndGetError(storage_path, &error);
+  if (!success) {
+    DLOG(ERROR) << "Failed to create directory: " << storage_path
+                << ", error: " << error;
+    return;
+  }
+
+  key_system_client->CreateCdm(std::move(storage_path),
+                               std::move(create_fetcher_cb),
+                               std::move(request));
 }
 
 void FuchsiaCdmManager::set_on_key_system_disconnect_for_test_callback(
@@ -244,35 +241,6 @@
       .Append(HexEncodeHash(key_system));
 }
 
-void FuchsiaCdmManager::CreateCdm(
-    const std::string& key_system_name,
-    CreateFetcherCB create_fetcher_cb,
-    fidl::InterfaceRequest<fuchsia::media::drm::ContentDecryptionModule>
-        request,
-    base::FilePath storage_path,
-    base::Optional<base::File::Error> storage_creation_error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  if (storage_creation_error) {
-    DLOG(ERROR) << "Failed to create directory: " << storage_path
-                << ", error: " << *storage_creation_error;
-    request.Close(ZX_ERR_NO_RESOURCES);
-    return;
-  }
-
-  KeySystemClient* key_system_client =
-      GetOrCreateKeySystemClient(key_system_name);
-  if (!key_system_client) {
-    // GetOrCreateKeySystemClient will log the reason for failure.
-    request.Close(ZX_ERR_NOT_FOUND);
-    return;
-  }
-
-  key_system_client->CreateCdm(std::move(storage_path),
-                               std::move(create_fetcher_cb),
-                               std::move(request));
-}
-
 void FuchsiaCdmManager::OnKeySystemClientError(
     const std::string& key_system_name) {
   if (on_key_system_disconnect_for_test_callback_) {
diff --git a/media/fuchsia/cdm/service/fuchsia_cdm_manager.h b/media/fuchsia/cdm/service/fuchsia_cdm_manager.h
index 746b708..c18629ee 100644
--- a/media/fuchsia/cdm/service/fuchsia_cdm_manager.h
+++ b/media/fuchsia/cdm/service/fuchsia_cdm_manager.h
@@ -10,11 +10,8 @@
 
 #include "base/callback_forward.h"
 #include "base/containers/flat_map.h"
-#include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/optional.h"
 #include "base/threading/thread_checker.h"
 #include "media/base/provision_fetcher.h"
 
@@ -66,13 +63,6 @@
   KeySystemClient* CreateKeySystemClient(const std::string& key_system_name);
   base::FilePath GetStoragePath(const std::string& key_system_name,
                                 const url::Origin& origin);
-  void CreateCdm(
-      const std::string& key_system_name,
-      CreateFetcherCB create_fetcher_cb,
-      fidl::InterfaceRequest<fuchsia::media::drm::ContentDecryptionModule>
-          request,
-      base::FilePath storage_path,
-      base::Optional<base::File::Error> storage_creation_error);
   void OnKeySystemClientError(const std::string& key_system_name);
 
   // A map of callbacks to create KeySystem channels indexed by their EME name.
@@ -89,7 +79,6 @@
       on_key_system_disconnect_for_test_callback_;
 
   THREAD_CHECKER(thread_checker_);
-  base::WeakPtrFactory<FuchsiaCdmManager> weak_factory_{this};
 };
 
 }  // namespace media
diff --git a/media/fuchsia/cdm/service/fuchsia_cdm_manager_test.cc b/media/fuchsia/cdm/service/fuchsia_cdm_manager_test.cc
index 3ff1d53..9455d7e 100644
--- a/media/fuchsia/cdm/service/fuchsia_cdm_manager_test.cc
+++ b/media/fuchsia/cdm/service/fuchsia_cdm_manager_test.cc
@@ -96,8 +96,8 @@
     return mock_key_systems_[key_system_name];
   }
 
-  base::test::TaskEnvironment task_environment_{
-      base::test::TaskEnvironment::MainThreadType::IO};
+  base::test::SingleThreadTaskEnvironment task_environment_{
+      base::test::SingleThreadTaskEnvironment::MainThreadType::IO};
 
   MockKeySystemMap mock_key_systems_;
   base::ScopedTempDir temp_dir_;
@@ -109,7 +109,7 @@
   base::RunLoop run_loop;
   drm::ContentDecryptionModulePtr cdm_ptr;
   cdm_ptr.set_error_handler([&](zx_status_t status) {
-    EXPECT_EQ(status, ZX_ERR_NOT_FOUND);
+    EXPECT_EQ(status, ZX_ERR_PEER_CLOSED);
     run_loop.Quit();
   });
 
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 65073d6..af9b6c2 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -437,7 +437,6 @@
       "base/host_mapping_rules.cc",
       "base/host_mapping_rules.h",
       "base/http_user_agent_settings.h",
-      "base/idempotency.h",
       "base/isolation_info.cc",
       "base/isolation_info.h",
       "base/load_flags.h",
diff --git a/net/base/idempotency.h b/net/base/idempotency.h
deleted file mode 100644
index ca5c6730..0000000
--- a/net/base/idempotency.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_BASE_IDEMPOTENCY_H_
-#define NET_BASE_IDEMPOTENCY_H_
-
-namespace net {
-
-// Idempotency of the request, which determines that if it is safe to enable
-// 0-RTT for the request. By default, 0-RTT is only enabled for safe
-// HTTP methods, i.e., GET, HEAD, OPTIONS, and TRACE. For other methods,
-// enabling 0-RTT may cause security issues since a network observer can replay
-// the request. If the request has any side effects, those effects can happen
-// multiple times. It is only safe to enable the 0-RTT if it is known that
-// the request is idempotent.
-enum Idempotency {
-  DEFAULT_IDEMPOTENCY = 0,
-  IDEMPOTENT = 1,
-  NOT_IDEMPOTENT = 2,
-};
-
-}  // namespace net
-
-#endif  // NET_BASE_IDEMPOTENCY_H_
diff --git a/net/data/fuzzer_dictionaries/net_dns_record_fuzzer.dict b/net/data/fuzzer_dictionaries/net_dns_record_fuzzer.dict
index 9793ef0..9208aeec 100644
--- a/net/data/fuzzer_dictionaries/net_dns_record_fuzzer.dict
+++ b/net/data/fuzzer_dictionaries/net_dns_record_fuzzer.dict
@@ -6,7 +6,8 @@
 
 # Some 16-bit big-endian values. Useful in a number of fields. Includes
 # A, AAAA, and CNAME IDs, low values for record counts, and multiples of
-# lengths of A and AAAA data fields.
+# lengths of A and AAAA data fields. Also some resulting data sizes from
+# combining HTTPS service parameters below with domain names below.
 "\x00\x00"
 "\x00\x01"
 "\x00\x02"
@@ -14,10 +15,25 @@
 "\x00\x04"
 "\x00\x05"
 "\x00\x08"
+"\x00\x0B"
 "\x00\x0C"
+"\x00\x0D"
+"\x00\x0E"
+"\x00\x0F"
 "\x00\x10"
+"\x00\x11"
+"\x00\x12"
+"\x00\x13"
+"\x00\x14"
+"\x00\x15"
+"\x00\x16"
+"\x00\x17"
+"\x00\x19"
+"\x00\x1B"
 "\x00\x1C"
+"\x00\x1F"
 "\x00\x20"
+"\x00\x21"
 "\x00\x30"
 
 # Some encoded domain names.
@@ -35,22 +51,25 @@
 "\x81\x80\x00\x01\x00\x02\x00\x00\x00\x00"
 "\x81\x80\x00\x01\x00\x10\x00\x00\x00\x00"
 
-# A, AAAA, and CNAME request suffixes - appear after domain name.
+# A, AAAA, CNAME, and HTTPS request suffixes - appear after domain name.
 "\x00\x01\x00\x01"
 "\x00\x1c\x00\x01"
 "\x00\x05\x00\x01"
+"\x00\x41\x00\x01"
 
 # ESNI (TLS 1.3 encrypted server name indication, experimental) draft 4
 # request suffix
 "\xff\x9f\x00\x01"
 
-# A, AAAA, and CNAME requests for foo and foo.com.
+# A, AAAA, CNAME, and HTTPS requests for foo and foo.com.
 "\x03foo\x00\x00\x01\x00\x01"
 "\x03foo\x00\x00\x1c\x00\x01"
 "\x03foo\x00\x00\x05\x00\x01"
+"\x03foo\x00\x00\x41\x00\x01"
 "\x03foo\x03com\x00\x00\x01\x00\x01"
 "\x03foo\x03com\x00\x00\x1c\x00\x01"
 "\x03foo\x03com\x00\x00\x05\x00\x01"
+"\x03foo\x03com\x00\x00\x41\x00\x01"
 
 # ESNI draft 4 (see above) requests for foo and foo.com
 "\x03foo\x00\xff\x9f\x00\x01"
@@ -74,6 +93,21 @@
 "\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x05\x03bar\x00"
 "\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x09\x03foo\x03com\x00"
 
+# HTTPS answer suffixes (without service params)
+"\x00\x41\x00\x01\x00\x00\x00\x10\x00\x07\x00\x00\x03foo\x00"
+"\x00\x41\x00\x01\x00\x00\x14\x00\x00\x03\x00\x00\x00"
+"\x00\x41\x00\x01\x00\x00\x00\x10\x00\x07\x00\x00\x03foo\x00"
+"\x00\x41\x00\x01\x00\x00\x14\x00\x00\x03\x00\x00\x00"
+
+# HTTPS service params
+"\x00\x01\x00\x08\x03foo\x03bar"
+"\x00\x02\x00\x00"
+"\x00\x03\x00\x02\x14\xC3"
+"\x00\x04\x00\x04\x08\x08\x08\x08"
+"\x00\x05\x00\x05hello"
+"\x00\x06\x00\x10\x20\x01\x48\x60\x48\x60\x00\x00\x00\x00\x00\x00\x00\x00\x88\x88"
+"\x00\x07\x00\x03foo"
+
 # ESNI draft 4 (see above) answer suffix, first truncated
 # (These are construted from dns_test_util's kWellFormedEsniKeys.)
 "\xff\x9f\x00\x01\x00\x00\x00\xFF\xff\x03\x00\x01\x00\x33\xff\x00\x24\x00\x1d\x00\x20\xed\xed\xc8\x68\xc1\x71\xd6\x9e\xa9\xf0\xa2\xc9\xf5\xa9\xdc\xcf\xf9\xb8\xed\x15\x5c\xc4\x5a\xec\x6f\xb2\x86\x14\xb7\x71\x1b\x7c\x00\x02"
diff --git a/net/dns/BUILD.gn b/net/dns/BUILD.gn
index 441b68e..bc54c81 100644
--- a/net/dns/BUILD.gn
+++ b/net/dns/BUILD.gn
@@ -65,6 +65,7 @@
       "host_resolver_mdns_task.h",
       "host_resolver_proc.cc",
       "host_resolver_proc.h",
+      "https_record_rdata.cc",
       "httpssvc_metrics.cc",
       "httpssvc_metrics.h",
       "mapped_host_resolver.cc",
@@ -313,6 +314,7 @@
       "dns_client.h",
       "dns_response.h",
       "dns_transaction.h",
+      "https_record_rdata.h",
       "record_parsed.h",
       "record_rdata.h",
     ]
@@ -396,6 +398,7 @@
     "dns_util_unittest.cc",
     "host_cache_unittest.cc",
     "host_resolver_manager_unittest.cc",
+    "https_record_rdata_unittest.cc",
     "httpssvc_metrics_unittest.cc",
     "mapped_host_resolver_unittest.cc",
     "record_parsed_unittest.cc",
@@ -511,6 +514,16 @@
   dict = "//net/data/fuzzer_dictionaries/net_dns_hosts_parse_fuzzer.dict"
 }
 
+fuzzer_test("net_dns_https_record_rdata_fuzzer") {
+  sources = [ "https_record_rdata_fuzzer.cc" ]
+  deps = [
+    "//base",
+    "//net",
+    "//net:net_fuzzer_test_support",
+  ]
+  dict = "//net/data/fuzzer_dictionaries/net_dns_record_fuzzer.dict"
+}
+
 fuzzer_test("net_dns_integrity_record_fuzzer") {
   sources = [ "integrity_record_fuzzer.cc" ]
   deps = [
diff --git a/net/dns/host_resolver_manager_unittest.cc b/net/dns/host_resolver_manager_unittest.cc
index 02e01f3..75968d4a 100644
--- a/net/dns/host_resolver_manager_unittest.cc
+++ b/net/dns/host_resolver_manager_unittest.cc
@@ -8838,8 +8838,8 @@
   const std::string kName = "https.test";
 
   MockDnsClientRuleList rules;
-  std::vector<DnsResourceRecord> records = {
-      BuildTestDnsRecord(kName, dns_protocol::kTypeHttps, "" /* rdata */)};
+  std::vector<DnsResourceRecord> records = {BuildTestDnsRecord(
+      kName, dns_protocol::kTypeHttps, "fake rdata" /* rdata */)};
   rules.emplace_back(kName, dns_protocol::kTypeHttps, false /* secure */,
                      MockDnsClientRule::Result(BuildTestDnsResponse(
                          kName, dns_protocol::kTypeHttps, records)),
@@ -9037,7 +9037,7 @@
 
   MockDnsClientRuleList rules;
   std::vector<DnsResourceRecord> records = {BuildTestDnsRecord(
-      "different.test", dns_protocol::kTypeHttps, "" /* rdata */)};
+      "different.test", dns_protocol::kTypeHttps, "fake rdata" /* rdata */)};
   rules.emplace_back(kName, dns_protocol::kTypeHttps, false /* secure */,
                      MockDnsClientRule::Result(BuildTestDnsResponse(
                          kName, dns_protocol::kTypeHttps, records)),
@@ -9101,8 +9101,8 @@
   const std::string kName = "https.test";
 
   MockDnsClientRuleList rules;
-  std::vector<DnsResourceRecord> records = {
-      BuildTestDnsRecord(kName, dns_protocol::kTypeHttps, "" /* rdata */)};
+  std::vector<DnsResourceRecord> records = {BuildTestDnsRecord(
+      kName, dns_protocol::kTypeHttps, "fake rdata" /* rdata */)};
   rules.emplace_back(kName, dns_protocol::kTypeHttps, false /* secure */,
                      MockDnsClientRule::Result(BuildTestDnsResponse(
                          kName, dns_protocol::kTypeHttps, records)),
@@ -9134,8 +9134,8 @@
                                {"DnsHttpssvcExperimentDomains", kName}});
 
   MockDnsClientRuleList rules;
-  std::vector<DnsResourceRecord> records = {
-      BuildTestDnsRecord(kName, dns_protocol::kTypeHttps, "" /* rdata */)};
+  std::vector<DnsResourceRecord> records = {BuildTestDnsRecord(
+      kName, dns_protocol::kTypeHttps, "fake rdata" /* rdata */)};
   rules.emplace_back(kName, dns_protocol::kTypeHttps, true /* secure */,
                      MockDnsClientRule::Result(BuildTestDnsResponse(
                          kName, dns_protocol::kTypeHttps, records)),
@@ -9207,8 +9207,8 @@
                                {"DnsHttpssvcExperimentDomains", kName}});
 
   MockDnsClientRuleList rules;
-  std::vector<DnsResourceRecord> records = {
-      BuildTestDnsRecord(kName, dns_protocol::kTypeHttps, "" /* rdata */)};
+  std::vector<DnsResourceRecord> records = {BuildTestDnsRecord(
+      kName, dns_protocol::kTypeHttps, "fake rdata" /* rdata */)};
   rules.emplace_back(kName, dns_protocol::kTypeHttps, true /* secure */,
                      MockDnsClientRule::Result(BuildTestDnsResponse(
                          kName, dns_protocol::kTypeHttps, records)),
@@ -9245,8 +9245,8 @@
                                {"DnsHttpssvcExperimentDomains", kName}});
 
   MockDnsClientRuleList rules;
-  std::vector<DnsResourceRecord> records = {
-      BuildTestDnsRecord(kName, dns_protocol::kTypeHttps, "" /* rdata */)};
+  std::vector<DnsResourceRecord> records = {BuildTestDnsRecord(
+      kName, dns_protocol::kTypeHttps, "fake rdata" /* rdata */)};
   rules.emplace_back(kName, dns_protocol::kTypeHttps, true /* secure */,
                      MockDnsClientRule::Result(BuildTestDnsResponse(
                          kName, dns_protocol::kTypeHttps, records)),
@@ -9353,8 +9353,8 @@
                                {"DnsHttpssvcExperimentDomains", kName}});
 
   MockDnsClientRuleList rules;
-  std::vector<DnsResourceRecord> records = {
-      BuildTestDnsRecord(kName, dns_protocol::kTypeHttps, "" /* rdata */)};
+  std::vector<DnsResourceRecord> records = {BuildTestDnsRecord(
+      kName, dns_protocol::kTypeHttps, "fake rdata" /* rdata */)};
   rules.emplace_back(kName, dns_protocol::kTypeHttps, true /* secure */,
                      MockDnsClientRule::Result(BuildTestDnsResponse(
                          kName, dns_protocol::kTypeHttps, records)),
@@ -9398,8 +9398,8 @@
                                {"DnsHttpssvcExperimentDomains", kName}});
 
   MockDnsClientRuleList rules;
-  std::vector<DnsResourceRecord> records = {
-      BuildTestDnsRecord(kName, dns_protocol::kTypeHttps, "" /* rdata */)};
+  std::vector<DnsResourceRecord> records = {BuildTestDnsRecord(
+      kName, dns_protocol::kTypeHttps, "fake rdata" /* rdata */)};
   rules.emplace_back(kName, dns_protocol::kTypeHttps, true /* secure */,
                      MockDnsClientRule::Result(BuildTestDnsResponse(
                          kName, dns_protocol::kTypeHttps, records)),
diff --git a/net/dns/https_record_rdata.cc b/net/dns/https_record_rdata.cc
new file mode 100644
index 0000000..95f617e
--- /dev/null
+++ b/net/dns/https_record_rdata.cc
@@ -0,0 +1,369 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/dns/https_record_rdata.h"
+
+#include <stdint.h>
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/big_endian.h"
+#include "base/check.h"
+#include "base/dcheck_is_on.h"
+#include "base/memory/ptr_util.h"
+#include "base/optional.h"
+#include "base/strings/string_piece.h"
+#include "net/base/ip_address.h"
+#include "net/dns/dns_util.h"
+#include "net/dns/public/dns_protocol.h"
+
+namespace net {
+
+namespace {
+
+bool ReadNextServiceParam(base::Optional<uint16_t> last_key,
+                          base::BigEndianReader& reader,
+                          uint16_t* out_param_key,
+                          base::StringPiece* out_param_value) {
+  DCHECK(out_param_key);
+  DCHECK(out_param_value);
+
+  uint16_t key;
+  if (!reader.ReadU16(&key))
+    return false;
+  if (last_key.has_value() && last_key.value() >= key)
+    return false;
+
+  base::StringPiece value;
+  if (!reader.ReadU16LengthPrefixed(&value))
+    return false;
+
+  *out_param_key = key;
+  *out_param_value = value;
+  return true;
+}
+
+bool ParseAlpnIds(base::StringPiece param_value,
+                  std::vector<std::string>* out_parsed) {
+  DCHECK(out_parsed);
+
+  base::BigEndianReader reader(param_value.data(), param_value.size());
+
+  std::vector<std::string> alpn_ids;
+  // Do/while to require at least one ID.
+  do {
+    base::StringPiece alpn_id;
+    if (!reader.ReadU8LengthPrefixed(&alpn_id))
+      return false;
+    if (alpn_id.size() < 1)
+      return false;
+    DCHECK_LE(alpn_id.size(), 255u);
+
+    alpn_ids.emplace_back(alpn_id.data(), alpn_id.size());
+  } while (reader.remaining() > 0);
+
+  *out_parsed = std::move(alpn_ids);
+  return true;
+}
+
+template <size_t ADDRESS_SIZE>
+bool ParseIpAddresses(base::StringPiece param_value,
+                      std::vector<IPAddress>* out_addresses) {
+  DCHECK(out_addresses);
+
+  base::BigEndianReader reader(param_value.data(), param_value.size());
+
+  std::vector<IPAddress> addresses;
+  uint8_t addr_bytes[ADDRESS_SIZE];
+  do {
+    if (!reader.ReadBytes(addr_bytes, ADDRESS_SIZE))
+      return false;
+    addresses.emplace_back(addr_bytes);
+    DCHECK(addresses.back().IsValid());
+  } while (reader.remaining() > 0);
+
+  *out_addresses = std::move(addresses);
+  return true;
+}
+
+}  // namespace
+
+// static
+std::unique_ptr<HttpsRecordRdata> HttpsRecordRdata::Parse(
+    base::StringPiece data) {
+  if (!HasValidSize(data, kType))
+    return nullptr;
+
+  base::BigEndianReader reader(data.data(), data.size());
+  uint16_t priority;
+  CHECK(reader.ReadU16(&priority));
+
+  if (priority == 0) {
+    return AliasFormHttpsRecordRdata::Parse(data);
+  } else {
+    return ServiceFormHttpsRecordRdata::Parse(data);
+  }
+}
+
+HttpsRecordRdata::~HttpsRecordRdata() = default;
+
+bool HttpsRecordRdata::IsEqual(const RecordRdata* other) const {
+  DCHECK(other);
+
+  if (other->Type() != kType)
+    return false;
+
+  const HttpsRecordRdata* https = static_cast<const HttpsRecordRdata*>(other);
+  return IsEqual(https);
+}
+
+uint16_t HttpsRecordRdata::Type() const {
+  return kType;
+}
+
+AliasFormHttpsRecordRdata* HttpsRecordRdata::AsAliasForm() {
+  CHECK(IsAlias());
+  return static_cast<AliasFormHttpsRecordRdata*>(this);
+}
+
+const AliasFormHttpsRecordRdata* HttpsRecordRdata::AsAliasForm() const {
+  return const_cast<HttpsRecordRdata*>(this)->AsAliasForm();
+}
+
+ServiceFormHttpsRecordRdata* HttpsRecordRdata::AsServiceForm() {
+  CHECK(!IsAlias());
+  return static_cast<ServiceFormHttpsRecordRdata*>(this);
+}
+
+const ServiceFormHttpsRecordRdata* HttpsRecordRdata::AsServiceForm() const {
+  return const_cast<HttpsRecordRdata*>(this)->AsServiceForm();
+}
+
+AliasFormHttpsRecordRdata::AliasFormHttpsRecordRdata(std::string alias_name)
+    : alias_name_(std::move(alias_name)) {
+  DCHECK(!alias_name_.empty());
+}
+
+// static
+std::unique_ptr<AliasFormHttpsRecordRdata> AliasFormHttpsRecordRdata::Parse(
+    base::StringPiece data) {
+  base::BigEndianReader reader(data.data(), data.size());
+
+  uint16_t priority;
+  if (!reader.ReadU16(&priority))
+    return nullptr;
+  if (priority != 0)
+    return nullptr;
+
+  base::Optional<std::string> alias_name =
+      DnsDomainToString(reader, true /* require_complete */);
+  if (!alias_name.has_value() || alias_name.value().empty())
+    return nullptr;
+
+  if (reader.remaining() != 0)
+    return nullptr;
+
+  return std::make_unique<AliasFormHttpsRecordRdata>(
+      std::move(alias_name).value());
+}
+
+bool AliasFormHttpsRecordRdata::IsEqual(const HttpsRecordRdata* other) const {
+  DCHECK(other);
+
+  if (!other->IsAlias())
+    return false;
+
+  const AliasFormHttpsRecordRdata* alias =
+      static_cast<const AliasFormHttpsRecordRdata*>(other);
+  return alias_name_ == alias->alias_name_;
+}
+
+bool AliasFormHttpsRecordRdata::IsAlias() const {
+  return true;
+}
+
+ServiceFormHttpsRecordRdata::ServiceFormHttpsRecordRdata(
+    uint16_t priority,
+    std::string service_name,
+    std::vector<std::string> alpn_ids,
+    bool default_alpn,
+    base::Optional<uint16_t> port,
+    std::vector<IPAddress> ipv4_hint,
+    std::string ech_config,
+    std::vector<IPAddress> ipv6_hint,
+    std::map<uint16_t, std::string> unparsed_params)
+    : priority_(priority),
+      service_name_(std::move(service_name)),
+      alpn_ids_(std::move(alpn_ids)),
+      default_alpn_(default_alpn),
+      port_(port),
+      ipv4_hint_(std::move(ipv4_hint)),
+      ech_config_(std::move(ech_config)),
+      ipv6_hint_(std::move(ipv6_hint)),
+      unparsed_params_(std::move(unparsed_params)) {
+  DCHECK_NE(priority_, 0);
+
+#if DCHECK_IS_ON()
+  for (const IPAddress& address : ipv4_hint) {
+    DCHECK(address.IsIPv4());
+  }
+  for (const IPAddress& address : ipv6_hint) {
+    DCHECK(address.IsIPv6());
+  }
+#endif  // DCHECK_IS_ON()
+}
+
+ServiceFormHttpsRecordRdata::~ServiceFormHttpsRecordRdata() = default;
+
+bool ServiceFormHttpsRecordRdata::IsEqual(const HttpsRecordRdata* other) const {
+  DCHECK(other);
+
+  if (other->IsAlias())
+    return false;
+
+  const ServiceFormHttpsRecordRdata* service =
+      static_cast<const ServiceFormHttpsRecordRdata*>(other);
+  return priority_ == service->priority_ &&
+         service_name_ == service->service_name_ &&
+         alpn_ids_ == service->alpn_ids_ &&
+         default_alpn_ == service->default_alpn_ && port_ == service->port_ &&
+         ipv4_hint_ == service->ipv4_hint_ &&
+         ech_config_ == service->ech_config_ &&
+         ipv6_hint_ == service->ipv6_hint_;
+}
+
+bool ServiceFormHttpsRecordRdata::IsAlias() const {
+  return false;
+}
+
+// static
+std::unique_ptr<ServiceFormHttpsRecordRdata> ServiceFormHttpsRecordRdata::Parse(
+    base::StringPiece data) {
+  base::BigEndianReader reader(data.data(), data.size());
+
+  uint16_t priority;
+  if (!reader.ReadU16(&priority))
+    return nullptr;
+  if (priority == 0)
+    return nullptr;
+
+  base::Optional<std::string> service_name =
+      DnsDomainToString(reader, true /* require_complete */);
+  if (!service_name.has_value())
+    return nullptr;
+
+  if (reader.remaining() == 0) {
+    return std::make_unique<ServiceFormHttpsRecordRdata>(
+        priority, std::move(service_name).value(),
+        std::vector<std::string>() /* alpn_ids */, true /* default_alpn */,
+        base::nullopt /* port */, std::vector<IPAddress>() /* ipv4_hint */,
+        std::string() /* ech_config */,
+        std::vector<IPAddress>() /* ipv6_hint */,
+        std::map<uint16_t, std::string>() /* unparsed_params */);
+  }
+
+  uint16_t param_key = 0;
+  base::StringPiece param_value;
+  if (!ReadNextServiceParam(base::nullopt /* last_key */, reader, &param_key,
+                            &param_value))
+    return nullptr;
+
+  std::map<uint16_t, std::string> unparsed_params;
+  while (param_key < dns_protocol::kHttpsServiceParamKeyAlpn) {
+    CHECK(unparsed_params
+              .emplace(param_key, static_cast<std::string>(param_value))
+              .second);
+    if (reader.remaining() == 0)
+      break;
+    if (!ReadNextServiceParam(param_key, reader, &param_key, &param_value))
+      return nullptr;
+  }
+
+  std::vector<std::string> alpn_ids;
+  if (param_key == dns_protocol::kHttpsServiceParamKeyAlpn) {
+    if (!ParseAlpnIds(param_value, &alpn_ids))
+      return nullptr;
+    if (reader.remaining() > 0 &&
+        !ReadNextServiceParam(param_key, reader, &param_key, &param_value)) {
+      return nullptr;
+    }
+  }
+
+  bool default_alpn = true;
+  if (param_key == dns_protocol::kHttpsServiceParamKeyNoDefaultAlpn) {
+    if (!param_value.empty())
+      return nullptr;
+    default_alpn = false;
+    if (reader.remaining() > 0 &&
+        !ReadNextServiceParam(param_key, reader, &param_key, &param_value)) {
+      return nullptr;
+    }
+  }
+
+  base::Optional<uint16_t> port;
+  if (param_key == dns_protocol::kHttpsServiceParamKeyPort) {
+    if (param_value.size() != 2)
+      return nullptr;
+    uint16_t port_val;
+    base::ReadBigEndian(param_value.data(), &port_val);
+    port = port_val;
+    if (reader.remaining() > 0 &&
+        !ReadNextServiceParam(param_key, reader, &param_key, &param_value)) {
+      return nullptr;
+    }
+  }
+
+  std::vector<IPAddress> ipv4_hint;
+  if (param_key == dns_protocol::kHttpsServiceParamKeyIpv4Hint) {
+    if (!ParseIpAddresses<IPAddress::kIPv4AddressSize>(param_value, &ipv4_hint))
+      return nullptr;
+    if (reader.remaining() > 0 &&
+        !ReadNextServiceParam(param_key, reader, &param_key, &param_value)) {
+      return nullptr;
+    }
+  }
+
+  std::string ech_config;
+  if (param_key == dns_protocol::kHttpsServiceParamKeyEchConfig) {
+    ech_config = std::string(param_value.data(), param_value.size());
+    if (reader.remaining() > 0 &&
+        !ReadNextServiceParam(param_key, reader, &param_key, &param_value)) {
+      return nullptr;
+    }
+  }
+
+  std::vector<IPAddress> ipv6_hint;
+  if (param_key == dns_protocol::kHttpsServiceParamKeyIpv6Hint) {
+    if (!ParseIpAddresses<IPAddress::kIPv6AddressSize>(param_value, &ipv6_hint))
+      return nullptr;
+    if (reader.remaining() > 0 &&
+        !ReadNextServiceParam(param_key, reader, &param_key, &param_value)) {
+      return nullptr;
+    }
+  }
+
+  // Note that if parsing has already reached the end of the rdata, `param_key`
+  // is still set for whatever param was read last.
+  if (param_key > dns_protocol::kHttpsServiceParamKeyIpv6Hint) {
+    for (;;) {
+      CHECK(unparsed_params
+                .emplace(param_key, static_cast<std::string>(param_value))
+                .second);
+      if (reader.remaining() == 0)
+        break;
+      if (!ReadNextServiceParam(param_key, reader, &param_key, &param_value))
+        return nullptr;
+    }
+  }
+
+  return std::make_unique<ServiceFormHttpsRecordRdata>(
+      priority, std::move(service_name).value(), std::move(alpn_ids),
+      default_alpn, port, std::move(ipv4_hint), std::move(ech_config),
+      std::move(ipv6_hint), std::move(unparsed_params));
+}
+
+}  // namespace net
diff --git a/net/dns/https_record_rdata.h b/net/dns/https_record_rdata.h
new file mode 100644
index 0000000..86790b1
--- /dev/null
+++ b/net/dns/https_record_rdata.h
@@ -0,0 +1,116 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_DNS_HTTPS_RECORD_RDATA_H_
+#define NET_DNS_HTTPS_RECORD_RDATA_H_
+
+#include <stdint.h>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/optional.h"
+#include "base/strings/string_piece.h"
+#include "net/base/ip_address.h"
+#include "net/base/net_export.h"
+#include "net/dns/public/dns_protocol.h"
+#include "net/dns/record_rdata.h"
+
+namespace net {
+
+class AliasFormHttpsRecordRdata;
+class ServiceFormHttpsRecordRdata;
+
+class NET_EXPORT_PRIVATE HttpsRecordRdata : public RecordRdata {
+ public:
+  static const uint16_t kType = dns_protocol::kTypeHttps;
+
+  static std::unique_ptr<HttpsRecordRdata> Parse(base::StringPiece data);
+
+  HttpsRecordRdata(const HttpsRecordRdata& rdata) = delete;
+  HttpsRecordRdata& operator=(const HttpsRecordRdata& rdata) = delete;
+
+  ~HttpsRecordRdata() override;
+
+  bool IsEqual(const RecordRdata* other) const override;
+  virtual bool IsEqual(const HttpsRecordRdata* other) const = 0;
+  uint16_t Type() const override;
+
+  virtual bool IsAlias() const = 0;
+  AliasFormHttpsRecordRdata* AsAliasForm();
+  const AliasFormHttpsRecordRdata* AsAliasForm() const;
+  ServiceFormHttpsRecordRdata* AsServiceForm();
+  const ServiceFormHttpsRecordRdata* AsServiceForm() const;
+
+ protected:
+  HttpsRecordRdata() = default;
+};
+
+class NET_EXPORT_PRIVATE AliasFormHttpsRecordRdata : public HttpsRecordRdata {
+ public:
+  explicit AliasFormHttpsRecordRdata(std::string alias_name);
+  static std::unique_ptr<AliasFormHttpsRecordRdata> Parse(
+      base::StringPiece data);
+
+  bool IsEqual(const HttpsRecordRdata* other) const override;
+  bool IsAlias() const override;
+
+  base::StringPiece alias_name() { return alias_name_; }
+
+ private:
+  AliasFormHttpsRecordRdata() = default;
+
+  const std::string alias_name_;
+};
+
+class NET_EXPORT_PRIVATE ServiceFormHttpsRecordRdata : public HttpsRecordRdata {
+ public:
+  ServiceFormHttpsRecordRdata(uint16_t priority,
+                              std::string service_name,
+                              std::vector<std::string> alpn_ids,
+                              bool default_alpn,
+                              base::Optional<uint16_t> port,
+                              std::vector<IPAddress> ipv4_hint,
+                              std::string ech_config,
+                              std::vector<IPAddress> ipv6_hint,
+                              std::map<uint16_t, std::string> unparsed_params);
+  static std::unique_ptr<ServiceFormHttpsRecordRdata> Parse(
+      base::StringPiece data);
+
+  ~ServiceFormHttpsRecordRdata() override;
+
+  bool IsEqual(const HttpsRecordRdata* other) const override;
+  bool IsAlias() const override;
+
+  uint16_t priority() { return priority_; }
+  base::StringPiece service_name() { return service_name_; }
+  const std::vector<std::string>& alpn_ids() { return alpn_ids_; }
+  bool default_alpn() { return default_alpn_; }
+  base::Optional<uint16_t> port() { return port_; }
+  const std::vector<IPAddress>& ipv4_hint() { return ipv4_hint_; }
+  base::StringPiece ech_config() { return ech_config_; }
+  const std::vector<IPAddress>& ipv6_hint() { return ipv6_hint_; }
+  const std::map<uint16_t, std::string>& unparsed_params() {
+    return unparsed_params_;
+  }
+
+ private:
+  const uint16_t priority_;
+  const std::string service_name_;
+
+  // Supported service parameters.
+  const std::vector<std::string> alpn_ids_;
+  const bool default_alpn_;
+  const base::Optional<uint16_t> port_;
+  const std::vector<IPAddress> ipv4_hint_;
+  const std::string ech_config_;
+  const std::vector<IPAddress> ipv6_hint_;
+
+  const std::map<uint16_t, std::string> unparsed_params_;
+};
+
+}  // namespace net
+
+#endif  // NET_DNS_HTTPS_RECORD_RDATA_H_
diff --git a/net/dns/https_record_rdata_fuzzer.cc b/net/dns/https_record_rdata_fuzzer.cc
new file mode 100644
index 0000000..61cf595
--- /dev/null
+++ b/net/dns/https_record_rdata_fuzzer.cc
@@ -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.
+
+#include "net/dns/https_record_rdata.h"
+
+#include <stdint.h>
+
+#include <memory>
+
+#include "base/check.h"
+#include "base/strings/string_piece.h"
+#include "net/dns/public/dns_protocol.h"
+
+namespace net {
+namespace {
+
+void ParseAndExercise(base::StringPiece data) {
+  std::unique_ptr<HttpsRecordRdata> parsed = HttpsRecordRdata::Parse(data);
+  std::unique_ptr<HttpsRecordRdata> parsed2 = HttpsRecordRdata::Parse(data);
+
+  CHECK_EQ(!!parsed, !!parsed2);
+
+  if (!parsed)
+    return;
+
+  CHECK(parsed->IsEqual(parsed.get()));
+  CHECK(parsed->IsEqual(parsed2.get()));
+
+  CHECK_EQ(parsed->Type(), dns_protocol::kTypeHttps);
+  if (parsed->IsAlias()) {
+    AliasFormHttpsRecordRdata* alias = parsed->AsAliasForm();
+    CHECK(!alias->alias_name().empty());
+  } else {
+    ServiceFormHttpsRecordRdata* service = parsed->AsServiceForm();
+    CHECK_GT(service->priority(), 0);
+    service->service_name();
+    service->alpn_ids();
+    service->default_alpn();
+    service->port();
+    service->ipv4_hint();
+    service->ech_config();
+    service->ipv6_hint();
+    service->unparsed_params();
+  }
+}
+
+}  // namespace
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  ParseAndExercise(
+      base::StringPiece(reinterpret_cast<const char*>(data), size));
+  return 0;
+}
+
+}  // namespace net
diff --git a/net/dns/https_record_rdata_unittest.cc b/net/dns/https_record_rdata_unittest.cc
new file mode 100644
index 0000000..852dc4e
--- /dev/null
+++ b/net/dns/https_record_rdata_unittest.cc
@@ -0,0 +1,109 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/dns/https_record_rdata.h"
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/strings/string_piece.h"
+#include "net/base/ip_address.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace {
+
+TEST(HttpsRecordRdataTest, ParsesAlias) {
+  const char kRdata[] =
+      // Priority: 0 for alias record
+      "\000\000"
+      // Alias name: chromium.org
+      "\010chromium\003org\000";
+
+  std::unique_ptr<HttpsRecordRdata> rdata =
+      HttpsRecordRdata::Parse(base::StringPiece(kRdata, sizeof(kRdata) - 1));
+  ASSERT_TRUE(rdata);
+
+  AliasFormHttpsRecordRdata expected("chromium.org");
+  EXPECT_TRUE(rdata->IsEqual(&expected));
+
+  EXPECT_TRUE(rdata->IsAlias());
+  AliasFormHttpsRecordRdata* alias_rdata = rdata->AsAliasForm();
+  ASSERT_TRUE(alias_rdata);
+  EXPECT_EQ(alias_rdata->alias_name(), "chromium.org");
+}
+
+TEST(HttpsRecordRdataTest, ParsesService) {
+  const char kRdata[] =
+      // Priority: 1
+      "\000\001"
+      // Service name: chromium.org
+      "\010chromium\003org\000"
+      // alpn=foo,bar
+      "\000\001\000\010\003foo\003bar"
+      // no-default-alpn
+      "\000\002\000\000"
+      // port=46
+      "\000\003\000\002\000\056"
+      // ipv4hint=8.8.8.8
+      "\000\004\000\004\010\010\010\010"
+      // echconfig=hello
+      "\000\005\000\005hello"
+      // ipv6hint=2001:4860:4860::8888
+      "\000\006\000\020\x20\x01\x48\x60\x48\x60\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x88\x88"
+      // Unknown key7=foo
+      "\000\007\000\003foo";
+
+  std::unique_ptr<HttpsRecordRdata> rdata =
+      HttpsRecordRdata::Parse(base::StringPiece(kRdata, sizeof(kRdata) - 1));
+  ASSERT_TRUE(rdata);
+
+  IPAddress expected_ipv6;
+  ASSERT_TRUE(expected_ipv6.AssignFromIPLiteral("2001:4860:4860::8888"));
+  ServiceFormHttpsRecordRdata expected(
+      1 /* priority */, "chromium.org",
+      std::vector<std::string>({"foo", "bar"}) /* alpn_ids */,
+      false /* default_alpn */, base::Optional<uint16_t>(46) /* port */,
+      std::vector<IPAddress>({IPAddress(8, 8, 8, 8)}) /* ipv4_hint */,
+      "hello" /* ech_config */,
+      std::vector<IPAddress>({expected_ipv6}) /* ipv6_hint */,
+      std::map<uint16_t, std::string>({{7, "foo"}}) /* unparsed_params */);
+  EXPECT_TRUE(rdata->IsEqual(&expected));
+
+  EXPECT_FALSE(rdata->IsAlias());
+  ServiceFormHttpsRecordRdata* service_rdata = rdata->AsServiceForm();
+  ASSERT_TRUE(service_rdata);
+  EXPECT_EQ(service_rdata->priority(), 1);
+  EXPECT_EQ(service_rdata->service_name(), "chromium.org");
+  EXPECT_THAT(service_rdata->alpn_ids(), testing::ElementsAre("foo", "bar"));
+  EXPECT_FALSE(service_rdata->default_alpn());
+  EXPECT_THAT(service_rdata->port(), testing::Optional(46));
+  EXPECT_THAT(service_rdata->ipv4_hint(),
+              testing::ElementsAre(IPAddress(8, 8, 8, 8)));
+  EXPECT_EQ(service_rdata->ech_config(), "hello");
+  EXPECT_THAT(service_rdata->ipv6_hint(), testing::ElementsAre(expected_ipv6));
+  EXPECT_THAT(service_rdata->unparsed_params(),
+              testing::ElementsAre(testing::Pair(7, "foo")));
+}
+
+TEST(HttpsRecordRdataTest, RejectCorruptRdata) {
+  const char kRdata[] =
+      // Priority: 5
+      "\000\005"
+      // Service name: chromium.org
+      "\010chromium\003org\000"
+      // Malformed alpn
+      "\000\001\000\005hi";
+
+  std::unique_ptr<HttpsRecordRdata> rdata =
+      HttpsRecordRdata::Parse(base::StringPiece(kRdata, sizeof(kRdata) - 1));
+  EXPECT_FALSE(rdata);
+}
+
+}  // namespace
+}  // namespace net
diff --git a/net/dns/public/dns_protocol.h b/net/dns/public/dns_protocol.h
index 608b7ec..3cf796b 100644
--- a/net/dns/public/dns_protocol.h
+++ b/net/dns/public/dns_protocol.h
@@ -187,6 +187,16 @@
 static const uint16_t kFlagRD = 0x100;  // Recursion Desired - query flag.
 static const uint16_t kFlagTC = 0x200;  // Truncated - server flag.
 
+// SVCB/HTTPS ServiceParamKey
+//
+// IANA registration pending. Values from draft-ietf-dnsop-svcb-httpssvc-03.
+static constexpr uint16_t kHttpsServiceParamKeyAlpn = 1;
+static constexpr uint16_t kHttpsServiceParamKeyNoDefaultAlpn = 2;
+static constexpr uint16_t kHttpsServiceParamKeyPort = 3;
+static constexpr uint16_t kHttpsServiceParamKeyIpv4Hint = 4;
+static constexpr uint16_t kHttpsServiceParamKeyEchConfig = 5;
+static constexpr uint16_t kHttpsServiceParamKeyIpv6Hint = 6;
+
 }  // namespace dns_protocol
 
 }  // namespace net
diff --git a/net/dns/record_rdata.cc b/net/dns/record_rdata.cc
index c25a253..1f2795d7 100644
--- a/net/dns/record_rdata.cc
+++ b/net/dns/record_rdata.cc
@@ -25,6 +25,9 @@
 static constexpr size_t kIntegrityMinimumSize =
     sizeof(uint16_t) + IntegrityRecordRdata::kDigestLen;
 
+// Minimal HTTPS rdata is 2 octets priority + 1 octet empty name.
+static constexpr size_t kHttpsRdataMinimumSize = 3;
+
 bool RecordRdata::HasValidSize(const base::StringPiece& data, uint16_t type) {
   switch (type) {
     case dns_protocol::kTypeSRV:
@@ -36,8 +39,7 @@
     case dns_protocol::kExperimentalTypeIntegrity:
       return data.size() >= kIntegrityMinimumSize;
     case dns_protocol::kTypeHttps:
-      // TODO(crbug.com/1138620): Implement actual size minimum.
-      return data.size() == 0;
+      return data.size() >= kHttpsRdataMinimumSize;
     case dns_protocol::kTypeCNAME:
     case dns_protocol::kTypePTR:
     case dns_protocol::kTypeTXT:
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index 07e461a..ecca1c2 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -192,9 +192,7 @@
     proxy_ssl_config_.disable_cert_verification_network_fetches = true;
   }
 
-  if (request_->idempotency == IDEMPOTENT ||
-      (request_->idempotency == DEFAULT_IDEMPOTENCY &&
-       HttpUtil::IsMethodSafe(request_info->method))) {
+  if (HttpUtil::IsMethodSafe(request_info->method)) {
     can_send_early_data_ = true;
   }
 
diff --git a/net/http/http_request_info.cc b/net/http/http_request_info.cc
index 9e12e79..1410e3b1a 100644
--- a/net/http/http_request_info.cc
+++ b/net/http/http_request_info.cc
@@ -11,8 +11,7 @@
       load_flags(0),
       privacy_mode(PRIVACY_MODE_DISABLED),
       disable_secure_dns(false),
-      reporting_upload_depth(0),
-      idempotency(net::DEFAULT_IDEMPOTENCY) {}
+      reporting_upload_depth(0) {}
 
 HttpRequestInfo::HttpRequestInfo(const HttpRequestInfo& other) = default;
 
diff --git a/net/http/http_request_info.h b/net/http/http_request_info.h
index c75fc1fe..8771765 100644
--- a/net/http/http_request_info.h
+++ b/net/http/http_request_info.h
@@ -8,7 +8,6 @@
 #include <string>
 
 #include "base/optional.h"
-#include "net/base/idempotency.h"
 #include "net/base/net_export.h"
 #include "net/base/network_isolation_key.h"
 #include "net/base/privacy_mode.h"
@@ -74,15 +73,6 @@
   // this to NetworkIsolationKey::TopFrameSite().  That gives more consistent
   /// behavior, and may still provide useful metrics.
   base::Optional<url::Origin> possibly_top_frame_origin;
-
-  // Idempotency of the request, which determines that if it is safe to enable
-  // 0-RTT for the request. By default, 0-RTT is only enabled for safe
-  // HTTP methods, i.e., GET, HEAD, OPTIONS, and TRACE. For other methods,
-  // enabling 0-RTT may cause security issues since a network observer can
-  // replay the request. If the request has any side effects, those effects can
-  // happen multiple times. It is only safe to enable the 0-RTT if it is known
-  // that the request is idempotent.
-  net::Idempotency idempotency;
 };
 
 }  // namespace net
diff --git a/net/test/embedded_test_server/http_request.cc b/net/test/embedded_test_server/http_request.cc
index 80c0e8b..4ad8d56 100644
--- a/net/test/embedded_test_server/http_request.cc
+++ b/net/test/embedded_test_server/http_request.cc
@@ -19,6 +19,8 @@
 
 namespace {
 
+size_t kRequestSizeLimit = 64 * 1024 * 1024;  // 64 mb.
+
 // Helper function used to trim tokens in http request headers.
 std::string Trim(const std::string& value) {
   std::string result;
@@ -28,7 +30,9 @@
 
 }  // namespace
 
-HttpRequest::HttpRequest() : method(METHOD_UNKNOWN), has_content(false) {}
+HttpRequest::HttpRequest() : method(METHOD_UNKNOWN),
+                             has_content(false) {
+}
 
 HttpRequest::HttpRequest(const HttpRequest& other) = default;
 
@@ -50,6 +54,8 @@
 
 void HttpRequestParser::ProcessChunk(const base::StringPiece& data) {
   buffer_.append(data.data(), data.size());
+  DCHECK_LE(buffer_.size() + data.size(), kRequestSizeLimit) <<
+      "The HTTP request is too large.";
 }
 
 std::string HttpRequestParser::ShiftLine() {
@@ -110,8 +116,8 @@
 
     // Protocol.
     const std::string protocol = base::ToLowerASCII(header_line_tokens[2]);
-    CHECK(protocol == "http/1.0" || protocol == "http/1.1")
-        << "Protocol not supported: " << protocol;
+    CHECK(protocol == "http/1.0" || protocol == "http/1.1") <<
+        "Protocol not supported: " << protocol;
   }
 
   // Parse further headers.
@@ -134,7 +140,8 @@
         DCHECK_NE(std::string::npos, delimiter_pos) << "Syntax error.";
         header_name = Trim(header_line.substr(0, delimiter_pos));
         std::string header_value = Trim(header_line.substr(
-            delimiter_pos + 1, header_line.size() - delimiter_pos - 1));
+            delimiter_pos + 1,
+            header_line.size() - delimiter_pos - 1));
         http_request_->headers[header_name] = header_value;
       }
     }
@@ -145,7 +152,8 @@
   if (http_request_->headers.count("Content-Length") > 0) {
     http_request_->has_content = true;
     const bool success = base::StringToSizeT(
-        http_request_->headers["Content-Length"], &declared_content_length_);
+        http_request_->headers["Content-Length"],
+        &declared_content_length_);
     if (!success) {
       declared_content_length_ = 0;
       LOG(WARNING) << "Malformed Content-Length header's value.";
@@ -191,10 +199,11 @@
     return WAITING;
   }
 
-  const size_t fetch_bytes =
-      std::min(available_bytes,
-               declared_content_length_ - http_request_->content.size());
-  http_request_->content.append(buffer_.data() + buffer_position_, fetch_bytes);
+  const size_t fetch_bytes = std::min(
+      available_bytes,
+      declared_content_length_ - http_request_->content.size());
+  http_request_->content.append(buffer_.data() + buffer_position_,
+                                fetch_bytes);
   buffer_position_ += fetch_bytes;
 
   if (declared_content_length_ == http_request_->content.size()) {
diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h
index eed0ae9..adeb342 100644
--- a/net/url_request/url_request.h
+++ b/net/url_request/url_request.h
@@ -19,7 +19,6 @@
 #include "base/threading/thread_checker.h"
 #include "base/time/time.h"
 #include "net/base/auth.h"
-#include "net/base/idempotency.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/isolation_info.h"
 #include "net/base/load_states.h"
@@ -712,9 +711,6 @@
     send_client_certs_ = send_client_certs;
   }
 
-  void SetIdempotency(Idempotency idempotency) { idempotency_ = idempotency; }
-  Idempotency GetIdempotency() const { return idempotency_; }
-
   base::WeakPtr<URLRequest> GetWeakPtr();
 
  protected:
@@ -952,9 +948,6 @@
 
   bool send_client_certs_ = true;
 
-  // Idempotency of the request.
-  Idempotency idempotency_ = DEFAULT_IDEMPOTENCY;
-
   THREAD_CHECKER(thread_checker_);
 
   base::WeakPtrFactory<URLRequest> weak_factory_{this};
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index c9985fd..2112797e 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -299,7 +299,6 @@
   request_info_.traffic_annotation =
       net::MutableNetworkTrafficAnnotationTag(request_->traffic_annotation());
   request_info_.socket_tag = request_->socket_tag();
-  request_info_.idempotency = request_->GetIdempotency();
 #if BUILDFLAG(ENABLE_REPORTING)
   request_info_.reporting_upload_depth = request_->reporting_upload_depth();
 #endif
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 8464322..67e2b492 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -12207,120 +12207,6 @@
   }
 }
 
-// TLSEarlyDataTest tests that the 0-RTT is enabled for idempotent POST request.
-TEST_F(HTTPSEarlyDataTest, TLSEarlyDataIdempotentPOSTTest) {
-  ASSERT_TRUE(test_server_.Start());
-  context_.http_transaction_factory()->GetSession()->ClearSSLSessionCache();
-
-  {
-    TestDelegate d;
-    std::unique_ptr<URLRequest> r(context_.CreateRequest(
-        test_server_.GetURL("/zerortt"), DEFAULT_PRIORITY, &d,
-        TRAFFIC_ANNOTATION_FOR_TESTS));
-    r->Start();
-    EXPECT_TRUE(r->is_pending());
-
-    base::RunLoop().Run();
-
-    EXPECT_EQ(1, d.response_started_count());
-
-    EXPECT_EQ(SSL_CONNECTION_VERSION_TLS1_3,
-              SSLConnectionStatusToVersion(r->ssl_info().connection_status));
-    EXPECT_TRUE(r->ssl_info().unverified_cert.get());
-    EXPECT_TRUE(test_server_.GetCertificate()->EqualsIncludingChain(
-        r->ssl_info().cert.get()));
-
-    // The Early-Data header should be omitted in the initial request, and the
-    // handler should return "0".
-    EXPECT_EQ("0", d.data_received());
-  }
-
-  context_.http_transaction_factory()->GetSession()->CloseAllConnections(
-      ERR_FAILED, "Very good reason");
-
-  {
-    TestDelegate d;
-    std::unique_ptr<URLRequest> r(context_.CreateRequest(
-        test_server_.GetURL("/zerortt"), DEFAULT_PRIORITY, &d,
-        TRAFFIC_ANNOTATION_FOR_TESTS));
-    r->set_method("POST");
-    r->SetIdempotency(net::IDEMPOTENT);
-    r->Start();
-    EXPECT_TRUE(r->is_pending());
-
-    base::RunLoop().Run();
-
-    EXPECT_EQ(1, d.response_started_count());
-
-    EXPECT_EQ(SSL_CONNECTION_VERSION_TLS1_3,
-              SSLConnectionStatusToVersion(r->ssl_info().connection_status));
-    EXPECT_TRUE(r->ssl_info().unverified_cert.get());
-    EXPECT_TRUE(test_server_.GetCertificate()->EqualsIncludingChain(
-        r->ssl_info().cert.get()));
-
-    // The Early-Data header should be set since the request is set as an
-    // idempotent POST request.
-    EXPECT_EQ("1", d.data_received());
-  }
-}
-
-// TLSEarlyDataTest tests that the 0-RTT is disabled for non-idempotent request.
-TEST_F(HTTPSEarlyDataTest, TLSEarlyDataNonIdempotentRequestTest) {
-  ASSERT_TRUE(test_server_.Start());
-  context_.http_transaction_factory()->GetSession()->ClearSSLSessionCache();
-
-  {
-    TestDelegate d;
-    std::unique_ptr<URLRequest> r(context_.CreateRequest(
-        test_server_.GetURL("/zerortt"), DEFAULT_PRIORITY, &d,
-        TRAFFIC_ANNOTATION_FOR_TESTS));
-    r->Start();
-    EXPECT_TRUE(r->is_pending());
-
-    base::RunLoop().Run();
-
-    EXPECT_EQ(1, d.response_started_count());
-
-    EXPECT_EQ(SSL_CONNECTION_VERSION_TLS1_3,
-              SSLConnectionStatusToVersion(r->ssl_info().connection_status));
-    EXPECT_TRUE(r->ssl_info().unverified_cert.get());
-    EXPECT_TRUE(test_server_.GetCertificate()->EqualsIncludingChain(
-        r->ssl_info().cert.get()));
-
-    // The Early-Data header should be omitted in the initial request, and the
-    // handler should return "0".
-    EXPECT_EQ("0", d.data_received());
-  }
-
-  context_.http_transaction_factory()->GetSession()->CloseAllConnections(
-      ERR_FAILED, "Very good reason");
-
-  {
-    TestDelegate d;
-    std::unique_ptr<URLRequest> r(context_.CreateRequest(
-        test_server_.GetURL("/zerortt"), DEFAULT_PRIORITY, &d,
-        TRAFFIC_ANNOTATION_FOR_TESTS));
-    // Sets the GET request as not idempotent.
-    r->SetIdempotency(net::NOT_IDEMPOTENT);
-    r->Start();
-    EXPECT_TRUE(r->is_pending());
-
-    base::RunLoop().Run();
-
-    EXPECT_EQ(1, d.response_started_count());
-
-    EXPECT_EQ(SSL_CONNECTION_VERSION_TLS1_3,
-              SSLConnectionStatusToVersion(r->ssl_info().connection_status));
-    EXPECT_TRUE(r->ssl_info().unverified_cert.get());
-    EXPECT_TRUE(test_server_.GetCertificate()->EqualsIncludingChain(
-        r->ssl_info().cert.get()));
-
-    // The Early-Data header should be omitted in the initial request even
-    // though it is a GET request, since the request is set as not idempotent.
-    EXPECT_EQ("0", d.data_received());
-  }
-}
-
 std::unique_ptr<test_server::HttpResponse> HandleTooEarly(
     bool* sent_425,
     const test_server::HttpRequest& request) {
diff --git a/remoting/host/chromeos/clipboard_aura.cc b/remoting/host/chromeos/clipboard_aura.cc
index 3c67d61..e95356c 100644
--- a/remoting/host/chromeos/clipboard_aura.cc
+++ b/remoting/host/chromeos/clipboard_aura.cc
@@ -12,8 +12,8 @@
 #include "remoting/proto/event.pb.h"
 #include "remoting/protocol/clipboard_stub.h"
 #include "ui/base/clipboard/clipboard.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
 #include "ui/base/clipboard/scoped_clipboard_writer.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 
 namespace {
 
diff --git a/remoting/protocol/connection_unittest.cc b/remoting/protocol/connection_unittest.cc
index 9aaa1e1..0d1bec2 100644
--- a/remoting/protocol/connection_unittest.cc
+++ b/remoting/protocol/connection_unittest.cc
@@ -650,7 +650,9 @@
   client_audio_player_.Verify();
 }
 
-TEST_P(ConnectionTest, FirstCaptureFailed) {
+// Flaky on multiple platforms
+// https://crbug.com/1143671
+TEST_P(ConnectionTest, DISABLED_FirstCaptureFailed) {
   Connect();
 
   auto capturer = std::make_unique<TestScreenCapturer>();
@@ -660,7 +662,9 @@
   WaitNextVideoFrame();
 }
 
-TEST_P(ConnectionTest, SecondCaptureFailed) {
+// Flaky on multiple platforms
+// https://crbug.com/1143671
+TEST_P(ConnectionTest, DISABLED_SecondCaptureFailed) {
   Connect();
 
   auto capturer = std::make_unique<TestScreenCapturer>();
diff --git a/third_party/accessibility_test_framework/BUILD.gn b/third_party/accessibility_test_framework/BUILD.gn
index 3cddc14..b4bd2f3 100644
--- a/third_party/accessibility_test_framework/BUILD.gn
+++ b/third_party/accessibility_test_framework/BUILD.gn
@@ -10,6 +10,7 @@
   # Uses wrong version of proto (not protolite).
   # Disable these to avoid build warnings.
   enable_bytecode_checks = false
+  enable_desugar = false
 
   jar_path = "lib/accessibility-test-framework.jar"
   deps = [
diff --git a/third_party/blink/common/privacy_budget/aggregating_sample_collector_unittest.cc b/third_party/blink/common/privacy_budget/aggregating_sample_collector_unittest.cc
index ebce0d8..1ca56b72 100644
--- a/third_party/blink/common/privacy_budget/aggregating_sample_collector_unittest.cc
+++ b/third_party/blink/common/privacy_budget/aggregating_sample_collector_unittest.cc
@@ -41,6 +41,8 @@
   bool IsAnyTypeOrSurfaceBlocked() const override { return false; }
   bool IsSurfaceAllowed(IdentifiableSurface) const override { return true; }
   bool IsTypeAllowed(IdentifiableSurface::Type) const override { return true; }
+  int SampleRate(IdentifiableSurface) const override { return 1; }
+  int SampleRate(IdentifiableSurface::Type) const override { return 1; }
 };
 
 }  // namespace
diff --git a/third_party/blink/common/privacy_budget/identifiability_study_settings.cc b/third_party/blink/common/privacy_budget/identifiability_study_settings.cc
index d1b9661..a218d75 100644
--- a/third_party/blink/common/privacy_budget/identifiability_study_settings.cc
+++ b/third_party/blink/common/privacy_budget/identifiability_study_settings.cc
@@ -8,6 +8,7 @@
 #include "base/compiler_specific.h"
 #include "base/no_destructor.h"
 #include "base/optional.h"
+#include "base/rand_util.h"
 #include "base/synchronization/atomic_flag.h"
 #include "third_party/blink/public/common/privacy_budget/identifiability_study_settings_provider.h"
 
@@ -80,6 +81,16 @@
   base::AtomicFlag initialized_;
 };
 
+bool DecideSample(int sample_rate) {
+  if (sample_rate == 0)
+    return false;
+
+  if (sample_rate == 1)
+    return true;
+
+  return base::RandGenerator(sample_rate) == 0;
+}
+
 }  // namespace
 
 IdentifiabilityStudySettingsProvider::~IdentifiabilityStudySettingsProvider() =
@@ -142,4 +153,20 @@
       IdentifiableSurface::Type::kWebFeature, feature));
 }
 
+bool IdentifiabilityStudySettings::ShouldSample(
+    IdentifiableSurface surface) const {
+  if (LIKELY(!is_enabled_))
+    return false;
+
+  return DecideSample(provider_->SampleRate(surface));
+}
+
+bool IdentifiabilityStudySettings::ShouldSample(
+    IdentifiableSurface::Type type) const {
+  if (LIKELY(!is_enabled_))
+    return false;
+
+  return DecideSample(provider_->SampleRate(type));
+}
+
 }  // namespace blink
diff --git a/third_party/blink/common/privacy_budget/identifiability_study_settings_unittest.cc b/third_party/blink/common/privacy_budget/identifiability_study_settings_unittest.cc
index e134197..fb181789 100644
--- a/third_party/blink/common/privacy_budget/identifiability_study_settings_unittest.cc
+++ b/third_party/blink/common/privacy_budget/identifiability_study_settings_unittest.cc
@@ -48,6 +48,10 @@
     return state_->response_for_is_allowed;
   }
 
+  int SampleRate(IdentifiableSurface surface) const override { return 1; }
+
+  int SampleRate(IdentifiableSurface::Type type) const override { return 1; }
+
  private:
   CallCounts* state_ = nullptr;
 };
diff --git a/third_party/blink/public/common/privacy_budget/identifiability_study_settings.h b/third_party/blink/public/common/privacy_budget/identifiability_study_settings.h
index 23777fd3..a59ef3b 100644
--- a/third_party/blink/public/common/privacy_budget/identifiability_study_settings.h
+++ b/third_party/blink/public/common/privacy_budget/identifiability_study_settings.h
@@ -63,14 +63,16 @@
   // true, it doesn't return false at any point after. The converse is not true.
   bool IsActive() const;
 
-  // Returns true if |surface| is allowed.
+  // Returns true if |surface| is allowed to be sampled. Be sure to check
+  // ShouldSample before actually collecting a sample.
   //
   // Will always return false if IsActive() is false. I.e. If the study is
   // inactive, all surfaces are considered to be blocked. Hence it is sufficient
   // to call this function directly instead of calling IsActive() before it.
   bool IsSurfaceAllowed(IdentifiableSurface surface) const;
 
-  // Returns true if |type| is allowed.
+  // Returns true if |type| is allowed to be sampled. Be sure to check
+  // ShouldSample before actually collecting a sample.
   //
   // Will always return false if IsActive() is false. I.e. If the study is
   // inactive, all surface types are considered to be blocked. Hence it is
@@ -78,6 +80,22 @@
   // before it.
   bool IsTypeAllowed(IdentifiableSurface::Type type) const;
 
+  // Returns true if |surface| should be sampled.
+  //
+  // Will always return false if IsActive() is false or if IsSurfaceAllowed() is
+  // false. I.e. If the study is inactive, all surfaces are considered to be
+  // blocked. Hence it is sufficient to call this function directly instead of
+  // calling IsActive() before it.
+  bool ShouldSample(IdentifiableSurface surface) const;
+
+  // Returns true if |type| should be sampled.
+  //
+  // Will always return false if IsActive() is false or if IsTypeAllowed() is
+  // false. I.e. If the study is inactive, all surface types are considered to
+  // be blocked. Hence it is sufficient to call this function directly instead
+  // of calling IsActive() before it.
+  bool ShouldSample(IdentifiableSurface::Type type) const;
+
   // Convenience method for determining whether the surface constructable from
   // the type (|kWebFeature|) and the |feature| is allowed. See IsSurfaceAllowed
   // for more detail.
diff --git a/third_party/blink/public/common/privacy_budget/identifiability_study_settings_provider.h b/third_party/blink/public/common/privacy_budget/identifiability_study_settings_provider.h
index 1aa41a66..2ac98fd 100644
--- a/third_party/blink/public/common/privacy_budget/identifiability_study_settings_provider.h
+++ b/third_party/blink/public/common/privacy_budget/identifiability_study_settings_provider.h
@@ -26,15 +26,25 @@
   // Only meaningful if IsActive() returns true.
   virtual bool IsAnyTypeOrSurfaceBlocked() const = 0;
 
-  // Returns true if the given surface should be sampled.
+  // Returns true if the given surface is allowed to be sampled.
   //
   // If IsActive() is false, this method will not be called.
   virtual bool IsSurfaceAllowed(IdentifiableSurface surface) const = 0;
 
-  // Returns true if the given surface type should be sampled.
+  // Returns true if the given surface type is allowed to be sampled.
   //
   // If IsActive() is false, this method will not be called.
   virtual bool IsTypeAllowed(IdentifiableSurface::Type type) const = 0;
+
+  // Returns the sample rate of the given surface.
+  //
+  // If IsActive() is false, this method will return 0.
+  virtual int SampleRate(IdentifiableSurface surface) const = 0;
+
+  // Returns the sample rate of the given surface type.
+  //
+  // If IsActive() is false, this method will return 0.
+  virtual int SampleRate(IdentifiableSurface::Type type) const = 0;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/public/platform/web_security_origin.h b/third_party/blink/public/platform/web_security_origin.h
index d05027f..c7b2569 100644
--- a/third_party/blink/public/platform/web_security_origin.h
+++ b/third_party/blink/public/platform/web_security_origin.h
@@ -109,6 +109,18 @@
   // passwords stored in password manager.
   BLINK_PLATFORM_EXPORT bool CanAccessPasswordManager() const;
 
+  // This method implements HTML's "same origin" check, which verifies equality
+  // of opaque origins, or exact (scheme,host,port) matches. Note that
+  // `document.domain` does not come into play for this comparison.
+  //
+  // This method does not take the "universal access" flag into account. It does
+  // take the "local access" flag into account, considering `file:` origins that
+  // set the flag to be same-origin with all other `file:` origins that set the
+  // flag.
+  //
+  // https://html.spec.whatwg.org/#same-origin
+  BLINK_PLATFORM_EXPORT bool IsSameOriginWith(const WebSecurityOrigin&) const;
+
 #if INSIDE_BLINK
   BLINK_PLATFORM_EXPORT WebSecurityOrigin(scoped_refptr<const SecurityOrigin>);
   BLINK_PLATFORM_EXPORT WebSecurityOrigin& operator=(
diff --git a/third_party/blink/renderer/bindings/modules/v8/generated.gni b/third_party/blink/renderer/bindings/modules/v8/generated.gni
index 51cf44a..797c332 100644
--- a/third_party/blink/renderer/bindings/modules/v8/generated.gni
+++ b/third_party/blink/renderer/bindings/modules/v8/generated.gni
@@ -97,6 +97,8 @@
   "$bindings_modules_v8_output_dir/string_or_array_buffer_or_array_buffer_view_or_ndef_message_init.h",
   "$bindings_modules_v8_output_dir/string_or_canvas_gradient_or_canvas_pattern.cc",
   "$bindings_modules_v8_output_dir/string_or_canvas_gradient_or_canvas_pattern.h",
+  "$bindings_modules_v8_output_dir/string_or_document_fragment_or_document.cc",
+  "$bindings_modules_v8_output_dir/string_or_document_fragment_or_document.h",
   "$bindings_modules_v8_output_dir/string_or_string_sequence_or_constrain_dom_string_parameters.cc",
   "$bindings_modules_v8_output_dir/string_or_string_sequence_or_constrain_dom_string_parameters.h",
   "$bindings_modules_v8_output_dir/string_or_unsigned_long.cc",
diff --git a/third_party/blink/renderer/core/css/build.gni b/third_party/blink/renderer/core/css/build.gni
index 41cf5d09..ce86cff 100644
--- a/third_party/blink/renderer/core/css/build.gni
+++ b/third_party/blink/renderer/core/css/build.gni
@@ -248,6 +248,8 @@
   "cssom/css_numeric_value.h",
   "cssom/css_numeric_value_type.cc",
   "cssom/css_numeric_value_type.h",
+  "cssom/css_paint_worklet_input.cc",
+  "cssom/css_paint_worklet_input.h",
   "cssom/css_perspective.cc",
   "cssom/css_perspective.h",
   "cssom/css_position_value.cc",
@@ -295,7 +297,6 @@
   "cssom/inline_style_property_map.h",
   "cssom/paint_worklet_deferred_image.cc",
   "cssom/paint_worklet_deferred_image.h",
-  "cssom/paint_worklet_input.cc",
   "cssom/paint_worklet_input.h",
   "cssom/paint_worklet_style_property_map.cc",
   "cssom/paint_worklet_style_property_map.h",
diff --git a/third_party/blink/renderer/core/css/css_paint_value.cc b/third_party/blink/renderer/core/css/css_paint_value.cc
index dd113798..bac65b23 100644
--- a/third_party/blink/renderer/core/css/css_paint_value.cc
+++ b/third_party/blink/renderer/core/css/css_paint_value.cc
@@ -8,8 +8,8 @@
 #include "third_party/blink/renderer/core/css/css_custom_ident_value.h"
 #include "third_party/blink/renderer/core/css/css_paint_image_generator.h"
 #include "third_party/blink/renderer/core/css/css_syntax_definition.h"
+#include "third_party/blink/renderer/core/css/cssom/css_paint_worklet_input.h"
 #include "third_party/blink/renderer/core/css/cssom/paint_worklet_deferred_image.h"
-#include "third_party/blink/renderer/core/css/cssom/paint_worklet_input.h"
 #include "third_party/blink/renderer/core/css/cssom/style_value_factory.h"
 #include "third_party/blink/renderer/core/css/properties/computed_style_utils.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
@@ -163,8 +163,8 @@
       Vector<std::unique_ptr<CrossThreadStyleValue>>
           cross_thread_input_arguments;
       BuildInputArgumentValues(cross_thread_input_arguments);
-      scoped_refptr<PaintWorkletInput> input =
-          base::MakeRefCounted<PaintWorkletInput>(
+      scoped_refptr<CSSPaintWorkletInput> input =
+          base::MakeRefCounted<CSSPaintWorkletInput>(
               GetName(), target_size, zoom, device_scale_factor,
               generator.WorkletId(), std::move(style_data.value()),
               std::move(cross_thread_input_arguments),
diff --git a/third_party/blink/renderer/core/css/cssom/paint_worklet_input.cc b/third_party/blink/renderer/core/css/cssom/css_paint_worklet_input.cc
similarity index 73%
rename from third_party/blink/renderer/core/css/cssom/paint_worklet_input.cc
rename to third_party/blink/renderer/core/css/cssom/css_paint_worklet_input.cc
index 2557f7d..3a4827e2 100644
--- a/third_party/blink/renderer/core/css/cssom/paint_worklet_input.cc
+++ b/third_party/blink/renderer/core/css/cssom/css_paint_worklet_input.cc
@@ -4,11 +4,11 @@
 
 #include <utility>
 
-#include "third_party/blink/renderer/core/css/cssom/paint_worklet_input.h"
+#include "third_party/blink/renderer/core/css/cssom/css_paint_worklet_input.h"
 
 namespace blink {
 
-PaintWorkletInput::PaintWorkletInput(
+CSSPaintWorkletInput::CSSPaintWorkletInput(
     const String& name,
     const FloatSize& container_size,
     float effective_zoom,
@@ -17,13 +17,11 @@
     PaintWorkletStylePropertyMap::CrossThreadData data,
     Vector<std::unique_ptr<CrossThreadStyleValue>> parsed_input_arguments,
     cc::PaintWorkletInput::PropertyKeys property_keys)
-    : name_(name.IsolatedCopy()),
-      container_size_(container_size),
+    : PaintWorkletInput(container_size, worklet_id, property_keys),
+      name_(name.IsolatedCopy()),
       effective_zoom_(effective_zoom),
       device_scale_factor_(device_scale_factor),
-      worklet_id_(worklet_id),
       style_map_data_(std::move(data)),
-      parsed_input_arguments_(std::move(parsed_input_arguments)),
-      property_keys_(std::move(property_keys)) {}
+      parsed_input_arguments_(std::move(parsed_input_arguments)) {}
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/cssom/css_paint_worklet_input.h b/third_party/blink/renderer/core/css/cssom/css_paint_worklet_input.h
new file mode 100644
index 0000000..d6c7c8a
--- /dev/null
+++ b/third_party/blink/renderer/core/css/cssom/css_paint_worklet_input.h
@@ -0,0 +1,76 @@
+// 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_CORE_CSS_CSSOM_CSS_PAINT_WORKLET_INPUT_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSSOM_CSS_PAINT_WORKLET_INPUT_H_
+
+#include <memory>
+#include <utility>
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/css/cssom/paint_worklet_input.h"
+#include "third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map.h"
+#include "third_party/blink/renderer/platform/geometry/float_size.h"
+#include "third_party/blink/renderer/platform/graphics/compositor_element_id.h"
+
+namespace blink {
+
+// CSSPaintWorkletInput encapsulates the necessary information to run a CSS
+// Paint instance (a 'PaintWorklet') for a given target (e.g. the
+// 'background-image' property of a particular element). It is used to enable
+// Off-Thread PaintWorklet, allowing us to defer the actual JavaScript calls
+// until the cc-Raster phase (and even then run the JavaScript on a separate
+// worklet thread).
+//
+// This object is passed cross-thread, but contains thread-unsafe objects (the
+// WTF::Strings for |name_| and the WTF::Strings stored in |style_map_|). As
+// such CSSPaintWorkletInput must be treated carefully. In essence, it 'belongs'
+// to the PaintWorklet thread for the purposes of the WTF::String members. None
+// of the WTF::String accessors should be accessed on any thread apart from the
+// PaintWorklet thread, where an IsolatedCopy should still be taken.
+//
+// An IsolatedCopy is still needed on the PaintWorklet thread because
+// cc::PaintWorkletInput is thread-safe ref-counted (it is shared between Blink,
+// cc-impl, and the cc-raster thread pool), so we *do not know* on what thread
+// this object will die - and thus on what thread the WTF::Strings that it
+// contains will die.
+class CORE_EXPORT CSSPaintWorkletInput : public PaintWorkletInput {
+ public:
+  CSSPaintWorkletInput(
+      const String& name,
+      const FloatSize& container_size,
+      float effective_zoom,
+      float device_scale_factor,
+      int worklet_id,
+      PaintWorkletStylePropertyMap::CrossThreadData values,
+      Vector<std::unique_ptr<CrossThreadStyleValue>> parsed_input_args,
+      cc::PaintWorkletInput::PropertyKeys property_keys);
+
+  ~CSSPaintWorkletInput() override = default;
+
+  // These accessors are safe on any thread.
+  float EffectiveZoom() const { return effective_zoom_; }
+  float DeviceScaleFactor() const { return device_scale_factor_; }
+  const Vector<std::unique_ptr<CrossThreadStyleValue>>& ParsedInputArguments()
+      const {
+    return parsed_input_arguments_;
+  }
+
+  // These should only be accessed on the PaintWorklet thread.
+  String NameCopy() const { return name_.IsolatedCopy(); }
+  PaintWorkletStylePropertyMap::CrossThreadData StyleMapData() const {
+    return PaintWorkletStylePropertyMap::CopyCrossThreadData(style_map_data_);
+  }
+
+ private:
+  const String name_;
+  const float effective_zoom_;
+  const float device_scale_factor_;
+  PaintWorkletStylePropertyMap::CrossThreadData style_map_data_;
+  Vector<std::unique_ptr<CrossThreadStyleValue>> parsed_input_arguments_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSSOM_CSS_PAINT_WORKLET_INPUT_H_
diff --git a/third_party/blink/renderer/core/css/cssom/css_style_image_value.cc b/third_party/blink/renderer/core/css/cssom/css_style_image_value.cc
index 2348a39..2c0b63f 100644
--- a/third_party/blink/renderer/core/css/cssom/css_style_image_value.cc
+++ b/third_party/blink/renderer/core/css/cssom/css_style_image_value.cc
@@ -36,8 +36,7 @@
 FloatSize CSSStyleImageValue::ElementSize(
     const FloatSize& default_object_size,
     const RespectImageOrientationEnum) const {
-  bool not_used;
-  return FloatSize(intrinsicWidth(not_used), intrinsicHeight(not_used));
+  return FloatSize(IntrinsicSize().value_or(IntSize()));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/cssom/paint_worklet_input.h b/third_party/blink/renderer/core/css/cssom/paint_worklet_input.h
index 3daffb7..6dde812 100644
--- a/third_party/blink/renderer/core/css/cssom/paint_worklet_input.h
+++ b/third_party/blink/renderer/core/css/cssom/paint_worklet_input.h
@@ -10,45 +10,14 @@
 
 #include "cc/paint/paint_worklet_input.h"
 #include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map.h"
 #include "third_party/blink/renderer/platform/geometry/float_size.h"
-#include "third_party/blink/renderer/platform/graphics/compositor_element_id.h"
 
 namespace blink {
 
-// PaintWorkletInput encapsulates the necessary information to run a CSS Paint
-// instance (a 'PaintWorklet') for a given target (e.g. the 'background-image'
-// property of a particular element). It is used to enable Off-Thread
-// PaintWorklet, allowing us to defer the actual JavaScript calls until the
-// cc-Raster phase (and even then run the JavaScript on a separate worklet
-// thread).
-//
-// This object is passed cross-thread, but contains thread-unsafe objects (the
-// WTF::Strings for |name_| and the WTF::Strings stored in |style_map_|). As
-// such PaintWorkletInput must be treated carefully. In essence, it 'belongs' to
-// the PaintWorklet thread for the purposes of the WTF::String members. None of
-// the WTF::String accessors should be accessed on any thread apart from the
-// PaintWorklet thread, where an IsolatedCopy should still be taken.
-//
-// An IsolatedCopy is still needed on the PaintWorklet thread because
-// cc::PaintWorkletInput is thread-safe ref-counted (it is shared between Blink,
-// cc-impl, and the cc-raster thread pool), so we *do not know* on what thread
-// this object will die - and thus on what thread the WTF::Strings that it
-// contains will die.
+// PaintWorkletInput contains information that is shared by the native and the
+// CSS paint worklet.
 class CORE_EXPORT PaintWorkletInput : public cc::PaintWorkletInput {
  public:
-  PaintWorkletInput(
-      const String& name,
-      const FloatSize& container_size,
-      float effective_zoom,
-      float device_scale_factor,
-      int worklet_id,
-      PaintWorkletStylePropertyMap::CrossThreadData values,
-      Vector<std::unique_ptr<CrossThreadStyleValue>> parsed_input_args,
-      cc::PaintWorkletInput::PropertyKeys property_keys);
-
-  ~PaintWorkletInput() override = default;
-
   // PaintWorkletInput implementation
   gfx::SizeF GetSize() const override {
     return gfx::SizeF(container_size_.Width(), container_size_.Height());
@@ -60,27 +29,20 @@
 
   // These accessors are safe on any thread.
   const FloatSize& ContainerSize() const { return container_size_; }
-  float EffectiveZoom() const { return effective_zoom_; }
-  float DeviceScaleFactor() const { return device_scale_factor_; }
-  const Vector<std::unique_ptr<CrossThreadStyleValue>>& ParsedInputArguments()
-      const {
-    return parsed_input_arguments_;
-  }
 
-  // These should only be accessed on the PaintWorklet thread.
-  String NameCopy() const { return name_.IsolatedCopy(); }
-  PaintWorkletStylePropertyMap::CrossThreadData StyleMapData() const {
-    return PaintWorkletStylePropertyMap::CopyCrossThreadData(style_map_data_);
-  }
+ protected:
+  PaintWorkletInput(const FloatSize& container_size,
+                    int worklet_id,
+                    cc::PaintWorkletInput::PropertyKeys property_keys)
+      : container_size_(container_size),
+        worklet_id_(worklet_id),
+        property_keys_(std::move(property_keys)) {}
+
+  ~PaintWorkletInput() override = default;
 
  private:
-  const String name_;
   const FloatSize container_size_;
-  const float effective_zoom_;
-  const float device_scale_factor_;
   const int worklet_id_;
-  PaintWorkletStylePropertyMap::CrossThreadData style_map_data_;
-  Vector<std::unique_ptr<CrossThreadStyleValue>> parsed_input_arguments_;
 
   // List of properties associated with this PaintWorkletInput.
   // Kept and initialized here, but used in CC, so using C++ std library types.
diff --git a/third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map_test.cc b/third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map_test.cc
index d8e1fda..69b7cf1 100644
--- a/third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map_test.cc
+++ b/third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map_test.cc
@@ -11,10 +11,10 @@
 #include "third_party/blink/renderer/core/css/css_computed_style_declaration.h"
 #include "third_party/blink/renderer/core/css/css_test_helpers.h"
 #include "third_party/blink/renderer/core/css/cssom/css_keyword_value.h"
+#include "third_party/blink/renderer/core/css/cssom/css_paint_worklet_input.h"
 #include "third_party/blink/renderer/core/css/cssom/css_unit_value.h"
 #include "third_party/blink/renderer/core/css/cssom/css_unparsed_value.h"
 #include "third_party/blink/renderer/core/css/cssom/css_unsupported_color_value.h"
-#include "third_party/blink/renderer/core/css/cssom/paint_worklet_input.h"
 #include "third_party/blink/renderer/core/css/properties/longhands/custom_property.h"
 #include "third_party/blink/renderer/core/dom/element.h"
 #include "third_party/blink/renderer/core/dom/node_computed_style.h"
@@ -50,7 +50,7 @@
   }
 
   void CheckUnregisteredProperty(base::WaitableEvent* waitable_event,
-                                 scoped_refptr<PaintWorkletInput> input) {
+                                 scoped_refptr<CSSPaintWorkletInput> input) {
     ASSERT_TRUE(!IsMainThread());
 
     PaintWorkletStylePropertyMap* map =
@@ -71,7 +71,7 @@
   }
 
   void CheckCrossThreadData(base::WaitableEvent* waitable_event,
-                            scoped_refptr<PaintWorkletInput> input) {
+                            scoped_refptr<CSSPaintWorkletInput> input) {
     DCHECK(!IsMainThread());
 
     PaintWorkletStylePropertyMap* map =
@@ -130,8 +130,8 @@
 
   Vector<std::unique_ptr<CrossThreadStyleValue>> input_arguments;
   std::vector<cc::PaintWorkletInput::PropertyKey> property_keys;
-  scoped_refptr<PaintWorkletInput> input =
-      base::MakeRefCounted<PaintWorkletInput>(
+  scoped_refptr<CSSPaintWorkletInput> input =
+      base::MakeRefCounted<CSSPaintWorkletInput>(
           "test", FloatSize(100, 100), 1.0f, 1.0f, 1, std::move(data.value()),
           std::move(input_arguments), std::move(property_keys));
   ASSERT_TRUE(input);
@@ -178,8 +178,8 @@
 
   EXPECT_TRUE(data.has_value());
   std::vector<cc::PaintWorkletInput::PropertyKey> property_keys;
-  scoped_refptr<PaintWorkletInput> input =
-      base::MakeRefCounted<PaintWorkletInput>(
+  scoped_refptr<CSSPaintWorkletInput> input =
+      base::MakeRefCounted<CSSPaintWorkletInput>(
           "test", FloatSize(100, 100), 1.0f, 1.0f, 1, std::move(data.value()),
           std::move(input_arguments), std::move(property_keys));
   DCHECK(input);
diff --git a/third_party/blink/renderer/core/css/media_query_evaluator.cc b/third_party/blink/renderer/core/css/media_query_evaluator.cc
index daad683..2286a3b 100644
--- a/third_party/blink/renderer/core/css/media_query_evaluator.cc
+++ b/third_party/blink/renderer/core/css/media_query_evaluator.cc
@@ -1005,7 +1005,7 @@
     bool result = func(expr.ExpValue(), kNoPrefix, *media_values_);
     Document* doc = nullptr;
     if (!skip_ukm_reporting_ && (doc = media_values_->GetDocument()) &&
-        (IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+        (IdentifiabilityStudySettings::Get()->ShouldSample(
             IdentifiableSurface::Type::kMediaQuery))) {
       RecordMediaQueryResult(doc, expr, result);
     }
diff --git a/third_party/blink/renderer/core/css/vision_deficiency.cc b/third_party/blink/renderer/core/css/vision_deficiency.cc
index 370529d..6e45aec 100644
--- a/third_party/blink/renderer/core/css/vision_deficiency.cc
+++ b/third_party/blink/renderer/core/css/vision_deficiency.cc
@@ -24,18 +24,25 @@
 AtomicString CreateVisionDeficiencyFilterUrl(
     VisionDeficiency vision_deficiency) {
   // The filter color matrices are based on the following research paper:
-  // Gustavo M. Machado, Manuel M. Oliveira, and Leandro A. F. Fernandes
+  // Gustavo M. Machado, Manuel M. Oliveira, and Leandro A. F. Fernandes,
   // "A Physiologically-based Model for Simulation of Color Vision Deficiency".
   // IEEE Transactions on Visualization and Computer Graphics. Volume 15 (2009),
   // Number 6, November/December 2009. pp. 1291-1298.
   // https://www.inf.ufrgs.br/~oliveira/pubs_files/CVD_Simulation/CVD_Simulation.html
+  //
+  // The filter grayscale matrix is based on the following research paper:
+  // Rang Man Ho Nguyen and Michael S. Brown,
+  // "Why You Should Forget Luminance Conversion and Do Something Better".
+  // IEEE Conference on Computer Vision and Pattern Recognition (CVPR),
+  // Honolulu, HI, 2017. pp. 6750-6758.
+  // https://openaccess.thecvf.com/content_cvpr_2017/papers/Nguyen_Why_You_Should_CVPR_2017_paper.pdf
   switch (vision_deficiency) {
     case VisionDeficiency::kAchromatopsia:
       return CreateFilterDataUrl(
           "<feColorMatrix values=\""
-          "0.299  0.587  0.114  0.000  0.000 "
-          "0.299  0.587  0.114  0.000  0.000 "
-          "0.299  0.587  0.114  0.000  0.000 "
+          "0.213  0.715  0.072  0.000  0.000 "
+          "0.213  0.715  0.072  0.000  0.000 "
+          "0.213  0.715  0.072  0.000  0.000 "
           "0.000  0.000  0.000  1.000  0.000 "
           "\"/>");
     case VisionDeficiency::kBlurredVision:
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index 87554717..f955a940 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -40,6 +40,7 @@
 
 #include "base/auto_reset.h"
 #include "base/macros.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/optional.h"
 #include "base/time/time.h"
 #include "cc/input/overscroll_behavior.h"
@@ -3995,6 +3996,23 @@
   return true;
 }
 
+namespace {
+
+enum class BeforeUnloadUse {
+  kNoDialogNoText,
+  kNoDialogNoUserGesture,
+  kNoDialogMultipleConfirmationForNavigation,
+  kShowDialog,
+  kNoDialogAutoCancelTrue,
+  kMaxValue = kNoDialogAutoCancelTrue,
+};
+
+void RecordBeforeUnloadUse(BeforeUnloadUse metric) {
+  base::UmaHistogramEnumeration("Document.BeforeUnloadDialog", metric);
+}
+
+}  // namespace
+
 bool Document::DispatchBeforeUnloadEvent(ChromeClient* chrome_client,
                                          bool is_reload,
                                          bool& did_allow_navigation) {
@@ -4033,24 +4051,14 @@
   if (!before_unload_event.defaultPrevented())
     DefaultEventHandler(before_unload_event);
 
-  enum BeforeUnloadDialogHistogramEnum {
-    kNoDialogNoText,
-    kNoDialogNoUserGesture,
-    kNoDialogMultipleConfirmationForNavigation,
-    kShowDialog,
-    kNoDialogAutoCancelTrue,
-    kDialogEnumMax
-  };
-  DEFINE_STATIC_LOCAL(EnumerationHistogram, beforeunload_dialog_histogram,
-                      ("Document.BeforeUnloadDialog", kDialogEnumMax));
   if (before_unload_event.returnValue().IsNull()) {
-    beforeunload_dialog_histogram.Count(kNoDialogNoText);
+    RecordBeforeUnloadUse(BeforeUnloadUse::kNoDialogNoText);
   }
   if (!GetFrame() || before_unload_event.returnValue().IsNull())
     return true;
 
   if (!GetFrame()->HasStickyUserActivation()) {
-    beforeunload_dialog_histogram.Count(kNoDialogNoUserGesture);
+    RecordBeforeUnloadUse(BeforeUnloadUse::kNoDialogNoUserGesture);
     String message =
         "Blocked attempt to show a 'beforeunload' confirmation panel for a "
         "frame that never had a user gesture since its load. "
@@ -4060,8 +4068,8 @@
   }
 
   if (did_allow_navigation) {
-    beforeunload_dialog_histogram.Count(
-        kNoDialogMultipleConfirmationForNavigation);
+    RecordBeforeUnloadUse(
+        BeforeUnloadUse::kNoDialogMultipleConfirmationForNavigation);
     String message =
         "Blocked attempt to show multiple 'beforeunload' confirmation panels "
         "for a single navigation.";
@@ -4072,14 +4080,13 @@
   // If |chrome_client| is null simply indicate that the navigation should
   // not proceed.
   if (!chrome_client) {
-    beforeunload_dialog_histogram.Count(kNoDialogAutoCancelTrue);
+    RecordBeforeUnloadUse(BeforeUnloadUse::kNoDialogAutoCancelTrue);
     did_allow_navigation = false;
     return false;
   }
 
   String text = before_unload_event.returnValue();
-  beforeunload_dialog_histogram.Count(
-      BeforeUnloadDialogHistogramEnum::kShowDialog);
+  RecordBeforeUnloadUse(BeforeUnloadUse::kShowDialog);
   const base::TimeTicks beforeunload_confirmpanel_start =
       base::TimeTicks::Now();
   did_allow_navigation =
diff --git a/third_party/blink/renderer/core/frame/dactyloscoper.cc b/third_party/blink/renderer/core/frame/dactyloscoper.cc
index df1dda7..91ed2e7c 100644
--- a/third_party/blink/renderer/core/frame/dactyloscoper.cc
+++ b/third_party/blink/renderer/core/frame/dactyloscoper.cc
@@ -25,8 +25,8 @@
 
 namespace {
 
-bool IsStudyEnabled(WebFeature feature) {
-  return IdentifiabilityStudySettings::Get()->IsSurfaceAllowed(
+bool ShouldSample(WebFeature feature) {
+  return IdentifiabilityStudySettings::Get()->ShouldSample(
       IdentifiableSurface::FromTypeAndToken(
           IdentifiableSurface::Type::kWebFeature, feature));
 }
@@ -48,7 +48,7 @@
 void Dactyloscoper::RecordDirectSurface(ExecutionContext* context,
                                         WebFeature feature,
                                         const IdentifiableToken& value) {
-  if (!context || !IsStudyEnabled(feature))
+  if (!context || !ShouldSample(feature))
     return;
   auto* window = DynamicTo<LocalDOMWindow>(context);
   if (!window)
@@ -63,7 +63,7 @@
 void Dactyloscoper::RecordDirectSurface(ExecutionContext* context,
                                         WebFeature feature,
                                         const String& str) {
-  if (!context || !IsStudyEnabled(feature))
+  if (!context || !ShouldSample(feature))
     return;
   if (str.IsEmpty())
     return;
@@ -75,7 +75,7 @@
 void Dactyloscoper::RecordDirectSurface(ExecutionContext* context,
                                         WebFeature feature,
                                         const Vector<String>& strs) {
-  if (!context || !IsStudyEnabled(feature))
+  if (!context || !ShouldSample(feature))
     return;
   if (strs.IsEmpty())
     return;
@@ -90,7 +90,7 @@
 void Dactyloscoper::RecordDirectSurface(ExecutionContext* context,
                                         WebFeature feature,
                                         const DOMArrayBufferView* buffer) {
-  if (!context || !IsStudyEnabled(feature))
+  if (!context || !ShouldSample(feature))
     return;
   if (!buffer || buffer->byteLengthAsSizeT() == 0)
     return;
diff --git a/third_party/blink/renderer/core/frame/navigator_ua.cc b/third_party/blink/renderer/core/frame/navigator_ua.cc
index be1a09e..3d03eb2 100644
--- a/third_party/blink/renderer/core/frame/navigator_ua.cc
+++ b/third_party/blink/renderer/core/frame/navigator_ua.cc
@@ -38,7 +38,7 @@
 void NavigatorUA::MaybeRecordMetrics(const NavigatorUAData& ua_data) {
   constexpr auto identifiable_surface = IdentifiableSurface::FromTypeAndToken(
       IdentifiableSurface::Type::kWebFeature, WebFeature::kNavigatorUserAgent);
-  if (LIKELY(!IdentifiabilityStudySettings::Get()->IsSurfaceAllowed(
+  if (LIKELY(!IdentifiabilityStudySettings::Get()->ShouldSample(
           identifiable_surface))) {
     return;
   }
diff --git a/third_party/blink/renderer/core/frame/navigator_ua_data.cc b/third_party/blink/renderer/core/frame/navigator_ua_data.cc
index 081acb39..a696f0c80 100644
--- a/third_party/blink/renderer/core/frame/navigator_ua_data.cc
+++ b/third_party/blink/renderer/core/frame/navigator_ua_data.cc
@@ -109,7 +109,7 @@
   DCHECK(execution_context);
 
   bool record_identifiability =
-      IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+      IdentifiabilityStudySettings::Get()->ShouldSample(
           IdentifiableSurface::Type::kNavigatorUAData_GetHighEntropyValues);
   UADataValues* values = MakeGarbageCollected<UADataValues>();
   for (const String& hint : hints) {
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc
index 30653c1..ca17f56 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc
+++ b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc
@@ -491,7 +491,7 @@
 }
 
 void CanvasAsyncBlobCreator::RecordIdentifiabilityMetric() {
-  if (!IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+  if (!IdentifiabilityStudySettings::Get()->ShouldSample(
           blink::IdentifiableSurface::Type::kCanvasReadback)) {
     return;
   }
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
index b245634e..d884ef69 100644
--- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
+++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -268,7 +268,7 @@
 
 void HTMLCanvasElement::IdentifiabilityReportWithDigest(
     IdentifiableToken canvas_contents_token) const {
-  if (IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+  if (IdentifiabilityStudySettings::Get()->ShouldSample(
           blink::IdentifiableSurface::Type::kCanvasReadback)) {
     RecordIdentifiabilityMetric(
         blink::IdentifiableSurface::FromTypeAndToken(
@@ -284,7 +284,7 @@
   auto* old_contents_cc_layer = ContentsCcLayer();
   auto* result = GetCanvasRenderingContextInternal(type, attributes);
 
-  if (IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+  if (IdentifiabilityStudySettings::Get()->ShouldSample(
           IdentifiableSurface::Type::kCanvasRenderingContext)) {
     IdentifiabilityMetricBuilder(ukm_params_.source_id)
         .Set(IdentifiableSurface::FromTypeAndToken(
diff --git a/third_party/blink/renderer/core/html/media/html_media_element.cc b/third_party/blink/renderer/core/html/media/html_media_element.cc
index 29cc65de..6e632f6 100644
--- a/third_party/blink/renderer/core/html/media/html_media_element.cc
+++ b/third_party/blink/renderer/core/html/media/html_media_element.cc
@@ -818,7 +818,7 @@
   MIMETypeRegistry::SupportsType support =
       GetSupportsType(ContentType(mime_type));
 
-  if (IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+  if (IdentifiabilityStudySettings::Get()->ShouldSample(
           blink::IdentifiableSurface::Type::kHTMLMediaElement_CanPlayType)) {
     blink::IdentifiabilityMetricBuilder(context->UkmSourceID())
         .Set(
diff --git a/third_party/blink/renderer/core/layout/layout_view.cc b/third_party/blink/renderer/core/layout/layout_view.cc
index 664890a..d40f5cd 100644
--- a/third_party/blink/renderer/core/layout/layout_view.cc
+++ b/third_party/blink/renderer/core/layout/layout_view.cc
@@ -137,15 +137,9 @@
   // Note that if an iframe has its render pipeline throttled, it will not
   // update layout here, and it will also not propagate the hit test into the
   // iframe's inner document.
-  if (RuntimeEnabledFeatures::CompositingOptimizationsEnabled()) {
-    if (!GetFrameView()->UpdateLifecycleToPrePaintClean(
-            DocumentUpdateReason::kHitTest))
-      return false;
-  } else {
-    if (!GetFrameView()->UpdateAllLifecyclePhasesExceptPaint(
-            DocumentUpdateReason::kHitTest))
-      return false;
-  }
+  if (!GetFrameView()->UpdateLifecycleToPrePaintClean(
+          DocumentUpdateReason::kHitTest))
+    return false;
   HitTestLatencyRecorder hit_test_latency_recorder(
       result.GetHitTestRequest().AllowsChildFrameContent());
   return HitTestNoLifecycleUpdate(location, result);
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc
index a6cba137..8f77b32 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc
@@ -156,7 +156,11 @@
   }
   if (IsItemCursor()) {
     DCHECK(root_box_fragment_);
-    return To<LayoutBlockFlow>(root_box_fragment_->GetLayoutObject());
+    const LayoutObject* layout_object =
+        root_box_fragment_->GetSelfOrContainerLayoutObject();
+    DCHECK(layout_object);
+    DCHECK(!layout_object->IsLayoutFlowThread());
+    return To<LayoutBlockFlow>(layout_object);
   }
   NOTREACHED();
   return nullptr;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h
index 2be4356..0d8be82 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h
@@ -252,6 +252,7 @@
   }
 
   // Returns the |LayoutBlockFlow| containing this cursor.
+  // When |this| is a column box, returns the multicol container.
   const LayoutBlockFlow* GetLayoutBlockFlow() const;
 
   // Return the index of the current physical box fragment of the containing
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_container.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_container.cc
index 27c3624..a1cdc817 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_container.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_container.cc
@@ -59,13 +59,15 @@
       transform_change == SVGTransformChange::kFull ||
       SVGLayoutSupport::ScreenScaleFactorChanged(Parent());
 
-  // When hasRelativeLengths() is false, no descendants have relative lengths
+  SVGContainerLayoutInfo layout_info;
+  layout_info.scale_factor_changed = did_screen_scale_factor_change_;
+  // When HasRelativeLengths() is false, no descendants have relative lengths
   // (hence no one is interested in viewport size changes).
-  bool layout_size_changed =
+  layout_info.viewport_changed =
       GetElement()->HasRelativeLengths() &&
       SVGLayoutSupport::LayoutSizeOfNearestViewportChanged(this);
 
-  content_.Layout(false, did_screen_scale_factor_change_, layout_size_changed);
+  content_.Layout(layout_info);
 
   bool bbox_changed = false;
   if (needs_boundaries_update_) {
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_hidden_container.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_hidden_container.cc
index 9330a101..0ab474f 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_hidden_container.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_hidden_container.cc
@@ -32,13 +32,15 @@
   DCHECK(NeedsLayout());
   LayoutAnalyzer::Scope analyzer(*this);
 
-  // When hasRelativeLengths() is false, no descendants have relative lengths
+  SVGContainerLayoutInfo layout_info;
+  layout_info.force_layout = SelfNeedsLayout();
+  // When HasRelativeLengths() is false, no descendants have relative lengths
   // (hence no one is interested in viewport size changes).
-  bool layout_size_changed =
+  layout_info.viewport_changed =
       GetElement()->HasRelativeLengths() &&
       SVGLayoutSupport::LayoutSizeOfNearestViewportChanged(this);
 
-  Content().Layout(SelfNeedsLayout(), false, layout_size_changed);
+  Content().Layout(layout_info);
   UpdateCachedBoundaries();
   ClearNeedsLayout();
 }
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
index 199191b..969e019 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
@@ -249,8 +249,11 @@
   is_layout_size_changed_ =
       viewport_may_have_changed && svg->HasRelativeLengths();
 
-  content_.Layout(false, did_screen_scale_factor_change_,
-                  is_layout_size_changed_);
+  SVGContainerLayoutInfo layout_info;
+  layout_info.scale_factor_changed = did_screen_scale_factor_change_;
+  layout_info.viewport_changed = is_layout_size_changed_;
+
+  content_.Layout(layout_info);
 
   if (needs_boundaries_or_transform_update_) {
     UpdateCachedBoundaries();
diff --git a/third_party/blink/renderer/core/layout/svg/svg_content_container.cc b/third_party/blink/renderer/core/layout/svg/svg_content_container.cc
index 89a5f45..8a5ca1f7 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_content_container.cc
+++ b/third_party/blink/renderer/core/layout/svg/svg_content_container.cc
@@ -14,14 +14,12 @@
 
 namespace blink {
 
-void SVGContentContainer::Layout(bool force_layout,
-                                 bool screen_scaling_factor_changed,
-                                 bool layout_size_changed) {
+void SVGContentContainer::Layout(const SVGContainerLayoutInfo& layout_info) {
   for (LayoutObject* child = children_.FirstChild(); child;
        child = child->NextSibling()) {
-    bool force_child_layout = force_layout;
+    bool force_child_layout = layout_info.force_layout;
 
-    if (screen_scaling_factor_changed) {
+    if (layout_info.scale_factor_changed) {
       // If the screen scaling factor changed we need to update the text
       // metrics (note: this also happens for layoutSizeChanged=true).
       if (child->IsSVGText())
@@ -29,7 +27,7 @@
       force_child_layout = true;
     }
 
-    if (layout_size_changed) {
+    if (layout_info.viewport_changed) {
       // When selfNeedsLayout is false and the layout size changed, we have to
       // check whether this child uses relative lengths
       if (auto* element = DynamicTo<SVGElement>(child->GetNode())) {
diff --git a/third_party/blink/renderer/core/layout/svg/svg_content_container.h b/third_party/blink/renderer/core/layout/svg/svg_content_container.h
index 2f255c3..8f0fed4e 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_content_container.h
+++ b/third_party/blink/renderer/core/layout/svg/svg_content_container.h
@@ -14,14 +14,18 @@
 class HitTestLocation;
 class HitTestResult;
 
+struct SVGContainerLayoutInfo {
+  bool force_layout = false;
+  bool scale_factor_changed = false;
+  bool viewport_changed = false;
+};
+
 // Content representation for an SVG container. Wraps a LayoutObjectChildList
 // with additional state related to the children of the container. Used by
 // <svg>, <g> etc.
 class SVGContentContainer {
  public:
-  void Layout(bool force_layout,
-              bool screen_scaling_factor_changed,
-              bool layout_size_changed);
+  void Layout(const SVGContainerLayoutInfo&);
   bool HitTest(HitTestResult&, const HitTestLocation&, HitTestAction) const;
 
   void ComputeBoundingBoxes(FloatRect& object_bounding_box,
diff --git a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
index 2f15c75..b9cf04d0 100644
--- a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
+++ b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
@@ -234,7 +234,7 @@
 void OffscreenCanvas::RecordIdentifiabilityMetric(
     const blink::IdentifiableSurface& surface,
     const IdentifiableToken& token) const {
-  if (!IdentifiabilityStudySettings::Get()->IsSurfaceAllowed(surface))
+  if (!IdentifiabilityStudySettings::Get()->ShouldSample(surface))
     return;
   blink::IdentifiabilityMetricBuilder(GetExecutionContext()->UkmSourceID())
       .Set(surface, token)
diff --git a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
index 91505de..04f286b 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
@@ -1450,15 +1450,10 @@
       !layout_object_->IsBox())
     return nullptr;
 
-    // Must be called with lifecycle >= compositing clean
+    // Must be called with lifecycle >= pre-paint clean
 #if DCHECK_IS_ON()
-  if (RuntimeEnabledFeatures::CompositingOptimizationsEnabled()) {
-    DCHECK_GE(GetDocument()->Lifecycle().GetState(),
-              DocumentLifecycle::kPrePaintClean);
-  } else {
-    DCHECK_GE(GetDocument()->Lifecycle().GetState(),
-              DocumentLifecycle::kCompositingAssignmentsClean);
-  }
+  DCHECK_GE(GetDocument()->Lifecycle().GetState(),
+            DocumentLifecycle::kPrePaintClean);
 #endif
 
   PaintLayer* layer = ToLayoutBox(layout_object_)->Layer();
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc
index 12d5de0..ff860fd 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc
@@ -698,7 +698,7 @@
     ExceptionState& exception_state) {
   const IdentifiableSurface surface = IdentifiableSurface::FromTypeAndToken(
       IdentifiableSurface::Type::kCanvasReadback, GetContextType());
-  if (IdentifiabilityStudySettings::Get()->IsSurfaceAllowed(surface)) {
+  if (IdentifiabilityStudySettings::Get()->ShouldSample(surface)) {
     blink::IdentifiabilityMetricBuilder(ukm_source_id_)
         .Set(surface, 0)
         .Record(ukm_recorder_);
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_api_test.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_api_test.cc
index 7354bc1..ead1d044 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_api_test.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_api_test.cc
@@ -393,6 +393,8 @@
   bool IsTypeAllowed(IdentifiableSurface::Type type) const override {
     return true;
   }
+  int SampleRate(IdentifiableSurface surface) const override { return 1; }
+  int SampleRate(IdentifiableSurface::Type type) const override { return 1; }
 };
 
 // An RAII class that opts into study participation using
diff --git a/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client.cc b/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client.cc
index a59c79bf..bd7c861 100644
--- a/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client.cc
+++ b/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client.cc
@@ -9,8 +9,8 @@
 #include "base/single_thread_task_runner.h"
 #include "third_party/blink/renderer/core/css/cssom/cross_thread_color_value.h"
 #include "third_party/blink/renderer/core/css/cssom/cross_thread_unit_value.h"
+#include "third_party/blink/renderer/core/css/cssom/css_paint_worklet_input.h"
 #include "third_party/blink/renderer/core/css/cssom/css_style_value.h"
-#include "third_party/blink/renderer/core/css/cssom/paint_worklet_input.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
 #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
@@ -184,8 +184,8 @@
   PaintWorkletGlobalScope* global_scope = global_scopes_[base::RandInt(
       0, (PaintWorklet::kNumGlobalScopesPerThread)-1)];
 
-  const PaintWorkletInput* input =
-      static_cast<const PaintWorkletInput*>(compositor_input);
+  const CSSPaintWorkletInput* input =
+      static_cast<const CSSPaintWorkletInput*>(compositor_input);
   CSSPaintDefinition* definition =
       global_scope->FindDefinition(input->NameCopy());
   PaintWorkletStylePropertyMap* style_map =
diff --git a/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client_test.cc b/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client_test.cc
index e0ab90e..d1e4d1be 100644
--- a/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client_test.cc
+++ b/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client_test.cc
@@ -12,7 +12,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_source_code.h"
 #include "third_party/blink/renderer/core/css/cssom/cross_thread_style_value.h"
-#include "third_party/blink/renderer/core/css/cssom/paint_worklet_input.h"
+#include "third_party/blink/renderer/core/css/cssom/css_paint_worklet_input.h"
 #include "third_party/blink/renderer/core/script/classic_script.h"
 #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
 #include "third_party/blink/renderer/core/workers/worker_reporting_proxy.h"
@@ -219,8 +219,8 @@
   PaintWorkletStylePropertyMap::CrossThreadData data;
   Vector<std::unique_ptr<CrossThreadStyleValue>> input_arguments;
   std::vector<cc::PaintWorkletInput::PropertyKey> property_keys;
-  scoped_refptr<PaintWorkletInput> input =
-      base::MakeRefCounted<PaintWorkletInput>(
+  scoped_refptr<CSSPaintWorkletInput> input =
+      base::MakeRefCounted<CSSPaintWorkletInput>(
           "foo", FloatSize(100, 100), 1.0f, 1.0f, 1, std::move(data),
           std::move(input_arguments), std::move(property_keys));
   sk_sp<PaintRecord> record = proxy_client->Paint(input.get(), {});
diff --git a/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc b/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc
index e1f0f8d..9baa8875 100644
--- a/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc
+++ b/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc
@@ -83,7 +83,7 @@
 
 void RecordGamepadsForIdentifiabilityStudy(ExecutionContext* context,
                                            GamepadList* gamepads) {
-  if (!context || !IdentifiabilityStudySettings::Get()->IsSurfaceAllowed(
+  if (!context || !IdentifiabilityStudySettings::Get()->ShouldSample(
                       IdentifiableSurface::FromTypeAndToken(
                           IdentifiableSurface::Type::kWebFeature,
                           WebFeature::kGetGamepads)))
diff --git a/third_party/blink/renderer/modules/keyboard/keyboard_layout.cc b/third_party/blink/renderer/modules/keyboard/keyboard_layout.cc
index da43ef0..d9bdfd9 100644
--- a/third_party/blink/renderer/modules/keyboard/keyboard_layout.cc
+++ b/third_party/blink/renderer/modules/keyboard/keyboard_layout.cc
@@ -86,7 +86,7 @@
   }
 
   if (!EnsureServiceConnected()) {
-    if (IdentifiabilityStudySettings::Get()->IsSurfaceAllowed(
+    if (IdentifiabilityStudySettings::Get()->ShouldSample(
             kGetKeyboardLayoutMapSurface)) {
       RecordGetLayoutMapResult(ExecutionContext::From(script_state),
                                IdentifiableToken());
@@ -133,9 +133,8 @@
     mojom::blink::GetKeyboardLayoutMapResultPtr result) {
   DCHECK(script_promise_resolver_);
 
-  bool instrumentation_on =
-      IdentifiabilityStudySettings::Get()->IsSurfaceAllowed(
-          kGetKeyboardLayoutMapSurface);
+  bool instrumentation_on = IdentifiabilityStudySettings::Get()->ShouldSample(
+      kGetKeyboardLayoutMapSurface);
 
   switch (result->status) {
     case mojom::blink::GetKeyboardLayoutMapStatus::kSuccess:
diff --git a/third_party/blink/renderer/modules/media_capabilities/media_capabilities_identifiability_metrics.cc b/third_party/blink/renderer/modules/media_capabilities/media_capabilities_identifiability_metrics.cc
index 28027e16..ff7af61 100644
--- a/third_party/blink/renderer/modules/media_capabilities/media_capabilities_identifiability_metrics.cc
+++ b/third_party/blink/renderer/modules/media_capabilities/media_capabilities_identifiability_metrics.cc
@@ -29,6 +29,11 @@
       IdentifiableSurface::Type::kMediaCapabilities_DecodingInfo);
 }
 
+bool ShouldSampleDecodingInfoType() {
+  return IdentifiabilityStudySettings::Get()->ShouldSample(
+      IdentifiableSurface::Type::kMediaCapabilities_DecodingInfo);
+}
+
 void RecordDecodingIdentifiabilityMetric(ExecutionContext* context,
                                          IdentifiableToken input_token,
                                          IdentifiableToken output_token) {
@@ -226,7 +231,7 @@
 void ReportDecodingInfoResult(ExecutionContext* context,
                               const MediaDecodingConfiguration* input,
                               const MediaCapabilitiesDecodingInfo* output) {
-  if (!IsDecodingInfoTypeAllowed())
+  if (!IsDecodingInfoTypeAllowed() || !ShouldSampleDecodingInfoType())
     return;
 
   RecordDecodingIdentifiabilityMetric(context, ComputeToken(input),
@@ -237,7 +242,7 @@
                               base::Optional<IdentifiableToken> input_token,
                               const MediaCapabilitiesDecodingInfo* output) {
   DCHECK_EQ(IsDecodingInfoTypeAllowed(), input_token.has_value());
-  if (!input_token.has_value())
+  if (!input_token.has_value() || !ShouldSampleDecodingInfoType())
     return;
 
   RecordDecodingIdentifiabilityMetric(context, input_token.value(),
@@ -246,7 +251,7 @@
 
 base::Optional<IdentifiableToken> ComputeDecodingInfoInputToken(
     const MediaDecodingConfiguration* input) {
-  if (!IsDecodingInfoTypeAllowed())
+  if (!IsDecodingInfoTypeAllowed() || !ShouldSampleDecodingInfoType())
     return base::nullopt;
 
   return ComputeToken(input);
diff --git a/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc b/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc
index 6d533e0e..cf3f588 100644
--- a/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc
+++ b/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc
@@ -331,7 +331,7 @@
   ContentType content_type(type);
   bool result = handler->CanSupportMimeType(content_type.GetType(),
                                             content_type.Parameter("codecs"));
-  if (IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+  if (IdentifiabilityStudySettings::Get()->ShouldSample(
           blink::IdentifiableSurface::Type::kMediaRecorder_IsTypeSupported)) {
     blink::IdentifiabilityMetricBuilder(context->UkmSourceID())
         .Set(blink::IdentifiableSurface::FromTypeAndToken(
diff --git a/third_party/blink/renderer/modules/mediasource/media_source.cc b/third_party/blink/renderer/modules/mediasource/media_source.cc
index 9c200df..19da60e1 100644
--- a/third_party/blink/renderer/modules/mediasource/media_source.cc
+++ b/third_party/blink/renderer/modules/mediasource/media_source.cc
@@ -431,7 +431,7 @@
 void MediaSource::RecordIdentifiabilityMetric(ExecutionContext* context,
                                               const String& type,
                                               bool result) {
-  if (!IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+  if (!IdentifiabilityStudySettings::Get()->ShouldSample(
           blink::IdentifiableSurface::Type::kMediaSource_IsTypeSupported)) {
     return;
   }
diff --git a/third_party/blink/renderer/modules/mediastream/identifiability_metrics.cc b/third_party/blink/renderer/modules/mediastream/identifiability_metrics.cc
index 0525e9ca..9e64389f 100644
--- a/third_party/blink/renderer/modules/mediastream/identifiability_metrics.cc
+++ b/third_party/blink/renderer/modules/mediastream/identifiability_metrics.cc
@@ -6,6 +6,7 @@
 
 #include "base/callback.h"
 #include "third_party/blink/public/common/privacy_budget/identifiability_metric_builder.h"
+#include "third_party/blink/public/common/privacy_budget/identifiability_study_settings.h"
 #include "third_party/blink/public/common/privacy_budget/identifiable_token.h"
 #include "third_party/blink/renderer/bindings/modules/v8/boolean_or_constrain_boolean_parameters.h"
 #include "third_party/blink/renderer/bindings/modules/v8/boolean_or_double_or_constrain_double_range.h"
@@ -247,7 +248,8 @@
 void RecordIdentifiabilityMetric(const IdentifiableSurface& surface,
                                  ExecutionContext* context,
                                  IdentifiableToken token) {
-  if (surface.IsValid() && context) {
+  if (surface.IsValid() && context &&
+      IdentifiabilityStudySettings::Get()->ShouldSample(surface)) {
     IdentifiabilityMetricBuilder(context->UkmSourceID())
         .Set(surface, token)
         .Record(context->UkmRecorder());
diff --git a/third_party/blink/renderer/modules/plugins/navigator_plugins.cc b/third_party/blink/renderer/modules/plugins/navigator_plugins.cc
index 543ddb7..f154e35 100644
--- a/third_party/blink/renderer/modules/plugins/navigator_plugins.cc
+++ b/third_party/blink/renderer/modules/plugins/navigator_plugins.cc
@@ -82,8 +82,7 @@
 void RecordMimeTypes(LocalDOMWindow* window, DOMMimeTypeArray* mime_types) {
   constexpr IdentifiableSurface surface = IdentifiableSurface::FromTypeAndToken(
       IdentifiableSurface::Type::kWebFeature, WebFeature::kNavigatorMimeTypes);
-  if (!IdentifiabilityStudySettings::Get()->IsSurfaceAllowed(surface) ||
-      !window) {
+  if (!IdentifiabilityStudySettings::Get()->ShouldSample(surface) || !window) {
     return;
   }
   IdentifiableTokenBuilder builder;
diff --git a/third_party/blink/renderer/modules/sanitizer_api/sanitizer.cc b/third_party/blink/renderer/modules/sanitizer_api/sanitizer.cc
index 2577ca4..8c3b5e6c 100644
--- a/third_party/blink/renderer/modules/sanitizer_api/sanitizer.cc
+++ b/third_party/blink/renderer/modules/sanitizer_api/sanitizer.cc
@@ -5,7 +5,9 @@
 #include "sanitizer.h"
 
 #include "third_party/blink/renderer/bindings/core/v8/v8_node_filter.h"
+#include "third_party/blink/renderer/bindings/modules/v8/string_or_document_fragment_or_document.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_sanitizer_config.h"
+#include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/document_fragment.h"
 #include "third_party/blink/renderer/core/dom/element.h"
 #include "third_party/blink/renderer/core/dom/node.h"
@@ -84,25 +86,35 @@
 Sanitizer::~Sanitizer() = default;
 
 String Sanitizer::sanitizeToString(ScriptState* script_state,
-                                   const String& input,
+                                   StringOrDocumentFragmentOrDocument& input,
                                    ExceptionState& exception_state) {
   return CreateMarkup(sanitize(script_state, input, exception_state),
                       kChildrenOnly);
 }
 
 DocumentFragment* Sanitizer::sanitize(ScriptState* script_state,
-                                      const String& input,
+                                      StringOrDocumentFragmentOrDocument& input,
                                       ExceptionState& exception_state) {
+  DocumentFragment* fragment = nullptr;
+
   LocalDOMWindow* window = LocalDOMWindow::From(script_state);
-  if (!window) {
+  if (input.IsDocumentFragment()) {
+    fragment = input.GetAsDocumentFragment();
+  } else if (window) {
+    Document* document = window->document();
+    if (input.IsString() || input.IsNull()) {
+      fragment = document->createDocumentFragment();
+      DCHECK(document->QuerySelector("body"));
+      fragment->ParseHTML(input.GetAsString(), document->QuerySelector("body"));
+    } else {
+      fragment = document->createDocumentFragment();
+      fragment->appendChild(input.GetAsDocument()->documentElement());
+    }
+  } else {
     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
                                       "Cannot find current DOM window.");
     return nullptr;
   }
-  Document* document = window->document();
-  DocumentFragment* fragment = document->createDocumentFragment();
-  DCHECK(document->QuerySelector("body"));
-  fragment->ParseHTML(input, document->QuerySelector("body"));
 
   Node* node = fragment->firstChild();
 
@@ -155,6 +167,8 @@
         }
       } else {
         for (const auto& name : element->getAttributeNames()) {
+          // Attributes in drop list or not in allow list while allow list
+          // exists will be dropped.
           bool drop = (drop_attributes_.Contains(name) &&
                        (drop_attributes_.at(name).Contains("*") ||
                         drop_attributes_.at(name).Contains(node_name))) ||
diff --git a/third_party/blink/renderer/modules/sanitizer_api/sanitizer.h b/third_party/blink/renderer/modules/sanitizer_api/sanitizer.h
index 3860e2db..26a4553 100644
--- a/third_party/blink/renderer/modules/sanitizer_api/sanitizer.h
+++ b/third_party/blink/renderer/modules/sanitizer_api/sanitizer.h
@@ -11,10 +11,12 @@
 
 namespace blink {
 
+class Document;
 class DocumentFragment;
 class ExceptionState;
 class SanitizerConfig;
 class ScriptState;
+class StringOrDocumentFragmentOrDocument;
 
 class MODULES_EXPORT Sanitizer final : public ScriptWrappable {
   DEFINE_WRAPPERTYPEINFO();
@@ -24,8 +26,12 @@
   explicit Sanitizer(const SanitizerConfig*);
   ~Sanitizer() override;
 
-  String sanitizeToString(ScriptState*, const String&, ExceptionState&);
-  DocumentFragment* sanitize(ScriptState*, const String&, ExceptionState&);
+  String sanitizeToString(ScriptState*,
+                          StringOrDocumentFragmentOrDocument&,
+                          ExceptionState&);
+  DocumentFragment* sanitize(ScriptState*,
+                             StringOrDocumentFragmentOrDocument&,
+                             ExceptionState&);
 
   void Trace(Visitor*) const override;
 
diff --git a/third_party/blink/renderer/modules/sanitizer_api/sanitizer.idl b/third_party/blink/renderer/modules/sanitizer_api/sanitizer.idl
index 3e7c52a2b..b8ada27 100644
--- a/third_party/blink/renderer/modules/sanitizer_api/sanitizer.idl
+++ b/third_party/blink/renderer/modules/sanitizer_api/sanitizer.idl
@@ -4,11 +4,13 @@
 
 // https://github.com/WICG/sanitizer-api
 
+typedef (DOMString or DocumentFragment or Document) SanitizerInput;
+
 [
   Exposed=Window,
   RuntimeEnabled=SanitizerAPI
 ] interface Sanitizer {
   [RaisesException] constructor(optional SanitizerConfig config = {});
-  [CallWith=ScriptState, RaisesException] DOMString sanitizeToString(DOMString input);
-  [CallWith=ScriptState, RaisesException] DocumentFragment sanitize(DOMString input);
+  [CallWith=ScriptState, RaisesException] DOMString sanitizeToString(SanitizerInput input);
+  [CallWith=ScriptState, RaisesException] DocumentFragment sanitize(SanitizerInput input);
 };
diff --git a/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller.cc b/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller.cc
index 0f4469f0..c1d92d0 100644
--- a/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller.cc
+++ b/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller.cc
@@ -241,7 +241,7 @@
   if (!pending_callback_ || request_id != request_id_)
     return;
 
-  if (IdentifiabilityStudySettings::Get()->IsSurfaceAllowed(
+  if (IdentifiabilityStudySettings::Get()->ShouldSample(
           IdentifiableSurface::FromTypeAndToken(
               IdentifiableSurface::Type::kWebFeature,
               WebFeature::kScreenOrientationLock))) {
diff --git a/third_party/blink/renderer/modules/speech/speech_synthesis.cc b/third_party/blink/renderer/modules/speech/speech_synthesis.cc
index d5a70a8..b71fb8b 100644
--- a/third_party/blink/renderer/modules/speech/speech_synthesis.cc
+++ b/third_party/blink/renderer/modules/speech/speech_synthesis.cc
@@ -106,7 +106,7 @@
   constexpr IdentifiableSurface surface = IdentifiableSurface::FromTypeAndToken(
       IdentifiableSurface::Type::kWebFeature,
       WebFeature::kSpeechSynthesis_GetVoices_Method);
-  if (!IdentifiabilityStudySettings::Get()->IsSurfaceAllowed(surface))
+  if (!IdentifiabilityStudySettings::Get()->ShouldSample(surface))
     return;
   ExecutionContext* context = GetExecutionContext();
   if (!context)
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
index 60b2835..85d4229 100644
--- a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
@@ -599,7 +599,7 @@
     GLenum internalformat,
     GLint* values,
     GLint length) {
-  if (!IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+  if (!IdentifiabilityStudySettings::Get()->ShouldSample(
           IdentifiableSurface::Type::kWebGLInternalFormatParameter))
     return;
   const auto& ukm_params = GetUkmParameters();
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
index 323b8829..7ce365c 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -884,7 +884,7 @@
 
     make_xr_compatible_resolver_ = nullptr;
 
-    if (IdentifiabilityStudySettings::Get()->IsSurfaceAllowed(
+    if (IdentifiabilityStudySettings::Get()->ShouldSample(
             IdentifiableSurface::FromTypeAndToken(
                 IdentifiableSurface::Type::kWebFeature,
                 WebFeature::kWebGLRenderingContextMakeXRCompatible))) {
@@ -3331,7 +3331,7 @@
 };
 
 bool ShouldMeasureGLParam(GLenum pname) {
-  return IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+  return IdentifiabilityStudySettings::Get()->ShouldSample(
              blink::IdentifiableSurface::Type::kWebGLParameter) &&
          std::find(std::begin(kIdentifiableGLParams),
                    std::end(kIdentifiableGLParams),
@@ -3343,8 +3343,8 @@
 void WebGLRenderingContextBase::RecordIdentifiableGLParameterDigest(
     GLenum pname,
     IdentifiableToken value) {
-  if (!ShouldMeasureGLParam(pname))
-    return;
+  DCHECK(IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+      blink::IdentifiableSurface::Type::kWebGLParameter));
   const auto ukm_params = GetUkmParameters();
   blink::IdentifiabilityMetricBuilder(ukm_params.source_id)
       .Set(blink::IdentifiableSurface::FromTypeAndToken(
@@ -3357,9 +3357,8 @@
     GLenum shader_type,
     GLenum precision_type,
     WebGLShaderPrecisionFormat* format) {
-  if (!IdentifiabilityStudySettings::Get()->IsTypeAllowed(
-          blink::IdentifiableSurface::Type::kWebGLShaderPrecisionFormat))
-    return;
+  DCHECK(IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+      blink::IdentifiableSurface::Type::kWebGLShaderPrecisionFormat));
 
   const auto& ukm_params = GetUkmParameters();
   IdentifiableTokenBuilder builder;
@@ -3517,7 +3516,7 @@
     case GL_SCISSOR_TEST:
       return GetBooleanParameter(script_state, pname);
     case GL_SHADING_LANGUAGE_VERSION:
-      if (IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+      if (IdentifiabilityStudySettings::Get()->ShouldSample(
               blink::IdentifiableSurface::Type::kWebGLParameter)) {
         RecordIdentifiableGLParameterDigest(
             pname, IdentifiabilityBenignStringToken(String(
@@ -3585,7 +3584,7 @@
     case GL_VENDOR:
       return WebGLAny(script_state, String("WebKit"));
     case GL_VERSION:
-      if (IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+      if (IdentifiabilityStudySettings::Get()->ShouldSample(
               blink::IdentifiableSurface::Type::kWebGLParameter)) {
         RecordIdentifiableGLParameterDigest(
             pname, IdentifiabilityBenignStringToken(
@@ -3606,7 +3605,7 @@
       return ScriptValue::CreateNull(script_state->GetIsolate());
     case WebGLDebugRendererInfo::kUnmaskedRendererWebgl:
       if (ExtensionEnabled(kWebGLDebugRendererInfoName)) {
-        if (IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+        if (IdentifiabilityStudySettings::Get()->ShouldSample(
                 blink::IdentifiableSurface::Type::kWebGLParameter)) {
           RecordIdentifiableGLParameterDigest(
               pname, IdentifiabilityBenignStringToken(
@@ -3621,7 +3620,7 @@
       return ScriptValue::CreateNull(script_state->GetIsolate());
     case WebGLDebugRendererInfo::kUnmaskedVendorWebgl:
       if (ExtensionEnabled(kWebGLDebugRendererInfoName)) {
-        if (IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+        if (IdentifiabilityStudySettings::Get()->ShouldSample(
                 blink::IdentifiableSurface::Type::kWebGLParameter)) {
           RecordIdentifiableGLParameterDigest(
               pname, IdentifiabilityBenignStringToken(
@@ -3808,7 +3807,10 @@
     case GL_RENDERBUFFER_DEPTH_SIZE:
     case GL_RENDERBUFFER_STENCIL_SIZE:
       ContextGL()->GetRenderbufferParameteriv(target, pname, &value);
-      RecordIdentifiableGLParameterDigest(pname, value);
+      if (IdentifiabilityStudySettings::Get()->ShouldSample(
+              blink::IdentifiableSurface::Type::kWebGLParameter)) {
+        RecordIdentifiableGLParameterDigest(pname, value);
+      }
       return WebGLAny(script_state, value);
     case GL_RENDERBUFFER_INTERNAL_FORMAT:
       return WebGLAny(script_state, renderbuffer_binding_->InternalFormat());
@@ -3886,7 +3888,10 @@
                                         &precision);
   auto* result = MakeGarbageCollected<WebGLShaderPrecisionFormat>(
       range[0], range[1], precision);
-  RecordShaderPrecisionFormatForStudy(shader_type, precision_type, result);
+  if (IdentifiabilityStudySettings::Get()->ShouldSample(
+          blink::IdentifiableSurface::Type::kWebGLShaderPrecisionFormat)) {
+    RecordShaderPrecisionFormatForStudy(shader_type, precision_type, result);
+  }
   return result;
 }
 
@@ -4671,7 +4676,7 @@
     GLenum format,
     GLenum type,
     MaybeShared<DOMArrayBufferView> pixels) {
-  if (IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+  if (IdentifiabilityStudySettings::Get()->ShouldSample(
           blink::IdentifiableSurface::Type::kCanvasReadback)) {
     const auto& ukm_params = GetUkmParameters();
     blink::IdentifiabilityMetricBuilder(ukm_params.source_id)
@@ -7174,7 +7179,10 @@
   GLfloat value = 0;
   if (!isContextLost())
     ContextGL()->GetFloatv(pname, &value);
-  RecordIdentifiableGLParameterDigest(pname, value);
+  if (IdentifiabilityStudySettings::Get()->ShouldSample(
+          blink::IdentifiableSurface::Type::kWebGLParameter)) {
+    RecordIdentifiableGLParameterDigest(pname, value);
+  }
   return WebGLAny(script_state, value);
 }
 
@@ -7197,7 +7205,10 @@
         break;
     }
   }
-  RecordIdentifiableGLParameterDigest(pname, value);
+  if (IdentifiabilityStudySettings::Get()->ShouldSample(
+          blink::IdentifiableSurface::Type::kWebGLParameter)) {
+    RecordIdentifiableGLParameterDigest(pname, value);
+  }
   return WebGLAny(script_state, value);
 }
 
diff --git a/third_party/blink/renderer/modules/webgpu/gpu.cc b/third_party/blink/renderer/modules/webgpu/gpu.cc
index 293384e..c74039a 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu.cc
@@ -130,7 +130,7 @@
     GPUAdapter* adapter) const {
   constexpr IdentifiableSurface::Type type =
       IdentifiableSurface::Type::kGPU_RequestAdapter;
-  if (!IdentifiabilityStudySettings::Get()->IsTypeAllowed(type))
+  if (!IdentifiabilityStudySettings::Get()->ShouldSample(type))
     return;
   ExecutionContext* context = GetExecutionContext();
   if (!context)
diff --git a/third_party/blink/renderer/modules/webmidi/midi_access.cc b/third_party/blink/renderer/modules/webmidi/midi_access.cc
index 84e0b38..44292396 100644
--- a/third_party/blink/renderer/modules/webmidi/midi_access.cc
+++ b/third_party/blink/renderer/modules/webmidi/midi_access.cc
@@ -88,7 +88,7 @@
   constexpr IdentifiableSurface surface = IdentifiableSurface::FromTypeAndToken(
       IdentifiableSurface::Type::kWebFeature,
       WebFeature::kRequestMIDIAccess_ObscuredByFootprinting);
-  if (IdentifiabilityStudySettings::Get()->IsSurfaceAllowed(surface)) {
+  if (IdentifiabilityStudySettings::Get()->ShouldSample(surface)) {
     IdentifiableTokenBuilder builder;
     for (const auto& port : ports) {
       builder.AddToken(IdentifiabilityBenignStringToken(port.id));
diff --git a/third_party/blink/renderer/platform/exported/web_security_origin.cc b/third_party/blink/renderer/platform/exported/web_security_origin.cc
index a465d67..52e70dc 100644
--- a/third_party/blink/renderer/platform/exported/web_security_origin.cc
+++ b/third_party/blink/renderer/platform/exported/web_security_origin.cc
@@ -113,6 +113,12 @@
   return private_->CanAccessPasswordManager();
 }
 
+bool WebSecurityOrigin::IsSameOriginWith(const WebSecurityOrigin& other) const {
+  DCHECK(private_);
+  DCHECK(other.private_);
+  return private_->IsSameOriginWith(other.private_.Get());
+}
+
 WebSecurityOrigin::WebSecurityOrigin(scoped_refptr<const SecurityOrigin> origin)
     : private_(std::move(origin)) {}
 
diff --git a/third_party/blink/renderer/platform/fonts/font_matching_metrics.cc b/third_party/blink/renderer/platform/fonts/font_matching_metrics.cc
index 42ad9d6..eb5f91d 100644
--- a/third_party/blink/renderer/platform/fonts/font_matching_metrics.cc
+++ b/third_party/blink/renderer/platform/fonts/font_matching_metrics.cc
@@ -284,8 +284,8 @@
   for (const auto& surface_entry : hash_maps_with_corresponding_surface_types) {
     TokenToTokenHashMap* hash_map = surface_entry.first;
     const IdentifiableSurface::Type& surface_type = surface_entry.second;
-    if (IdentifiabilityStudySettings::Get()->IsTypeAllowed(surface_type)) {
-      for (const auto& individual_lookup : *hash_map) {
+    for (const auto& individual_lookup : *hash_map) {
+      if (IdentifiabilityStudySettings::Get()->ShouldSample(surface_type)) {
         builder.Set(IdentifiableSurface::FromTypeAndToken(
                         surface_type, individual_lookup.key.token),
                     individual_lookup.value);
diff --git a/third_party/blink/renderer/platform/graphics/identifiability_paint_op_digest_unittest.cc b/third_party/blink/renderer/platform/graphics/identifiability_paint_op_digest_unittest.cc
index bc72d425..e9262667 100644
--- a/third_party/blink/renderer/platform/graphics/identifiability_paint_op_digest_unittest.cc
+++ b/third_party/blink/renderer/platform/graphics/identifiability_paint_op_digest_unittest.cc
@@ -27,6 +27,8 @@
   bool IsTypeAllowed(IdentifiableSurface::Type type) const override {
     return true;
   }
+  int SampleRate(IdentifiableSurface surface) const override { return 1; }
+  int SampleRate(IdentifiableSurface::Type type) const override { return 1; }
 };
 
 // An RAII class that opts into study participation using
diff --git a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc
index 4d81997..0d6e8d5 100644
--- a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc
+++ b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc
@@ -315,7 +315,7 @@
     kOrientationTag = 0x112,
     kResolutionXTag = 0x11a,
     kResolutionYTag = 0x11b,
-    kresolution_unitTag = 0x128,
+    kResolutionUnitTag = 0x128,
     kPixelXDimensionTag = 0xa002,
     kPixelYDimensionTag = 0xa003,
     kExifOffsetTag = 0x8769
@@ -353,7 +353,7 @@
           metadata.orientation = ImageOrientation::FromEXIFValue(ReadUint16(value_ptr, is_big_endian));
         break;
 
-      case ExifTags::kresolution_unitTag:
+      case ExifTags::kResolutionUnitTag:
         if (type == kUnsignedShortType && count == 1)
           metadata.resolution_unit = ReadUint16(value_ptr, is_big_endian);
         break;
@@ -431,7 +431,7 @@
     // http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf
     JOCTET* data_end = marker->data + marker->data_length;
     JOCTET* root_start = marker->data + kOffsetToTiffData;
-    JOCTET* tiff_start = marker->data + ifd_offset;
+    JOCTET* tiff_start = marker->data + ifd_offset - 2;
     JOCTET* ifd0 = root_start + ifd_offset;
 
     ReadExifDirectory(ifd0, tiff_start, root_start, data_end, is_big_endian, metadata);
diff --git a/third_party/blink/renderer/platform/wtf/allocator/partitions.cc b/third_party/blink/renderer/platform/wtf/allocator/partitions.cc
index ca2b037..e6c60b0 100644
--- a/third_party/blink/renderer/platform/wtf/allocator/partitions.cc
+++ b/third_party/blink/renderer/platform/wtf/allocator/partitions.cc
@@ -33,6 +33,7 @@
 #include "base/allocator/partition_allocator/memory_reclaimer.h"
 #include "base/allocator/partition_allocator/oom.h"
 #include "base/allocator/partition_allocator/page_allocator.h"
+#include "base/allocator/partition_allocator/partition_alloc_features.h"
 #include "base/debug/alias.h"
 #include "base/strings/safe_sprintf.h"
 #include "base/thread_annotations.h"
@@ -75,20 +76,38 @@
   // - BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC): Only one thread cache at a time
   //   is supported, in this case it is already claimed by malloc().
 #if DCHECK_IS_ON() && !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
-  fast_malloc_allocator.init({base::PartitionOptions::Alignment::kRegular,
-                              base::PartitionOptions::ThreadCache::kEnabled});
+  fast_malloc_allocator.init(
+      {base::PartitionOptions::Alignment::kRegular,
+       base::PartitionOptions::ThreadCache::kEnabled,
+       base::PartitionOptions::PCScan::kDisabledByDefault});
 #else
-  fast_malloc_allocator.init();
+  fast_malloc_allocator.init(
+      {base::PartitionOptions::Alignment::kRegular,
+       base::PartitionOptions::ThreadCache::kDisabled,
+       base::PartitionOptions::PCScan::kDisabledByDefault});
 #endif
-  array_buffer_allocator.init();
-  buffer_allocator.init();
-  layout_allocator.init();
+  array_buffer_allocator.init(
+      {base::PartitionOptions::Alignment::kRegular,
+       base::PartitionOptions::ThreadCache::kDisabled,
+       base::PartitionOptions::PCScan::kAlwaysDisabled});
+  buffer_allocator.init({base::PartitionOptions::Alignment::kRegular,
+                         base::PartitionOptions::ThreadCache::kDisabled,
+                         base::PartitionOptions::PCScan::kDisabledByDefault});
+  layout_allocator.init({base::PartitionOptions::Alignment::kRegular,
+                         base::PartitionOptions::ThreadCache::kDisabled,
+                         base::PartitionOptions::PCScan::kDisabledByDefault});
 
   fast_malloc_root_ = fast_malloc_allocator.root();
   array_buffer_root_ = array_buffer_allocator.root();
   buffer_root_ = buffer_allocator.root();
   layout_root_ = layout_allocator.root();
 
+  if (base::features::IsPartitionAllocPCScanEnabled()) {
+    fast_malloc_root_->EnablePCScan();
+    buffer_root_->EnablePCScan();
+    layout_root_->EnablePCScan();
+  }
+
   initialized_ = true;
   return initialized_;
 }
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 8a92358..15964b1 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2612,6 +2612,13 @@
 crbug.com/958381 [ Mac ] external/wpt/css/CSS2/tables/table-anonymous-objects-206.xht [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 [ Mac11.0 ] external/wpt/fetch/api/response/response-clone.any.worker.html [ Failure Timeout ]
+crbug.com/626703 [ Mac11.0 ] virtual/omt-worker-fetch/external/wpt/fetch/api/response/response-clone.any.sharedworker.html [ Failure Timeout ]
+crbug.com/626703 [ Mac11.0 ] external/wpt/fetch/api/response/response-clone.any.serviceworker.html [ Failure Timeout ]
+crbug.com/626703 [ Mac10.15 ] virtual/omt-worker-fetch/external/wpt/fetch/api/response/response-clone.any.serviceworker.html [ Failure Timeout ]
+crbug.com/626703 [ Mac11.0 ] virtual/omt-worker-fetch/external/wpt/fetch/api/response/response-clone.any.serviceworker.html [ Failure Timeout ]
+crbug.com/626703 [ Mac11.0 ] external/wpt/fetch/api/response/response-clone.any.html [ Failure Timeout ]
+crbug.com/626703 [ Mac11.0 ] virtual/omt-worker-fetch/external/wpt/fetch/api/response/response-clone.any.html [ Failure Timeout ]
 crbug.com/626703 [ Mac ] external/wpt/webxr/xr_viewport_scale.https.html [ Timeout ]
 crbug.com/626703 external/wpt/editing/other/select-all-and-delete-in-html-element-having-contenteditable.html [ Timeout ]
 crbug.com/626703 external/wpt/paint-timing/with-first-paint/first-contentful-image.html [ Timeout ]
@@ -4250,7 +4257,6 @@
 
 # Importing 'fetch' tests from WPT.
 crbug.com/705490 external/wpt/fetch/api/basic/error-after-response.html [ Timeout Pass ]
-crbug.com/820334 external/wpt/fetch/api/request/request-cache-default-conditional.html [ Timeout Pass ]
 
 crbug.com/716320 external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success-and-failure.https.html [ Failure Timeout ]
 
@@ -6215,8 +6221,14 @@
 crbug.com/1140329 http/tests/devtools/network/network-filter-service-worker.js [ Pass Timeout Failure ]
 crbug.com/1140329 virtual/threaded/external/wpt/web-animations/timing-model/animations/updating-the-finished-state.html [ Pass Failure Timeout ]
 
+# DevTools: TypeScriptify elements/StylesSidebarPane.js
+crbug.com/1011811 http/tests/devtools/elements/styles-1/add-new-rule-keyboard.js [ Pass Failure Timeout ]
+
 #Sheriff 2020-10-21
 crbug.com/1141206 scrollbars/overflow-scrollbar-combinations.html [ Pass Failure ]
 
 #Sheriff 2020-10-26
 crbug.com/1142877 external/wpt/mediacapture-fromelement/capture.html [ Pass Failure Crash ]
+
+#Sheriff 2020-10-29
+crbug.com/1143720 [ Win7 ] external/wpt/media-source/mediasource-detach.html [ Pass Failure ]
\ No newline at end of file
diff --git a/third_party/blink/web_tests/android/ChromiumWPTExpectations b/third_party/blink/web_tests/android/ChromiumWPTExpectations
index 7d28c29..13891d9 100644
--- a/third_party/blink/web_tests/android/ChromiumWPTExpectations
+++ b/third_party/blink/web_tests/android/ChromiumWPTExpectations
@@ -1968,20 +1968,11 @@
 crbug.com/1050754 external/wpt/fetch/api/redirect/redirect-origin.any.html [ Timeout ]
 crbug.com/1050754 external/wpt/fetch/api/redirect/redirect-origin.any.worker.html [ Timeout ]
 crbug.com/1050754 external/wpt/fetch/api/request/destination/fetch-destination-worker.https.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/api/request/request-cache-force-cache.html [ Timeout ]
-crbug.com/1050754 external/wpt/fetch/api/request/request-cache-reload.html [ Timeout ]
-crbug.com/1050754 external/wpt/fetch/api/request/request-consume-empty.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/api/request/request-disturbed.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/api/request/request-error.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/api/request/request-init-stream.any.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/api/request/request-init-stream.any.serviceworker.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/api/request/request-init-stream.any.sharedworker.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/api/request/request-init-stream.any.worker.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/api/request/request-reset-attributes.https.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/api/request/request-structure.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/api/response/response-clone.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/api/response/response-consume-empty.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/api/response/response-error-from-stream.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/api/response/response-from-stream.any.sharedworker.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/api/response/response-stream-disturbed-by-pipe.any.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/api/response/response-stream-disturbed-by-pipe.any.worker.html [ Failure ]
@@ -1998,18 +1989,11 @@
 crbug.com/1050754 external/wpt/fetch/cross-origin-resource-policy/scheme-restriction.https.window.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/data-urls/processing.any.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/data-urls/processing.any.worker.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/http-cache/cc-request.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/http-cache/heuristic.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/http-cache/invalidate.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/http-cache/partial.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/http-cache/post-patch.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/http-cache/vary.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/metadata/download.https.sub.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/metadata/form.https.sub.html [ Timeout ]
 crbug.com/1050754 external/wpt/fetch/metadata/portal.https.sub.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/metadata/sharedworker.https.sub.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/metadata/track.https.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/metadata/trailing-dot.https.sub.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/nosniff/parsing-nosniff.window.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/origin/assorted.window.html [ Timeout ]
 crbug.com/1050754 external/wpt/fetch/range/general.window.html [ Failure ]
diff --git a/third_party/blink/web_tests/android/WeblayerWPTExpectations b/third_party/blink/web_tests/android/WeblayerWPTExpectations
index 4bfe84d..9b50ea7e 100644
--- a/third_party/blink/web_tests/android/WeblayerWPTExpectations
+++ b/third_party/blink/web_tests/android/WeblayerWPTExpectations
@@ -1867,20 +1867,11 @@
 crbug.com/1050754 external/wpt/fetch/api/redirect/redirect-origin.any.html [ Timeout ]
 crbug.com/1050754 external/wpt/fetch/api/redirect/redirect-origin.any.worker.html [ Timeout ]
 crbug.com/1050754 external/wpt/fetch/api/request/destination/fetch-destination-worker.https.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/api/request/request-cache-force-cache.html [ Timeout ]
-crbug.com/1050754 external/wpt/fetch/api/request/request-cache-reload.html [ Timeout ]
-crbug.com/1050754 external/wpt/fetch/api/request/request-consume-empty.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/api/request/request-disturbed.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/api/request/request-error.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/api/request/request-init-stream.any.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/api/request/request-init-stream.any.serviceworker.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/api/request/request-init-stream.any.sharedworker.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/api/request/request-init-stream.any.worker.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/api/request/request-reset-attributes.https.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/api/request/request-structure.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/api/response/response-clone.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/api/response/response-consume-empty.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/api/response/response-error-from-stream.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/api/response/response-from-stream.any.sharedworker.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/api/response/response-stream-disturbed-by-pipe.any.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/api/response/response-stream-disturbed-by-pipe.any.worker.html [ Failure ]
@@ -1897,12 +1888,6 @@
 crbug.com/1050754 external/wpt/fetch/cross-origin-resource-policy/scheme-restriction.https.window.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/data-urls/processing.any.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/data-urls/processing.any.worker.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/http-cache/cc-request.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/http-cache/heuristic.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/http-cache/invalidate.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/http-cache/partial.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/http-cache/post-patch.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/http-cache/vary.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/metadata/download.https.sub.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/metadata/favicon.https.sub.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/metadata/form.https.sub.html [ Timeout ]
@@ -1912,7 +1897,6 @@
 crbug.com/1050754 external/wpt/fetch/metadata/redirect/redirect-http-upgrade-prefetch.optional.sub.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/metadata/redirect/redirect-https-downgrade-prefetch.optional.sub.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/metadata/sharedworker.https.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/metadata/trailing-dot.https.sub.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/nosniff/parsing-nosniff.window.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/origin/assorted.window.html [ Timeout ]
 crbug.com/1050754 external/wpt/fetch/range/general.window.html [ Failure ]
diff --git a/third_party/blink/web_tests/android/WebviewWPTExpectations b/third_party/blink/web_tests/android/WebviewWPTExpectations
index f6b4f3a..bf93ed5 100644
--- a/third_party/blink/web_tests/android/WebviewWPTExpectations
+++ b/third_party/blink/web_tests/android/WebviewWPTExpectations
@@ -2017,20 +2017,11 @@
 crbug.com/1050754 external/wpt/fetch/api/redirect/redirect-origin.any.html [ Timeout ]
 crbug.com/1050754 external/wpt/fetch/api/redirect/redirect-origin.any.worker.html [ Timeout ]
 crbug.com/1050754 external/wpt/fetch/api/request/destination/fetch-destination-worker.https.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/api/request/request-cache-force-cache.html [ Timeout ]
-crbug.com/1050754 external/wpt/fetch/api/request/request-cache-reload.html [ Timeout ]
-crbug.com/1050754 external/wpt/fetch/api/request/request-consume-empty.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/api/request/request-disturbed.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/api/request/request-error.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/api/request/request-init-stream.any.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/api/request/request-init-stream.any.serviceworker.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/api/request/request-init-stream.any.sharedworker.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/api/request/request-init-stream.any.worker.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/api/request/request-reset-attributes.https.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/api/request/request-structure.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/api/response/response-clone.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/api/response/response-consume-empty.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/api/response/response-error-from-stream.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/api/response/response-from-stream.any.sharedworker.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/api/response/response-stream-disturbed-by-pipe.any.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/api/response/response-stream-disturbed-by-pipe.any.worker.html [ Failure ]
@@ -2046,18 +2037,11 @@
 crbug.com/1050754 external/wpt/fetch/cross-origin-resource-policy/scheme-restriction.https.window.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/data-urls/processing.any.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/data-urls/processing.any.worker.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/http-cache/cc-request.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/http-cache/heuristic.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/http-cache/invalidate.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/http-cache/partial.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/http-cache/post-patch.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/http-cache/vary.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/metadata/download.https.sub.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/metadata/form.https.sub.html [ Timeout ]
 crbug.com/1050754 external/wpt/fetch/metadata/history.https.sub.html [ Timeout ]
 crbug.com/1050754 external/wpt/fetch/metadata/portal.https.sub.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/metadata/sharedworker.https.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/fetch/metadata/trailing-dot.https.sub.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/metadata/window-open.https.sub.html [ Timeout ]
 crbug.com/1050754 external/wpt/fetch/nosniff/parsing-nosniff.window.html [ Failure ]
 crbug.com/1050754 external/wpt/fetch/origin/assorted.window.html [ Timeout ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index f3d4080..4fc02947 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -208196,6 +208196,10 @@
        []
       ]
      },
+     "is-specificity-shadow-expected.txt": [
+      "077db756104dfe54cde59f029813327af8667520",
+      []
+     ],
      "is-where-pseudo-elements-ref.html": [
       "3a17efedfbbaa0558ab73a16aef42ce626e27b7d",
       []
@@ -214323,6 +214327,14 @@
        "846995459c871a8106ff191959a5842ba497429c",
        []
       ],
+      "request-upload.any.serviceworker-expected.txt": [
+       "846995459c871a8106ff191959a5842ba497429c",
+       []
+      ],
+      "request-upload.any.sharedworker-expected.txt": [
+       "846995459c871a8106ff191959a5842ba497429c",
+       []
+      ],
       "request-upload.any.worker-expected.txt": [
        "846995459c871a8106ff191959a5842ba497429c",
        []
@@ -214333,6 +214345,10 @@
        "1130f249e167d39118bfc9eb330b2690b2fa7cce",
        []
       ],
+      "cors-preflight-redirect.any.sharedworker-expected.txt": [
+       "1130f249e167d39118bfc9eb330b2690b2fa7cce",
+       []
+      ],
       "cors-preflight-redirect.any.worker-expected.txt": [
        "1130f249e167d39118bfc9eb330b2690b2fa7cce",
        []
@@ -214447,6 +214463,14 @@
        "9b61ad26fe81f240de05edbcf3ffad870fa81788",
        []
       ],
+      "redirect-empty-location.any.serviceworker-expected.txt": [
+       "9b61ad26fe81f240de05edbcf3ffad870fa81788",
+       []
+      ],
+      "redirect-empty-location.any.sharedworker-expected.txt": [
+       "9b61ad26fe81f240de05edbcf3ffad870fa81788",
+       []
+      ],
       "redirect-empty-location.any.worker-expected.txt": [
        "9b61ad26fe81f240de05edbcf3ffad870fa81788",
        []
@@ -214455,6 +214479,14 @@
        "2195cb15399ae551cdeecd4d874dfd40468d95ec",
        []
       ],
+      "redirect-location.any.serviceworker-expected.txt": [
+       "2195cb15399ae551cdeecd4d874dfd40468d95ec",
+       []
+      ],
+      "redirect-location.any.sharedworker-expected.txt": [
+       "2195cb15399ae551cdeecd4d874dfd40468d95ec",
+       []
+      ],
       "redirect-location.any.worker-expected.txt": [
        "2195cb15399ae551cdeecd4d874dfd40468d95ec",
        []
@@ -214555,14 +214587,62 @@
        "9c23dfe384cb702447c902896f99568d44c468ba",
        []
       ],
+      "request-consume-empty.any-expected.txt": [
+       "9c23dfe384cb702447c902896f99568d44c468ba",
+       []
+      ],
+      "request-consume-empty.any.serviceworker-expected.txt": [
+       "9c23dfe384cb702447c902896f99568d44c468ba",
+       []
+      ],
+      "request-consume-empty.any.sharedworker-expected.txt": [
+       "9c23dfe384cb702447c902896f99568d44c468ba",
+       []
+      ],
+      "request-consume-empty.any.worker-expected.txt": [
+       "9c23dfe384cb702447c902896f99568d44c468ba",
+       []
+      ],
       "request-disturbed-expected.txt": [
        "d46bdb8c09e8fdcfee2df0b8baf77766c9f1655b",
        []
       ],
+      "request-disturbed.any-expected.txt": [
+       "d46bdb8c09e8fdcfee2df0b8baf77766c9f1655b",
+       []
+      ],
+      "request-disturbed.any.serviceworker-expected.txt": [
+       "d46bdb8c09e8fdcfee2df0b8baf77766c9f1655b",
+       []
+      ],
+      "request-disturbed.any.sharedworker-expected.txt": [
+       "d46bdb8c09e8fdcfee2df0b8baf77766c9f1655b",
+       []
+      ],
+      "request-disturbed.any.worker-expected.txt": [
+       "d46bdb8c09e8fdcfee2df0b8baf77766c9f1655b",
+       []
+      ],
       "request-error-expected.txt": [
        "f3363b8565beda7f4c79e0ad792b657ca8b80372",
        []
       ],
+      "request-error.any-expected.txt": [
+       "f3363b8565beda7f4c79e0ad792b657ca8b80372",
+       []
+      ],
+      "request-error.any.serviceworker-expected.txt": [
+       "f3363b8565beda7f4c79e0ad792b657ca8b80372",
+       []
+      ],
+      "request-error.any.sharedworker-expected.txt": [
+       "f3363b8565beda7f4c79e0ad792b657ca8b80372",
+       []
+      ],
+      "request-error.any.worker-expected.txt": [
+       "f3363b8565beda7f4c79e0ad792b657ca8b80372",
+       []
+      ],
       "request-error.js": [
        "cf77313f5bc3096aa5862c6508a231eea582bd61",
        []
@@ -214575,6 +214655,22 @@
        "fcdfb85ec7bb34c6866aa96509ddccbb85786864",
        []
       ],
+      "request-structure.any-expected.txt": [
+       "fcdfb85ec7bb34c6866aa96509ddccbb85786864",
+       []
+      ],
+      "request-structure.any.serviceworker-expected.txt": [
+       "fcdfb85ec7bb34c6866aa96509ddccbb85786864",
+       []
+      ],
+      "request-structure.any.sharedworker-expected.txt": [
+       "fcdfb85ec7bb34c6866aa96509ddccbb85786864",
+       []
+      ],
+      "request-structure.any.worker-expected.txt": [
+       "fcdfb85ec7bb34c6866aa96509ddccbb85786864",
+       []
+      ],
       "resources": {
        "cache.py": [
         "ca0bd644b4f798c4fa64d1041b628a3740bc0bac",
@@ -214725,18 +214821,74 @@
        "6ff0e7113920bf7e56cc385b1b2a5be8e29804f1",
        []
       ],
+      "response-clone.any-expected.txt": [
+       "6ff0e7113920bf7e56cc385b1b2a5be8e29804f1",
+       []
+      ],
+      "response-clone.any.serviceworker-expected.txt": [
+       "6ff0e7113920bf7e56cc385b1b2a5be8e29804f1",
+       []
+      ],
+      "response-clone.any.sharedworker-expected.txt": [
+       "6ff0e7113920bf7e56cc385b1b2a5be8e29804f1",
+       []
+      ],
+      "response-clone.any.worker-expected.txt": [
+       "6ff0e7113920bf7e56cc385b1b2a5be8e29804f1",
+       []
+      ],
       "response-consume-empty-expected.txt": [
        "5b0426fa4dca632bb0e8992fbae4109c2388f83a",
        []
       ],
+      "response-consume-empty.any-expected.txt": [
+       "5b0426fa4dca632bb0e8992fbae4109c2388f83a",
+       []
+      ],
+      "response-consume-empty.any.serviceworker-expected.txt": [
+       "5b0426fa4dca632bb0e8992fbae4109c2388f83a",
+       []
+      ],
+      "response-consume-empty.any.sharedworker-expected.txt": [
+       "5b0426fa4dca632bb0e8992fbae4109c2388f83a",
+       []
+      ],
+      "response-consume-empty.any.worker-expected.txt": [
+       "5b0426fa4dca632bb0e8992fbae4109c2388f83a",
+       []
+      ],
       "response-error-from-stream-expected.txt": [
        "fd1e6908bfaeab27815e9edc02eaf51624d6320a",
        []
       ],
+      "response-error-from-stream.any-expected.txt": [
+       "fd1e6908bfaeab27815e9edc02eaf51624d6320a",
+       []
+      ],
+      "response-error-from-stream.any.serviceworker-expected.txt": [
+       "fd1e6908bfaeab27815e9edc02eaf51624d6320a",
+       []
+      ],
+      "response-error-from-stream.any.sharedworker-expected.txt": [
+       "fd1e6908bfaeab27815e9edc02eaf51624d6320a",
+       []
+      ],
+      "response-error-from-stream.any.worker-expected.txt": [
+       "fd1e6908bfaeab27815e9edc02eaf51624d6320a",
+       []
+      ],
       "response-stream-disturbed-by-pipe.any-expected.txt": [
        "7ee0f33a4ef947aa168fb4334899a47e94eaff3a",
        []
       ],
+      "response-stream-disturbed-by-pipe.any.serviceworker-expected.txt": [
+       "7ee0f33a4ef947aa168fb4334899a47e94eaff3a",
+       []
+      ],
+      "response-stream-disturbed-by-pipe.any.sharedworker-expected.txt": [
+       "7ee0f33a4ef947aa168fb4334899a47e94eaff3a",
+       []
+      ],
       "response-stream-disturbed-by-pipe.any.worker-expected.txt": [
        "7ee0f33a4ef947aa168fb4334899a47e94eaff3a",
        []
@@ -214978,6 +215130,14 @@
       "cfab79c6b3c7ecfefeba9e4541a3a5d81a8e2723",
       []
      ],
+     "processing.any.serviceworker-expected.txt": [
+      "cfab79c6b3c7ecfefeba9e4541a3a5d81a8e2723",
+      []
+     ],
+     "processing.any.sharedworker-expected.txt": [
+      "cfab79c6b3c7ecfefeba9e4541a3a5d81a8e2723",
+      []
+     ],
      "processing.any.worker-expected.txt": [
       "cfab79c6b3c7ecfefeba9e4541a3a5d81a8e2723",
       []
@@ -215026,14 +215186,62 @@
       "bee27041d4637ef2ed19aeff4ce0f514c1fd19b5",
       []
      ],
+     "cache-mode.any-expected.txt": [
+      "bee27041d4637ef2ed19aeff4ce0f514c1fd19b5",
+      []
+     ],
+     "cache-mode.any.serviceworker-expected.txt": [
+      "bee27041d4637ef2ed19aeff4ce0f514c1fd19b5",
+      []
+     ],
+     "cache-mode.any.sharedworker-expected.txt": [
+      "bee27041d4637ef2ed19aeff4ce0f514c1fd19b5",
+      []
+     ],
+     "cache-mode.any.worker-expected.txt": [
+      "bee27041d4637ef2ed19aeff4ce0f514c1fd19b5",
+      []
+     ],
      "cc-request-expected.txt": [
       "10e574ea6c106f29cb5ce22d5ce08417c5a0e6cc",
       []
      ],
+     "cc-request.any-expected.txt": [
+      "10e574ea6c106f29cb5ce22d5ce08417c5a0e6cc",
+      []
+     ],
+     "cc-request.any.serviceworker-expected.txt": [
+      "10e574ea6c106f29cb5ce22d5ce08417c5a0e6cc",
+      []
+     ],
+     "cc-request.any.sharedworker-expected.txt": [
+      "10e574ea6c106f29cb5ce22d5ce08417c5a0e6cc",
+      []
+     ],
+     "cc-request.any.worker-expected.txt": [
+      "10e574ea6c106f29cb5ce22d5ce08417c5a0e6cc",
+      []
+     ],
      "heuristic-expected.txt": [
       "e31950283c1246188ef891cabfd4e80b5044e354",
       []
      ],
+     "heuristic.any-expected.txt": [
+      "e31950283c1246188ef891cabfd4e80b5044e354",
+      []
+     ],
+     "heuristic.any.serviceworker-expected.txt": [
+      "e31950283c1246188ef891cabfd4e80b5044e354",
+      []
+     ],
+     "heuristic.any.sharedworker-expected.txt": [
+      "e31950283c1246188ef891cabfd4e80b5044e354",
+      []
+     ],
+     "heuristic.any.worker-expected.txt": [
+      "e31950283c1246188ef891cabfd4e80b5044e354",
+      []
+     ],
      "http-cache.js": [
       "c0d682d2cba654414d0146386e8f02f4a375177b",
       []
@@ -215042,14 +215250,62 @@
       "9f29bc55f9b0857a93440eebf80fa7000459c069",
       []
      ],
+     "invalidate.any-expected.txt": [
+      "9f29bc55f9b0857a93440eebf80fa7000459c069",
+      []
+     ],
+     "invalidate.any.serviceworker-expected.txt": [
+      "9f29bc55f9b0857a93440eebf80fa7000459c069",
+      []
+     ],
+     "invalidate.any.sharedworker-expected.txt": [
+      "9f29bc55f9b0857a93440eebf80fa7000459c069",
+      []
+     ],
+     "invalidate.any.worker-expected.txt": [
+      "9f29bc55f9b0857a93440eebf80fa7000459c069",
+      []
+     ],
      "partial-expected.txt": [
       "759cb5d39fb19ace224984b994579fcf812ba487",
       []
      ],
+     "partial.any-expected.txt": [
+      "759cb5d39fb19ace224984b994579fcf812ba487",
+      []
+     ],
+     "partial.any.serviceworker-expected.txt": [
+      "759cb5d39fb19ace224984b994579fcf812ba487",
+      []
+     ],
+     "partial.any.sharedworker-expected.txt": [
+      "759cb5d39fb19ace224984b994579fcf812ba487",
+      []
+     ],
+     "partial.any.worker-expected.txt": [
+      "759cb5d39fb19ace224984b994579fcf812ba487",
+      []
+     ],
      "post-patch-expected.txt": [
       "3a5cd58915539e5a42fbdd03f474da40f2b268c5",
       []
      ],
+     "post-patch.any-expected.txt": [
+      "3a5cd58915539e5a42fbdd03f474da40f2b268c5",
+      []
+     ],
+     "post-patch.any.serviceworker-expected.txt": [
+      "3a5cd58915539e5a42fbdd03f474da40f2b268c5",
+      []
+     ],
+     "post-patch.any.sharedworker-expected.txt": [
+      "3a5cd58915539e5a42fbdd03f474da40f2b268c5",
+      []
+     ],
+     "post-patch.any.worker-expected.txt": [
+      "3a5cd58915539e5a42fbdd03f474da40f2b268c5",
+      []
+     ],
      "resources": {
       "http-cache.py": [
        "c176b255a3f256738d514e37905ed77373986b30",
@@ -215071,6 +215327,22 @@
      "vary-expected.txt": [
       "5cfb7f71a1517441a64c250c8acca1bfa4049288",
       []
+     ],
+     "vary.any-expected.txt": [
+      "5cfb7f71a1517441a64c250c8acca1bfa4049288",
+      []
+     ],
+     "vary.any.serviceworker-expected.txt": [
+      "5cfb7f71a1517441a64c250c8acca1bfa4049288",
+      []
+     ],
+     "vary.any.sharedworker-expected.txt": [
+      "5cfb7f71a1517441a64c250c8acca1bfa4049288",
+      []
+     ],
+     "vary.any.worker-expected.txt": [
+      "5cfb7f71a1517441a64c250c8acca1bfa4049288",
+      []
      ]
     },
     "metadata": {
@@ -229716,14 +229988,6 @@
         "422c227ea95706b5eaa67c8784b0ce8ac4fca8e1",
         []
        ],
-       "compile-error-cross-origin-setInterval-expected.txt": [
-        "fa2584fd4c0679fb018c60732693e252fe9585cc",
-        []
-       ],
-       "compile-error-cross-origin-setTimeout-expected.txt": [
-        "bfa9c01cfc95944357e860e88720c21dda4fa9d2",
-        []
-       ],
        "compile-error-same-origin-with-hash-expected.txt": [
         "e6b4ffea5e691a3f0d6491ea4b34986e8deb489d",
         []
@@ -229798,25 +230062,17 @@
          ]
         }
        },
-       "runtime-error-cross-origin-setInterval-expected.txt": [
-        "1a692ddaa46bfb4397e75c7b0541e8e0e9498eac",
-        []
-       ],
-       "runtime-error-cross-origin-setTimeout-expected.txt": [
-        "2067df88b2c494edeb6f1759175058d9e7bf2ce3",
-        []
-       ],
        "runtime-error-same-origin-with-hash-expected.txt": [
         "98814ab16bb6a425e3712f2cf50f18a728511e7a",
         []
        ],
        "support": {
         "syntax-error-in-setInterval.js": [
-         "3b42fd9bc92e64873dadd1dc15ddd1492320378c",
+         "afec114458b37a31f28bc6833a93dfb604ed2f84",
          []
         ],
         "syntax-error-in-setTimeout.js": [
-         "84eb4fc419925d70470cd5fb90befb97e4fcd4fe",
+         "427542b42ec39d555599894e175393b4f157918d",
          []
         ],
         "syntax-error.js": [
@@ -229824,11 +230080,11 @@
          []
         ],
         "undefined-variable-in-setInterval.js": [
-         "4aa7da8256c655694fc9db1a29025bcb7658697f",
+         "c2a017a2abfbe4bac9720139f83ae0775c2e9ecc",
          []
         ],
         "undefined-variable-in-setTimeout.js": [
-         "6350ab62ebf335ce7ce539b4e7065ef2ccd9f9ee",
+         "6fa54cda9fb847dce7d9cc5bd5078d07f0f3f25a",
          []
         ],
         "undefined-variable.js": [
@@ -257394,6 +257650,10 @@
       "c592943b795596c4ebbd06c6ddfc79ed0fad2ec0",
       []
      ],
+     "get-set-cookie.py": [
+      "cdba642fca96f93a8d9d33a909682b4a1d2a7f04",
+      []
+     ],
      "gzip.py": [
       "17f142c4405f8e121a2468ffc380a9d56ef0822e",
       []
@@ -274802,7 +275062,7 @@
     ],
     "detached-iframe": {
      "clipboard-on-detached-iframe.https.html": [
-      "84fce80323624af9d1f431e85bc90e9d620174b0",
+      "5eb58e3213e33a0cf7150acbfaac8125bd0f61e5",
       [
        null,
        {}
@@ -307599,6 +307859,13 @@
        {}
       ]
      ],
+     "is-specificity-shadow.html": [
+      "af039955eb7c4fa1dff8bfa425775184a911a671",
+      [
+       null,
+       {}
+      ]
+     ],
      "is-specificity.html": [
       "541b0406d347e5ade0474024ba208ba222dc2d29",
       [
@@ -326423,11 +326690,67 @@
    "fetch": {
     "api": {
      "abort": {
-      "cache.https.html": [
-       "25ed0e1e9183b9a73884944352dd52780fda0091",
+      "cache.https.any.js": [
+       "bdaf0e69e5801040a18cb9d479b8fc3cc4a229d8",
        [
-        null,
-        {}
+        "fetch/api/abort/cache.https.any.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Request signals &amp; the cache API"
+          ],
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/abort/cache.https.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Request signals &amp; the cache API"
+          ],
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/abort/cache.https.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Request signals &amp; the cache API"
+          ],
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/abort/cache.https.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Request signals &amp; the cache API"
+          ],
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
        ]
       ],
       "destroyed-context.html": [
@@ -326569,12 +326892,46 @@
      },
      "basic": {
       "accept-header.any.js": [
-       "3d886dfad5a25ae16506e6eca23d845e3a997007",
+       "cd54cf2a03e8a926042356ef9d032b73c5d1a548",
        [
         "fetch/api/basic/accept-header.any.html",
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/accept-header.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/accept-header.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -326586,6 +326943,10 @@
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -326600,18 +326961,180 @@
         {}
        ]
       ],
-      "conditional-get.html": [
-       "b80e929fe6bb59de67967fdda1518fcd8a55ef14",
+      "conditional-get.any.js": [
+       "2f9fa81c02b18b8d4c736caf022fab860d4488c6",
        [
-        null,
-        {}
+        "fetch/api/basic/conditional-get.any.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Request ETag"
+          ],
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/conditional-get.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Request ETag"
+          ],
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/conditional-get.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Request ETag"
+          ],
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/conditional-get.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Request ETag"
+          ],
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ]
+         ]
+        }
        ]
       ],
-      "error-after-response.html": [
-       "8db3429324af16969d076c1c4db03b8b68496bf6",
+      "error-after-response.any.js": [
+       "f7114425f95504c1e7688421f17f74bc8326b9db",
        [
-        null,
+        "fetch/api/basic/error-after-response.any.html",
         {
+         "script_metadata": [
+          [
+           "title",
+           "Fetch: network timeout after receiving the HTTP response headers"
+          ],
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "timeout",
+           "long"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ],
+         "timeout": "long"
+        }
+       ],
+       [
+        "fetch/api/basic/error-after-response.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Fetch: network timeout after receiving the HTTP response headers"
+          ],
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "timeout",
+           "long"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ],
+         "timeout": "long"
+        }
+       ],
+       [
+        "fetch/api/basic/error-after-response.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Fetch: network timeout after receiving the HTTP response headers"
+          ],
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "timeout",
+           "long"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ],
+         "timeout": "long"
+        }
+       ],
+       [
+        "fetch/api/basic/error-after-response.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Fetch: network timeout after receiving the HTTP response headers"
+          ],
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "timeout",
+           "long"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ],
          "timeout": "long"
         }
        ]
@@ -326711,14 +327234,50 @@
        ]
       ],
       "historical.any.js": [
-       "aea4184ac8bca0c820cbf2d822cc38125f512e9a",
+       "c8081262168e36716a2f73e35681542c42ca7733",
        [
         "fetch/api/basic/historical.any.html",
-        {}
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/historical.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/historical.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
        ],
        [
         "fetch/api/basic/historical.any.worker.html",
-        {}
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
        ]
       ],
       "integrity.sub.any.js": [
@@ -326875,12 +327434,46 @@
        ]
       ],
       "request-forbidden-headers.any.js": [
-       "fedabed5418bea81e9ff19c3c325d542b99faf31",
+       "5d85c4e62d32b0e1dff0265967693fde688694b2",
        [
         "fetch/api/basic/request-forbidden-headers.any.html",
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/request-forbidden-headers.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/request-forbidden-headers.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -326892,6 +327485,10 @@
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -326900,45 +327497,187 @@
        ]
       ],
       "request-head.any.js": [
-       "dc435bf0d6df943bc02406ea46ec0cce4134c4d9",
+       "e0b6afa079a4000cc97dd702a531f69c568eafcc",
        [
         "fetch/api/basic/request-head.any.html",
-        {}
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/request-head.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/request-head.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
        ],
        [
         "fetch/api/basic/request-head.any.worker.html",
-        {}
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
        ]
       ],
       "request-headers-case.any.js": [
-       "067eabb13329b1caab7f5159b29bbe8a66e0ff85",
+       "4c10e717f8c2e594d0e1f612ce0a19191ac5fc85",
        [
         "fetch/api/basic/request-headers-case.any.html",
-        {}
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/request-headers-case.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/request-headers-case.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
        ],
        [
         "fetch/api/basic/request-headers-case.any.worker.html",
-        {}
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
        ]
       ],
       "request-headers-nonascii.any.js": [
-       "0d822fb24f3e0c091acc3792339c975c9a129e53",
+       "4a9a8011385351473f31936b4a5a81fee58ec250",
        [
         "fetch/api/basic/request-headers-nonascii.any.html",
-        {}
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/request-headers-nonascii.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/request-headers-nonascii.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
        ],
        [
         "fetch/api/basic/request-headers-nonascii.any.worker.html",
-        {}
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
        ]
       ],
       "request-headers.any.js": [
-       "4ba70f7c496b7c406e5ed1aef35ba5efb3dc46ef",
+       "ac54256e4c6a6377414d3a24dbe1fe34c8bb664d",
        [
         "fetch/api/basic/request-headers.any.html",
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/request-headers.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/request-headers.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -326950,6 +327689,10 @@
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -326965,12 +327708,46 @@
        ]
       ],
       "request-referrer.any.js": [
-       "62fbd43e1dd42d9ba320536eb9921f6c6ee04004",
+       "0c3357642d674b7327966f840fab27550883b7da",
        [
         "fetch/api/basic/request-referrer.any.html",
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/request-referrer.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/request-referrer.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -326982,6 +327759,10 @@
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -326990,12 +327771,46 @@
        ]
       ],
       "request-upload.any.js": [
-       "14f4a07a4987e424ee42a23ac0218acc77a42b76",
+       "1412816a3c220d60ca1b3c525ac5953d10157c3c",
        [
         "fetch/api/basic/request-upload.any.html",
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/request-upload.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/request-upload.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -327007,6 +327822,10 @@
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -327026,12 +327845,46 @@
        ]
       ],
       "scheme-about.any.js": [
-       "eb892d32fff9f3bf693853d2df15f179d4294cb5",
+       "4329bd070320ddf8e475de2b97a8859f201cebbd",
        [
         "fetch/api/basic/scheme-about.any.html",
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/scheme-about.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/scheme-about.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -327043,6 +327896,10 @@
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -327076,12 +327933,46 @@
        ]
       ],
       "scheme-data.any.js": [
-       "e4a880719d3410a77b686e7e1943cbaf55d4372b",
+       "1c3b5dc816c88b28ed2fd05607a2492ba8b6f5a6",
        [
         "fetch/api/basic/scheme-data.any.html",
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/scheme-data.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/scheme-data.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -327093,6 +327984,10 @@
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -327101,12 +327996,46 @@
        ]
       ],
       "scheme-others.sub.any.js": [
-       "9c3cad17028524a2d2d65e3b4fde79d0662b037c",
+       "550f69c41b5a43aa5ca1996703375fa1ea6fbc89",
        [
         "fetch/api/basic/scheme-others.sub.any.html",
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/scheme-others.sub.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/scheme-others.sub.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -327118,6 +328047,10 @@
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -327126,12 +328059,46 @@
        ]
       ],
       "stream-response.any.js": [
-       "5b11018eb31648f5503eba1b1e71a616e219b375",
+       "4a8855a62d7b0d5b53e9f2495f209170114ad4b6",
        [
         "fetch/api/basic/stream-response.any.html",
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/stream-response.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/stream-response.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -327143,6 +328110,10 @@
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -327197,11 +328168,83 @@
         }
        ]
       ],
-      "text-utf8.html": [
-       "e5c567b9c4531113c12a3c56d0f5d9c1517589a2",
+      "text-utf8.any.js": [
+       "05c8c88825d37bfafe63d757d33a9a35284e22f9",
        [
-        null,
-        {}
+        "fetch/api/basic/text-utf8.any.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Fetch: Request and Response text() should decode as UTF-8"
+          ],
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/text-utf8.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Fetch: Request and Response text() should decode as UTF-8"
+          ],
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/text-utf8.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Fetch: Request and Response text() should decode as UTF-8"
+          ],
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/basic/text-utf8.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Fetch: Request and Response text() should decode as UTF-8"
+          ],
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
        ]
       ]
      },
@@ -327364,12 +328407,46 @@
        ]
       ],
       "cors-multiple-origins.sub.any.js": [
-       "b1034eb7274a307d7f14e09d650277a38b329214",
+       "b3abb922841c63e5ccbb633d60d29f767f0586ad",
        [
         "fetch/api/cors/cors-multiple-origins.sub.any.html",
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/cors/cors-multiple-origins.sub.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/cors/cors-multiple-origins.sub.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -327381,6 +328458,10 @@
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -327561,12 +328642,62 @@
        ]
       ],
       "cors-preflight-redirect.any.js": [
-       "7ed54319b4e90c98ff0328ee7b3e61f8551e9a5f",
+       "15f7659abd21569b79c7b44c469c27274339a61c",
        [
         "fetch/api/cors/cors-preflight-redirect.any.html",
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/cors/cors-preflight-redirect.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/cors/cors-preflight-redirect.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "/common/utils.js"
           ],
@@ -327586,6 +328717,10 @@
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "/common/utils.js"
           ],
@@ -327972,12 +329107,46 @@
      },
      "credentials": {
       "authentication-basic.any.js": [
-       "4969b3042e8dcde56b0adb708fb2c5f64d18a9eb",
+       "babc5d003b108e6d2499e0e0ed0cc27f4130af18",
        [
         "fetch/api/credentials/authentication-basic.any.html",
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/credentials/authentication-basic.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/credentials/authentication-basic.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -327989,6 +329158,10 @@
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -327997,12 +329170,46 @@
        ]
       ],
       "cookies.any.js": [
-       "b65a866c09bce38fc8dfff20216ef9780c00e817",
+       "de30e477655c2851873e75a34019f30644679ac1",
        [
         "fetch/api/credentials/cookies.any.html",
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/credentials/cookies.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/credentials/cookies.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -328014,6 +329221,10 @@
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -328023,78 +329234,642 @@
       ]
      },
      "headers": {
-      "header-values-normalize.html": [
-       "d2da32332e0468ac3993cfe9f0b754bbe9a8930b",
+      "header-values-normalize.any.js": [
+       "814789c5b0b578d5f3674b165cf68d6fbad63668",
        [
-        null,
+        "fetch/api/headers/header-values-normalize.any.html",
         {
+         "script_metadata": [
+          [
+           "title",
+           "Header value normalizing test"
+          ],
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "timeout",
+           "long"
+          ]
+         ],
+         "timeout": "long"
+        }
+       ],
+       [
+        "fetch/api/headers/header-values-normalize.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Header value normalizing test"
+          ],
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "timeout",
+           "long"
+          ]
+         ],
+         "timeout": "long"
+        }
+       ],
+       [
+        "fetch/api/headers/header-values-normalize.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Header value normalizing test"
+          ],
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "timeout",
+           "long"
+          ]
+         ],
+         "timeout": "long"
+        }
+       ],
+       [
+        "fetch/api/headers/header-values-normalize.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Header value normalizing test"
+          ],
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "timeout",
+           "long"
+          ]
+         ],
          "timeout": "long"
         }
        ]
       ],
-      "header-values.html": [
-       "a68bfa91bf5d81d95141ee170f856f9defd8994a",
+      "header-values.any.js": [
+       "9a829d8d4ed6218b8c3ebde03caf7ae732111c12",
        [
-        null,
+        "fetch/api/headers/header-values.any.html",
         {
+         "script_metadata": [
+          [
+           "title",
+           "Header value test"
+          ],
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "timeout",
+           "long"
+          ]
+         ],
+         "timeout": "long"
+        }
+       ],
+       [
+        "fetch/api/headers/header-values.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Header value test"
+          ],
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "timeout",
+           "long"
+          ]
+         ],
+         "timeout": "long"
+        }
+       ],
+       [
+        "fetch/api/headers/header-values.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Header value test"
+          ],
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "timeout",
+           "long"
+          ]
+         ],
+         "timeout": "long"
+        }
+       ],
+       [
+        "fetch/api/headers/header-values.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Header value test"
+          ],
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "timeout",
+           "long"
+          ]
+         ],
          "timeout": "long"
         }
        ]
       ],
-      "headers-basic.html": [
-       "254ef051c1227cc676dafbc9f1a3d91c98a89b01",
+      "headers-basic.any.js": [
+       "5de71f43bb4fc37d38006626fc6c6276cd7dbd5b",
        [
-        null,
-        {}
+        "fetch/api/headers/headers-basic.any.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Headers structure"
+          ],
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/headers/headers-basic.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Headers structure"
+          ],
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/headers/headers-basic.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Headers structure"
+          ],
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/headers/headers-basic.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Headers structure"
+          ],
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
        ]
       ],
-      "headers-casing.html": [
-       "1e505d81cda8c19f7cbb16436ea08fb3f92c6f48",
+      "headers-casing.any.js": [
+       "57bec0164ed9abb109a0835c5a6ecb52ebdf8556",
        [
-        null,
-        {}
+        "fetch/api/headers/headers-casing.any.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Headers case management"
+          ],
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/headers/headers-casing.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Headers case management"
+          ],
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/headers/headers-casing.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Headers case management"
+          ],
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/headers/headers-casing.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Headers case management"
+          ],
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
        ]
       ],
-      "headers-combine.html": [
-       "7341b77e86b7ed7befa0398d3f68f51624dc1bce",
+      "headers-combine.any.js": [
+       "dab47889c45ef3cdb82f131a9c7d7cc4d2ed38fb",
        [
-        null,
-        {}
+        "fetch/api/headers/headers-combine.any.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Headers have combined (and sorted) values"
+          ],
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/headers/headers-combine.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Headers have combined (and sorted) values"
+          ],
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/headers/headers-combine.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Headers have combined (and sorted) values"
+          ],
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/headers/headers-combine.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Headers have combined (and sorted) values"
+          ],
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
        ]
       ],
-      "headers-errors.html": [
-       "7f9916d87fe2ac125953eb25f0e278aa31073b3e",
+      "headers-errors.any.js": [
+       "ab8a118e255f3ad2d57b6d57ae4a5f263461b711",
        [
-        null,
-        {}
+        "fetch/api/headers/headers-errors.any.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Headers errors"
+          ],
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/headers/headers-errors.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Headers errors"
+          ],
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/headers/headers-errors.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Headers errors"
+          ],
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/headers/headers-errors.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Headers errors"
+          ],
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
        ]
       ],
-      "headers-no-cors.window.js": [
-       "2f3a819ba1a6d1cb7418b0507e6f8130458ba988",
+      "headers-no-cors.any.js": [
+       "c09658e641ecdf143778df3b02b5ca549c5b4c19",
        [
-        "fetch/api/headers/headers-no-cors.window.html",
-        {}
+        "fetch/api/headers/headers-no-cors.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/headers/headers-no-cors.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/headers/headers-no-cors.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/headers/headers-no-cors.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
        ]
       ],
-      "headers-normalize.html": [
-       "6dfcf9d8194776479d500a6f6c6a5851424d9efc",
+      "headers-normalize.any.js": [
+       "5ebd7ae9ea9898917fe3d7a1660475f024c51d11",
        [
-        null,
-        {}
+        "fetch/api/headers/headers-normalize.any.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Headers normalize values"
+          ],
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/headers/headers-normalize.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Headers normalize values"
+          ],
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/headers/headers-normalize.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Headers normalize values"
+          ],
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/headers/headers-normalize.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Headers normalize values"
+          ],
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
        ]
       ],
-      "headers-record.html": [
-       "c7d8d99a7095ebb6b5d3e3154ac69108e819698f",
+      "headers-record.any.js": [
+       "55036c2da4c076884debd673fdea23abb7a9a2bd",
        [
-        null,
-        {}
+        "fetch/api/headers/headers-record.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/headers/headers-record.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/headers/headers-record.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/headers/headers-record.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
        ]
       ],
-      "headers-structure.html": [
-       "9448e450c9b80e53fff7c5372847a95ecb553f27",
+      "headers-structure.any.js": [
+       "c47290eb2098b37a67e2b189b310166ba1a6a828",
        [
-        null,
-        {}
+        "fetch/api/headers/headers-structure.any.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Headers basic"
+          ],
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/headers/headers-structure.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Headers basic"
+          ],
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/headers/headers-structure.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Headers basic"
+          ],
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/headers/headers-structure.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Headers basic"
+          ],
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
        ]
       ]
      },
@@ -328299,12 +330074,46 @@
      },
      "redirect": {
       "redirect-back-to-original-origin.any.js": [
-       "32d413cb2f16db6753bd71cfa0395ff8bd7efea9",
+       "74d731f24251c16b204c50e9fa81527eeecc88cb",
        [
         "fetch/api/redirect/redirect-back-to-original-origin.any.html",
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/redirect/redirect-back-to-original-origin.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/redirect/redirect-back-to-original-origin.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "/common/get-host-info.sub.js"
           ]
@@ -328316,6 +330125,10 @@
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "/common/get-host-info.sub.js"
           ]
@@ -328324,12 +330137,64 @@
        ]
       ],
       "redirect-count.any.js": [
-       "4ce080e69027bc12f180dc93d00f0e7c9683022c",
+       "dda5d7f52901ae4f736e8defbd76963bdeb86259",
        [
         "fetch/api/redirect/redirect-count.any.html",
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "timeout",
+           "long"
+          ]
+         ],
+         "timeout": "long"
+        }
+       ],
+       [
+        "fetch/api/redirect/redirect-count.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "timeout",
+           "long"
+          ]
+         ],
+         "timeout": "long"
+        }
+       ],
+       [
+        "fetch/api/redirect/redirect-count.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ],
@@ -328350,6 +330215,10 @@
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ],
@@ -328367,12 +330236,46 @@
        ]
       ],
       "redirect-empty-location.any.js": [
-       "79b04f5c5ec271f1fd3b17378ccc970ca1c3fab3",
+       "487f4d42e9239f1319bff6a8cbc46bb11231be60",
        [
         "fetch/api/redirect/redirect-empty-location.any.html",
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/redirect/redirect-empty-location.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/redirect/redirect-empty-location.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -328384,6 +330287,10 @@
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -328392,12 +330299,46 @@
        ]
       ],
       "redirect-location-escape.tentative.any.js": [
-       "2975e5fe1a9758e45d4abf7feeceb0b2b58e257d",
+       "779ad7057937f63c02c7adc89f39b890c68d4896",
        [
         "fetch/api/redirect/redirect-location-escape.tentative.any.html",
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/redirect/redirect-location-escape.tentative.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/redirect/redirect-location-escape.tentative.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -328409,6 +330350,10 @@
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -328417,12 +330362,46 @@
        ]
       ],
       "redirect-location.any.js": [
-       "91da26021d09a0254b7e571b9ee112fe1080d60f",
+       "5cb6cc280c4cd5fddb62fd8ba29d942894460d4e",
        [
         "fetch/api/redirect/redirect-location.any.html",
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/redirect/redirect-location.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/redirect/redirect-location.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -328434,6 +330413,10 @@
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -328442,12 +330425,46 @@
        ]
       ],
       "redirect-method.any.js": [
-       "b24bb092c603a2f2c6942a9c6b3ab5936a7e1687",
+       "9fe086a9db718a5de8756e4b8a3830ae411871e0",
        [
         "fetch/api/redirect/redirect-method.any.html",
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/redirect/redirect-method.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/redirect/redirect-method.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -328459,6 +330476,10 @@
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -328583,20 +330604,126 @@
         }
        ]
       ],
-      "redirect-schemes.html": [
-       "2aa7bcea6955882fad34f529fc2544c24c560f3e",
+      "redirect-schemes.any.js": [
+       "31ec124fd6a3eda60b1641fb3cba983cf2317fce",
        [
-        null,
-        {}
+        "fetch/api/redirect/redirect-schemes.any.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Fetch: handling different schemes in redirects"
+          ],
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/redirect/redirect-schemes.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Fetch: handling different schemes in redirects"
+          ],
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/redirect/redirect-schemes.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Fetch: handling different schemes in redirects"
+          ],
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/redirect/redirect-schemes.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "title",
+           "Fetch: handling different schemes in redirects"
+          ],
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ]
+         ]
+        }
        ]
       ],
       "redirect-to-dataurl.any.js": [
-       "2f36f0b9d21b223c4f20e9ae2cc1620fb08212f3",
+       "9d0f147349c48870aae00c8c2be4aa3e376d36b1",
        [
         "fetch/api/redirect/redirect-to-dataurl.any.html",
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/redirect/redirect-to-dataurl.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/redirect/redirect-to-dataurl.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "/common/get-host-info.sub.js"
           ]
@@ -328608,6 +330735,10 @@
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "/common/get-host-info.sub.js"
           ]
@@ -328670,62 +330801,821 @@
         ]
        ]
       },
-      "request-bad-port.html": [
-       "d1d42cc217d036d63dc706cf729208e7d93897ba",
+      "request-bad-port.any.js": [
+       "8614192f84ea2c2d1fd995809c040c73f3eada81",
        [
-        null,
-        {}
+        "fetch/api/request/request-bad-port.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-bad-port.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-bad-port.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-bad-port.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
        ]
       ],
-      "request-cache-default-conditional.html": [
-       "145b30262daba00e3318d78b9c3617a8bd94f3bc",
+      "request-cache-default-conditional.any.js": [
+       "c5b2001cc8f6b02372f4c1f1306ab77d83654172",
        [
-        null,
+        "fetch/api/request/request-cache-default-conditional.any.html",
         {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request cache - default with conditional requests"
+          ],
+          [
+           "timeout",
+           "long"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ],
+          [
+           "script",
+           "request-cache.js"
+          ]
+         ],
+         "timeout": "long"
+        }
+       ],
+       [
+        "fetch/api/request/request-cache-default-conditional.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request cache - default with conditional requests"
+          ],
+          [
+           "timeout",
+           "long"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ],
+          [
+           "script",
+           "request-cache.js"
+          ]
+         ],
+         "timeout": "long"
+        }
+       ],
+       [
+        "fetch/api/request/request-cache-default-conditional.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request cache - default with conditional requests"
+          ],
+          [
+           "timeout",
+           "long"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ],
+          [
+           "script",
+           "request-cache.js"
+          ]
+         ],
+         "timeout": "long"
+        }
+       ],
+       [
+        "fetch/api/request/request-cache-default-conditional.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request cache - default with conditional requests"
+          ],
+          [
+           "timeout",
+           "long"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ],
+          [
+           "script",
+           "request-cache.js"
+          ]
+         ],
          "timeout": "long"
         }
        ]
       ],
-      "request-cache-default.html": [
-       "c0e37b2d0c9b6382dfc72b1c6b90197b3e5e015d",
+      "request-cache-default.any.js": [
+       "dfa8369c9a37198ceec333e7d3f1748daa815058",
        [
-        null,
-        {}
+        "fetch/api/request/request-cache-default.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request cache - default"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ],
+          [
+           "script",
+           "request-cache.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-cache-default.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request cache - default"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ],
+          [
+           "script",
+           "request-cache.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-cache-default.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request cache - default"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ],
+          [
+           "script",
+           "request-cache.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-cache-default.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request cache - default"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ],
+          [
+           "script",
+           "request-cache.js"
+          ]
+         ]
+        }
        ]
       ],
-      "request-cache-force-cache.html": [
-       "ed45726f55e652306b7826129f4bcee98403e334",
+      "request-cache-force-cache.any.js": [
+       "00dce096c7292495606d8606c8649e096bcac81d",
        [
-        null,
-        {}
+        "fetch/api/request/request-cache-force-cache.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request cache - force-cache"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ],
+          [
+           "script",
+           "request-cache.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-cache-force-cache.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request cache - force-cache"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ],
+          [
+           "script",
+           "request-cache.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-cache-force-cache.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request cache - force-cache"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ],
+          [
+           "script",
+           "request-cache.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-cache-force-cache.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request cache - force-cache"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ],
+          [
+           "script",
+           "request-cache.js"
+          ]
+         ]
+        }
        ]
       ],
-      "request-cache-no-cache.html": [
-       "d30ed16269686ae7163853a795d529fb4d869b41",
+      "request-cache-no-cache.any.js": [
+       "41fc22baf23ddd3f832a38c853a203920a38062a",
        [
-        null,
-        {}
+        "fetch/api/request/request-cache-no-cache.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request cache : no-cache"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ],
+          [
+           "script",
+           "request-cache.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-cache-no-cache.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request cache : no-cache"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ],
+          [
+           "script",
+           "request-cache.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-cache-no-cache.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request cache : no-cache"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ],
+          [
+           "script",
+           "request-cache.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-cache-no-cache.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request cache : no-cache"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ],
+          [
+           "script",
+           "request-cache.js"
+          ]
+         ]
+        }
        ]
       ],
-      "request-cache-no-store.html": [
-       "396b6a650905def403a062a237fc760ddcda70aa",
+      "request-cache-no-store.any.js": [
+       "9a28718bf2292df5c0f9b7290dfe274ef0e015d8",
        [
-        null,
-        {}
+        "fetch/api/request/request-cache-no-store.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request cache - no store"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ],
+          [
+           "script",
+           "request-cache.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-cache-no-store.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request cache - no store"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ],
+          [
+           "script",
+           "request-cache.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-cache-no-store.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request cache - no store"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ],
+          [
+           "script",
+           "request-cache.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-cache-no-store.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request cache - no store"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ],
+          [
+           "script",
+           "request-cache.js"
+          ]
+         ]
+        }
        ]
       ],
-      "request-cache-only-if-cached.html": [
-       "adb31a397a759c43f918c0f88a7f2067bfac33a8",
+      "request-cache-only-if-cached.any.js": [
+       "1305787c7c1d6641ed9eb11bf0151ca391877a1b",
        [
-        null,
-        {}
+        "fetch/api/request/request-cache-only-if-cached.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,dedicatedworker,sharedworker"
+          ],
+          [
+           "title",
+           "Request cache - only-if-cached"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ],
+          [
+           "script",
+           "request-cache.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-cache-only-if-cached.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,dedicatedworker,sharedworker"
+          ],
+          [
+           "title",
+           "Request cache - only-if-cached"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ],
+          [
+           "script",
+           "request-cache.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-cache-only-if-cached.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,dedicatedworker,sharedworker"
+          ],
+          [
+           "title",
+           "Request cache - only-if-cached"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ],
+          [
+           "script",
+           "request-cache.js"
+          ]
+         ]
+        }
        ]
       ],
-      "request-cache-reload.html": [
-       "45ff5832482dd971b4062100414d0b2187e478e0",
+      "request-cache-reload.any.js": [
+       "c7bfffb398890d478d0a9955a642a665bc18df31",
        [
-        null,
-        {}
+        "fetch/api/request/request-cache-reload.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request cache - reload"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ],
+          [
+           "script",
+           "request-cache.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-cache-reload.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request cache - reload"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ],
+          [
+           "script",
+           "request-cache.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-cache-reload.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request cache - reload"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ],
+          [
+           "script",
+           "request-cache.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-cache-reload.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request cache - reload"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ],
+          [
+           "script",
+           "request-cache.js"
+          ]
+         ]
+        }
        ]
       ],
       "request-clone.sub.html": [
@@ -328735,39 +331625,367 @@
         {}
        ]
       ],
-      "request-consume-empty.html": [
-       "41599588eed3d412a306ad53fd6ea5f7a474a2b6",
+      "request-consume-empty.any.js": [
+       "034a86041a74f58c4d0310ef809f6170b09dbb05",
        [
-        null,
-        {}
+        "fetch/api/request/request-consume-empty.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request consume empty bodies"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-consume-empty.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request consume empty bodies"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-consume-empty.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request consume empty bodies"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-consume-empty.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request consume empty bodies"
+          ]
+         ]
+        }
        ]
       ],
-      "request-consume.html": [
-       "06ef8a7d36db899927e5d76447880deb68250ffd",
+      "request-consume.any.js": [
+       "aff5d65244a15e9fb7cbded180bcdb55ef65be2b",
        [
-        null,
-        {}
+        "fetch/api/request/request-consume.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request consume"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-consume.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request consume"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-consume.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request consume"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-consume.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request consume"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
        ]
       ],
-      "request-disturbed.html": [
-       "18d8a33478ead7af9408e15a41fcf73f1752762a",
+      "request-disturbed.any.js": [
+       "8a11de78ff6e0ed8a970a24325b1c126ebebcd97",
        [
-        null,
-        {}
+        "fetch/api/request/request-disturbed.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request disturbed"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-disturbed.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request disturbed"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-disturbed.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request disturbed"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-disturbed.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request disturbed"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
        ]
       ],
-      "request-error.html": [
-       "622ba3f4c28c6d552f205b3492026a9e731bd4af",
+      "request-error.any.js": [
+       "67ed70c5db2f09aaed3a97fc249022b20d4b941e",
        [
-        null,
-        {}
+        "fetch/api/request/request-error.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request error"
+          ],
+          [
+           "script",
+           "request-error.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-error.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request error"
+          ],
+          [
+           "script",
+           "request-error.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-error.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request error"
+          ],
+          [
+           "script",
+           "request-error.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-error.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request error"
+          ],
+          [
+           "script",
+           "request-error.js"
+          ]
+         ]
+        }
        ]
       ],
-      "request-headers.html": [
-       "014f2fb2d58616696236973b5519cbf7d9eb6e3d",
+      "request-headers.any.js": [
+       "c48e24e5bc63f64c7053152149eee6e17234ef78",
        [
-        null,
-        {}
+        "fetch/api/request/request-headers.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request Headers"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-headers.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request Headers"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-headers.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request Headers"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-headers.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request Headers"
+          ]
+         ]
+        }
        ]
       ],
       "request-init-001.sub.html": [
@@ -328777,11 +331995,67 @@
         {}
        ]
       ],
-      "request-init-002.html": [
-       "14be27742208beffe7f7123771812de073cff1d1",
+      "request-init-002.any.js": [
+       "abb6689f1e844acb507929f701f3f8852c0994fd",
        [
-        null,
-        {}
+        "fetch/api/request/request-init-002.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request init: headers and body"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-init-002.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request init: headers and body"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-init-002.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request init: headers and body"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-init-002.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request init: headers and body"
+          ]
+         ]
+        }
        ]
       ],
       "request-init-003.sub.html": [
@@ -328865,11 +332139,99 @@
         }
        ]
       ],
-      "request-keepalive.html": [
-       "e165422166e9531b689208271f4c2691e1415cf7",
+      "request-keepalive.any.js": [
+       "cb4506db46c931ca347b05a7caa108292e480fc1",
        [
-        null,
-        {}
+        "fetch/api/request/request-keepalive.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request keepalive"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-keepalive.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request keepalive"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-keepalive.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request keepalive"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-keepalive.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request keepalive"
+          ],
+          [
+           "script",
+           "/common/utils.js"
+          ],
+          [
+           "script",
+           "/common/get-host-info.sub.js"
+          ]
+         ]
+        }
        ]
       ],
       "request-reset-attributes.https.html": [
@@ -328879,11 +332241,67 @@
         {}
        ]
       ],
-      "request-structure.html": [
-       "e137a7ea5120ff24de310020fe330a6725cdb9d7",
+      "request-structure.any.js": [
+       "65f1b96b2b9042cd9f9656f125c756e9b4e5ff87",
        [
-        null,
-        {}
+        "fetch/api/request/request-structure.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request structure"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-structure.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request structure"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-structure.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request structure"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/request/request-structure.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Request structure"
+          ]
+         ]
+        }
        ]
       ],
       "url-encoding.html": [
@@ -328911,11 +332329,83 @@
         {}
        ]
       ],
-      "response-cancel-stream.html": [
-       "fcaed04d83e31a437695b55b50beb7425a5a3fb8",
+      "response-cancel-stream.any.js": [
+       "baa46de4039b176c30e0e8a49ee75acbd20e6450",
        [
-        null,
-        {}
+        "fetch/api/response/response-cancel-stream.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response consume blob and http bodies"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-cancel-stream.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response consume blob and http bodies"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-cancel-stream.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response consume blob and http bodies"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-cancel-stream.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response consume blob and http bodies"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
        ]
       ],
       "response-clone-iframe.window.js": [
@@ -328925,27 +332415,225 @@
         {}
        ]
       ],
-      "response-clone.html": [
-       "5529d49932cb8477f8c611de51c095a79e70000d",
+      "response-clone.any.js": [
+       "7cc8f205fa55d35e433a1ab8bc08f62af8bfb693",
        [
-        null,
+        "fetch/api/response/response-clone.any.html",
         {
-         "timeout": "long"
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response clone"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-clone.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response clone"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-clone.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response clone"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-clone.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response clone"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
         }
        ]
       ],
-      "response-consume-empty.html": [
-       "f587e635c655a13c4cb705dcb9756c603632a597",
+      "response-consume-empty.any.js": [
+       "0fa85ecbcb2d7b9093307b189c392aa9c528d9c7",
        [
-        null,
-        {}
+        "fetch/api/response/response-consume-empty.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response consume empty bodies"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-consume-empty.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response consume empty bodies"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-consume-empty.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response consume empty bodies"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-consume-empty.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response consume empty bodies"
+          ]
+         ]
+        }
        ]
       ],
-      "response-consume-stream.html": [
-       "8a97fa0c90f48bdac08b0adb27e2d8a619e97621",
+      "response-consume-stream.any.js": [
+       "d5b0c388cc75b6ed5fce3df21f3ecceb8ac606d5",
        [
-        null,
-        {}
+        "fetch/api/response/response-consume-stream.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response consume"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-consume-stream.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response consume"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-consume-stream.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response consume"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-consume-stream.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response consume"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
        ]
       ],
       "response-consume.html": [
@@ -328955,18 +332643,130 @@
         {}
        ]
       ],
-      "response-error-from-stream.html": [
-       "370f6ba78d7341ad7be59bd6115049ac03428e1f",
+      "response-error-from-stream.any.js": [
+       "118eb7d5cb398c1a27aefb2e8c2358a851c3bfaf",
        [
-        null,
-        {}
+        "fetch/api/response/response-error-from-stream.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response Receives Propagated Error from ReadableStream"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-error-from-stream.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response Receives Propagated Error from ReadableStream"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-error-from-stream.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response Receives Propagated Error from ReadableStream"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-error-from-stream.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response Receives Propagated Error from ReadableStream"
+          ]
+         ]
+        }
        ]
       ],
-      "response-error.html": [
-       "7cbb138345964f548add67a9b290657de3aecebd",
+      "response-error.any.js": [
+       "a76bc4380286fac47b96425abaa6217ed5291e52",
        [
-        null,
-        {}
+        "fetch/api/response/response-error.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response error"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-error.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response error"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-error.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response error"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-error.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response error"
+          ]
+         ]
+        }
        ]
       ],
       "response-from-stream.any.js": [
@@ -329016,94 +332816,740 @@
         }
        ]
       ],
-      "response-init-001.html": [
-       "7af23d310f1ace9ad9827b8dd4e9e5ca17d26b5e",
+      "response-init-001.any.js": [
+       "559e49ad11ffe13a7a291935f6540b6a177e4c9f",
        [
-        null,
-        {}
+        "fetch/api/response/response-init-001.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response init: simple cases"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-init-001.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response init: simple cases"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-init-001.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response init: simple cases"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-init-001.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response init: simple cases"
+          ]
+         ]
+        }
        ]
       ],
-      "response-init-002.html": [
-       "a48af833644efea5373963fc1ce18a202dd454c5",
+      "response-init-002.any.js": [
+       "6c0a46e480406c359abcc7cc315810a844fff6ec",
        [
-        null,
-        {}
+        "fetch/api/response/response-init-002.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response init: body and headers"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-init-002.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response init: body and headers"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-init-002.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response init: body and headers"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-init-002.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response init: body and headers"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
        ]
       ],
-      "response-static-error.html": [
-       "b2d6e82d4279b7c911f38e4fe8294d03b51ec9f3",
+      "response-static-error.any.js": [
+       "4097eab37b4c90e8c453027b99fbf4ed31a08b42",
        [
-        null,
-        {}
+        "fetch/api/response/response-static-error.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response: error static method"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-static-error.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response: error static method"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-static-error.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response: error static method"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-static-error.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response: error static method"
+          ]
+         ]
+        }
        ]
       ],
-      "response-static-redirect.html": [
-       "f647b6debeb8930f98868b10652cd8e2ca527385",
+      "response-static-redirect.any.js": [
+       "971baec4909de67b7fe8001e600c7d77c1df23ee",
        [
-        null,
-        {}
+        "fetch/api/response/response-static-redirect.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response: redirect static method"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-static-redirect.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response: redirect static method"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-static-redirect.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response: redirect static method"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-static-redirect.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Response: redirect static method"
+          ]
+         ]
+        }
        ]
       ],
-      "response-stream-disturbed-1.html": [
-       "c856a6d4e09df972e9def32a249f777e0c0ac5a4",
+      "response-stream-disturbed-1.any.js": [
+       "d80049a2a455e1afc9a1df244319b164141f995f",
        [
-        null,
-        {}
+        "fetch/api/response/response-stream-disturbed-1.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Consuming Response body after getting a ReadableStream"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-stream-disturbed-1.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Consuming Response body after getting a ReadableStream"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-stream-disturbed-1.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Consuming Response body after getting a ReadableStream"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-stream-disturbed-1.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Consuming Response body after getting a ReadableStream"
+          ]
+         ]
+        }
        ]
       ],
-      "response-stream-disturbed-2.html": [
-       "75cc4a59706259e6e5bf95a8032328d644b71e64",
+      "response-stream-disturbed-2.any.js": [
+       "ccff547556e724db0e1b62da36f7041e503391ee",
        [
-        null,
-        {}
+        "fetch/api/response/response-stream-disturbed-2.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Consuming Response body after getting a ReadableStream"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-stream-disturbed-2.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Consuming Response body after getting a ReadableStream"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-stream-disturbed-2.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Consuming Response body after getting a ReadableStream"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-stream-disturbed-2.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Consuming Response body after getting a ReadableStream"
+          ]
+         ]
+        }
        ]
       ],
-      "response-stream-disturbed-3.html": [
-       "795357e6fddca868507a17a2955dea4abcb55f1a",
+      "response-stream-disturbed-3.any.js": [
+       "32c11625eb454237f4296eaacd9c213192146f32",
        [
-        null,
-        {}
+        "fetch/api/response/response-stream-disturbed-3.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Consuming Response body after getting a ReadableStream"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-stream-disturbed-3.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Consuming Response body after getting a ReadableStream"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-stream-disturbed-3.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Consuming Response body after getting a ReadableStream"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-stream-disturbed-3.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Consuming Response body after getting a ReadableStream"
+          ]
+         ]
+        }
        ]
       ],
-      "response-stream-disturbed-4.html": [
-       "9c387699353320fd02560626da5452ac71561fde",
+      "response-stream-disturbed-4.any.js": [
+       "58331ae1d0c8a7e52ecb71c8c5131818c17e10dc",
        [
-        null,
-        {}
+        "fetch/api/response/response-stream-disturbed-4.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Consuming Response body after getting a ReadableStream"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-stream-disturbed-4.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Consuming Response body after getting a ReadableStream"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-stream-disturbed-4.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Consuming Response body after getting a ReadableStream"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-stream-disturbed-4.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Consuming Response body after getting a ReadableStream"
+          ]
+         ]
+        }
        ]
       ],
-      "response-stream-disturbed-5.html": [
-       "830a41bc8096205e7dae3c8b56cad29378a5340f",
+      "response-stream-disturbed-5.any.js": [
+       "9be0c93f35a07bc8d2a3c8ca2a83dae35e926515",
        [
-        null,
-        {}
+        "fetch/api/response/response-stream-disturbed-5.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Consuming Response body after getting a ReadableStream"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-stream-disturbed-5.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Consuming Response body after getting a ReadableStream"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-stream-disturbed-5.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Consuming Response body after getting a ReadableStream"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-stream-disturbed-5.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "Consuming Response body after getting a ReadableStream"
+          ]
+         ]
+        }
        ]
       ],
-      "response-stream-disturbed-6.html": [
-       "30492d472fee621a75d57e28ceca7bd7ea7d1fdd",
+      "response-stream-disturbed-6.any.js": [
+       "61d8544f0786c803f2793d463390537ff7d78fca",
        [
-        null,
-        {}
+        "fetch/api/response/response-stream-disturbed-6.any.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "ReadableStream disturbed tests, via Response's bodyUsed property"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-stream-disturbed-6.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "ReadableStream disturbed tests, via Response's bodyUsed property"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-stream-disturbed-6.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "ReadableStream disturbed tests, via Response's bodyUsed property"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-stream-disturbed-6.any.worker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "title",
+           "ReadableStream disturbed tests, via Response's bodyUsed property"
+          ]
+         ]
+        }
        ]
       ],
       "response-stream-disturbed-by-pipe.any.js": [
-       "f0066c2333a1c1038a506fb910ae9c280583c96e",
+       "5341b75271ead59be5022afd99ffbe22a26628fb",
        [
         "fetch/api/response/response-stream-disturbed-by-pipe.any.html",
-        {}
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-stream-disturbed-by-pipe.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-stream-disturbed-by-pipe.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
        ],
        [
         "fetch/api/response/response-stream-disturbed-by-pipe.any.worker.html",
-        {}
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ]
+         ]
+        }
        ]
       ],
       "response-stream-with-broken-then.any.js": [
-       "b83365d73af5f430e589adbe4e1ea165419f047c",
+       "8fef66c8a281c6248fd36763889bc95aa899f7cc",
        [
         "fetch/api/response/response-stream-with-broken-then.any.html",
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-stream-with-broken-then.any.serviceworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
+           "script",
+           "../resources/utils.js"
+          ]
+         ]
+        }
+       ],
+       [
+        "fetch/api/response/response-stream-with-broken-then.any.sharedworker.html",
+        {
+         "script_metadata": [
+          [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -329115,6 +333561,10 @@
         {
          "script_metadata": [
           [
+           "global",
+           "window,worker"
+          ],
+          [
            "script",
            "../resources/utils.js"
           ]
@@ -329137,14 +333587,50 @@
     },
     "content-encoding": {
      "bad-gzip-body.any.js": [
-      "f820322668c1cd79f1453cba918f1cf38bf8a1bb",
+      "17bc1261a3f5c36a9797c5a171990c522cfe7598",
       [
        "fetch/content-encoding/bad-gzip-body.any.html",
-       {}
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ]
+        ]
+       }
+      ],
+      [
+       "fetch/content-encoding/bad-gzip-body.any.serviceworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ]
+        ]
+       }
+      ],
+      [
+       "fetch/content-encoding/bad-gzip-body.any.sharedworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ]
+        ]
+       }
       ],
       [
        "fetch/content-encoding/bad-gzip-body.any.worker.html",
-       {}
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ]
+        ]
+       }
       ]
      ]
     },
@@ -329609,25 +334095,97 @@
     },
     "data-urls": {
      "base64.any.js": [
-      "c40805364e9d3e4b11283b80902c9562bd262a62",
+      "83f34db1777d99d6c1212a75ab4db44dcbd70720",
       [
        "fetch/data-urls/base64.any.html",
-       {}
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ]
+        ]
+       }
+      ],
+      [
+       "fetch/data-urls/base64.any.serviceworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ]
+        ]
+       }
+      ],
+      [
+       "fetch/data-urls/base64.any.sharedworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ]
+        ]
+       }
       ],
       [
        "fetch/data-urls/base64.any.worker.html",
-       {}
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ]
+        ]
+       }
       ]
      ],
      "processing.any.js": [
-      "940e5cea3878b9461e04cd64e0f5bde6b22e03d2",
+      "cec97bd6be2b2e3f1b39c7a5e8128ee48d7ac3d4",
       [
        "fetch/data-urls/processing.any.html",
-       {}
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ]
+        ]
+       }
+      ],
+      [
+       "fetch/data-urls/processing.any.serviceworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ]
+        ]
+       }
+      ],
+      [
+       "fetch/data-urls/processing.any.sharedworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ]
+        ]
+       }
       ],
       [
        "fetch/data-urls/processing.any.worker.html",
-       {}
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ]
+        ]
+       }
       ]
      ]
     },
@@ -329641,74 +334199,1050 @@
      ]
     },
     "http-cache": {
-     "304-update.html": [
-      "d6d8481e87427816113397bbed49f30b3e43c336",
+     "304-update.any.js": [
+      "15484f01eb32be314f0537694bb1a85a73bc2ba3",
       [
-       null,
+       "fetch/http-cache/304-update.any.html",
        {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - 304 Updates"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "fetch/http-cache/304-update.any.serviceworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - 304 Updates"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "fetch/http-cache/304-update.any.sharedworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - 304 Updates"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "fetch/http-cache/304-update.any.worker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - 304 Updates"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
         "timeout": "long"
        }
       ]
      ],
-     "cache-mode.html": [
-      "ea5bbad01889de63c2851b53ea50c0ded622431e",
+     "cache-mode.any.js": [
+      "8f406d5a6a500346febdc5cd5ac40ff613d51477",
       [
-       null,
+       "fetch/http-cache/cache-mode.any.html",
        {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "Fetch - Cache Mode"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "fetch/http-cache/cache-mode.any.serviceworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "Fetch - Cache Mode"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "fetch/http-cache/cache-mode.any.sharedworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "Fetch - Cache Mode"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "fetch/http-cache/cache-mode.any.worker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "Fetch - Cache Mode"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
         "timeout": "long"
        }
       ]
      ],
-     "cc-request.html": [
-      "e732683d7de1cb914e687e25b902a34e5e462c0c",
+     "cc-request.any.js": [
+      "d55656684144f89718cad19d9bf5ce7fc68268a9",
       [
-       null,
+       "fetch/http-cache/cc-request.any.html",
        {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Cache-Control Request Directives"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "fetch/http-cache/cc-request.any.serviceworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Cache-Control Request Directives"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "fetch/http-cache/cc-request.any.sharedworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Cache-Control Request Directives"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "fetch/http-cache/cc-request.any.worker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Cache-Control Request Directives"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
         "timeout": "long"
        }
       ]
      ],
-     "freshness.html": [
-      "38a457cbebab6c5ac6d48beb9c18a854e1ea8cbb",
+     "freshness.any.js": [
+      "6b97c8244f647c9dcbb95ccd2a9e06796e70444a",
       [
-       null,
+       "fetch/http-cache/freshness.any.html",
        {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Freshness"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "fetch/http-cache/freshness.any.serviceworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Freshness"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "fetch/http-cache/freshness.any.sharedworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Freshness"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "fetch/http-cache/freshness.any.worker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Freshness"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
         "timeout": "long"
        }
       ]
      ],
-     "heuristic.html": [
-      "c2333cd9f05cf096bdddb7a4c9d560125bcb2de6",
+     "heuristic.any.js": [
+      "d846131888288cb863308081eee9271caa108a09",
       [
-       null,
+       "fetch/http-cache/heuristic.any.html",
        {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Heuristic Freshness"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "fetch/http-cache/heuristic.any.serviceworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Heuristic Freshness"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "fetch/http-cache/heuristic.any.sharedworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Heuristic Freshness"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "fetch/http-cache/heuristic.any.worker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Heuristic Freshness"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
         "timeout": "long"
        }
       ]
      ],
-     "invalidate.html": [
-      "dbf727c0eaae9e86105e50ef858f953444801890",
+     "invalidate.any.js": [
+      "9f8090ace659d2b9cc44274b0379a30f08d949ee",
       [
-       null,
+       "fetch/http-cache/invalidate.any.html",
        {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Invalidation"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "fetch/http-cache/invalidate.any.serviceworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Invalidation"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "fetch/http-cache/invalidate.any.sharedworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Invalidation"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "fetch/http-cache/invalidate.any.worker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Invalidation"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
         "timeout": "long"
        }
       ]
      ],
-     "partial.html": [
-      "8f0b528e8ce396c90a87fc76b64f930e99700068",
+     "partial.any.js": [
+      "a75b8115f5cb54ce62f9af44510fc51b69826b89",
       [
-       null,
+       "fetch/http-cache/partial.any.html",
        {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Partial Content"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "fetch/http-cache/partial.any.serviceworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Partial Content"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "fetch/http-cache/partial.any.sharedworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Partial Content"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "fetch/http-cache/partial.any.worker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Partial Content"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
         "timeout": "long"
        }
       ]
      ],
-     "post-patch.html": [
-      "9025a96e4e3503830d3df69e6e0035e3217df1eb",
+     "post-patch.any.js": [
+      "0a69baa5c6646c53397618a8f6810ba7f703ef91",
       [
-       null,
+       "fetch/http-cache/post-patch.any.html",
        {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Caching POST and PATCH responses"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "fetch/http-cache/post-patch.any.serviceworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Caching POST and PATCH responses"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "fetch/http-cache/post-patch.any.sharedworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Caching POST and PATCH responses"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "fetch/http-cache/post-patch.any.worker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Caching POST and PATCH responses"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
         "timeout": "long"
        }
       ]
@@ -329720,20 +335254,266 @@
        {}
       ]
      ],
-     "status.html": [
-      "d55d9e3cf24a496316677a8be9d1d54d21d9c3b8",
+     "status.any.js": [
+      "10c83a25a26dc0441f50aebe646e8ac68700e241",
       [
-       null,
+       "fetch/http-cache/status.any.html",
        {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Status Codes"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "fetch/http-cache/status.any.serviceworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Status Codes"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "fetch/http-cache/status.any.sharedworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Status Codes"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "fetch/http-cache/status.any.worker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Status Codes"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
         "timeout": "long"
        }
       ]
      ],
-     "vary.html": [
-      "721d6e79b5248ed7a4334d754b8039c366090051",
+     "vary.any.js": [
+      "2cfd226af811739637a173dedd9f5d5c81ffb661",
       [
-       null,
-       {}
+       "fetch/http-cache/vary.any.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Vary"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "fetch/http-cache/vary.any.serviceworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Vary"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "fetch/http-cache/vary.any.sharedworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Vary"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "fetch/http-cache/vary.any.worker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "HTTP Cache - Vary"
+         ],
+         [
+          "timeout",
+          "long"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ],
+         [
+          "script",
+          "/common/get-host-info.sub.js"
+         ],
+         [
+          "script",
+          "http-cache.js"
+         ]
+        ],
+        "timeout": "long"
+       }
       ]
      ]
     },
@@ -329770,11 +335550,67 @@
        {}
       ]
      ],
-     "fetch-preflight.https.sub.html": [
-      "ec987e1ca4b8b232e45d8e649b3b1b7ad631d1a0",
+     "fetch-preflight.https.sub.any.js": [
+      "d52474353ba5573ee45a4005673caf5667fd88f8",
       [
-       null,
-       {}
+       "fetch/metadata/fetch-preflight.https.sub.any.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "script",
+          "/fetch/metadata/resources/helper.js"
+         ]
+        ]
+       }
+      ],
+      [
+       "fetch/metadata/fetch-preflight.https.sub.any.serviceworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "script",
+          "/fetch/metadata/resources/helper.js"
+         ]
+        ]
+       }
+      ],
+      [
+       "fetch/metadata/fetch-preflight.https.sub.any.sharedworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "script",
+          "/fetch/metadata/resources/helper.js"
+         ]
+        ]
+       }
+      ],
+      [
+       "fetch/metadata/fetch-preflight.https.sub.any.worker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "script",
+          "/fetch/metadata/resources/helper.js"
+         ]
+        ]
+       }
       ]
      ],
      "fetch-via-serviceworker--fallback.https.sub.html": [
@@ -329791,11 +335627,67 @@
        {}
       ]
      ],
-     "fetch.https.sub.html": [
-      "bb7d20009442ac02c5e8011d28b67cc0014339c5",
+     "fetch.https.sub.any.js": [
+      "aeec5cdf2dc11de137cd4a5eebba931cd16a937d",
       [
-       null,
-       {}
+       "fetch/metadata/fetch.https.sub.any.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "script",
+          "/fetch/metadata/resources/helper.js"
+         ]
+        ]
+       }
+      ],
+      [
+       "fetch/metadata/fetch.https.sub.any.serviceworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "script",
+          "/fetch/metadata/resources/helper.js"
+         ]
+        ]
+       }
+      ],
+      [
+       "fetch/metadata/fetch.https.sub.any.sharedworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "script",
+          "/fetch/metadata/resources/helper.js"
+         ]
+        ]
+       }
+      ],
+      [
+       "fetch/metadata/fetch.https.sub.any.worker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "script",
+          "/fetch/metadata/resources/helper.js"
+         ]
+        ]
+       }
       ]
      ],
      "fetch.sub.html": [
@@ -330018,11 +335910,67 @@
        {}
       ]
      ],
-     "trailing-dot.https.sub.html": [
-      "afd876f0524dd40a0f77b743409e8968a89f81dc",
+     "trailing-dot.https.sub.any.js": [
+      "5e32fc4e7f6a44d2646e093cc9945fa01da77eda",
       [
-       null,
-       {}
+       "fetch/metadata/trailing-dot.https.sub.any.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "script",
+          "/fetch/metadata/resources/helper.js"
+         ]
+        ]
+       }
+      ],
+      [
+       "fetch/metadata/trailing-dot.https.sub.any.serviceworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "script",
+          "/fetch/metadata/resources/helper.js"
+         ]
+        ]
+       }
+      ],
+      [
+       "fetch/metadata/trailing-dot.https.sub.any.sharedworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "script",
+          "/fetch/metadata/resources/helper.js"
+         ]
+        ]
+       }
+      ],
+      [
+       "fetch/metadata/trailing-dot.https.sub.any.worker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "script",
+          "/fetch/metadata/resources/helper.js"
+         ]
+        ]
+       }
       ]
      ],
      "unload.https.sub.html": [
@@ -330124,12 +336072,46 @@
     },
     "range": {
      "general.any.js": [
-      "656ac1ceea2511d960cdb21b25a2846eb092b8c4",
+      "80791c3847eac7501191b44e541d85f5b8f293b7",
       [
        "fetch/range/general.any.html",
        {
         "script_metadata": [
          [
+          "global",
+          "window,worker"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ]
+        ]
+       }
+      ],
+      [
+       "fetch/range/general.any.serviceworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ]
+        ]
+       }
+      ],
+      [
+       "fetch/range/general.any.sharedworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
           "script",
           "/common/utils.js"
          ]
@@ -330141,6 +336123,10 @@
        {
         "script_metadata": [
          [
+          "global",
+          "window,worker"
+         ],
+         [
           "script",
           "/common/utils.js"
          ]
@@ -330249,11 +336235,83 @@
        {}
       ]
      ],
-     "fetch.html": [
-      "c28708019fa4658a45e6637f045077585bb05605",
+     "fetch.any.js": [
+      "3682b9d2c3176eae85ff2f2a341948b37b8f6798",
       [
-       null,
-       {}
+       "fetch/stale-while-revalidate/fetch.any.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "Tests Stale While Revalidate is executed for fetch API"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ]
+        ]
+       }
+      ],
+      [
+       "fetch/stale-while-revalidate/fetch.any.serviceworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "Tests Stale While Revalidate is executed for fetch API"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ]
+        ]
+       }
+      ],
+      [
+       "fetch/stale-while-revalidate/fetch.any.sharedworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "Tests Stale While Revalidate is executed for fetch API"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ]
+        ]
+       }
+      ],
+      [
+       "fetch/stale-while-revalidate/fetch.any.worker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "title",
+          "Tests Stale While Revalidate is executed for fetch API"
+         ],
+         [
+          "script",
+          "/common/utils.js"
+         ]
+        ]
+       }
       ]
      ],
      "revalidate-not-blocked-by-csp.html": [
@@ -368741,14 +374799,14 @@
         ]
        ],
        "compile-error-cross-origin-setInterval.html": [
-        "14e9a8bc21532aa0446ca883daa9bf7bb0ec07af",
+        "c4028e650bf72b51d5fc3b594b16c253bdd59be6",
         [
          null,
          {}
         ]
        ],
        "compile-error-cross-origin-setTimeout.html": [
-        "7c46cc21a3e915764cc69fec39dade84070b8c42",
+        "1eebf82fbb0576b6ca955ca3ce7d518b7629e54a",
         [
          null,
          {}
@@ -368893,14 +374951,14 @@
         ]
        },
        "runtime-error-cross-origin-setInterval.html": [
-        "dd97566d70107a9713e05c838f63de07512a29e3",
+        "8b92f7d148d864842b5f1f19d1658979f280b39f",
         [
          null,
          {}
         ]
        ],
        "runtime-error-cross-origin-setTimeout.html": [
-        "6f9add5c9f59be752b2539414631126c4f33a4e5",
+        "2e1a9d23151804dd9635c19e1c1f5c5cbb05868f",
         [
          null,
          {}
@@ -432293,6 +438351,13 @@
       {}
      ]
     ],
+    "cookies.http.html": [
+     "0ab71dd168ab6de239c55287db204f8f9f14a4ff",
+     [
+      null,
+      {}
+     ]
+    ],
     "cors-expose-star.sub.any.js": [
      "9d88046806c764a467b0ad59fec3c73d9f0fa14b",
      [
diff --git a/third_party/blink/web_tests/external/wpt/cookies/schemeful-same-site/schemeful-websockets.sub.tentative.html b/third_party/blink/web_tests/external/wpt/cookies/schemeful-same-site/schemeful-websockets.sub.tentative.html
index 2626d1c..7095eee 100644
--- a/third_party/blink/web_tests/external/wpt/cookies/schemeful-same-site/schemeful-websockets.sub.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/cookies/schemeful-same-site/schemeful-websockets.sub.tentative.html
@@ -10,35 +10,45 @@
 <body>
 <div id=log></div>
 <script>
-  async_test(function (t) {
-    document.cookie = `samesite_strict=1; sameSite=strict; path=/`;
-    document.cookie = `samesite_lax=1; sameSite=lax; path=/`;
-    t.add_cleanup(function() {
-      credFetch(origin + "/cookies/resources/drop.py?name=" + "samesite_strict");
-      credFetch(origin + "/cookies/resources/drop.py?name=" + "samesite_lax");
+  promise_test(async function (t) {
+    var value = "" + Math.random();
+    document.cookie = `schemeful_same_site_websockets_strict=${value}; sameSite=strict; path=/`;
+    document.cookie = `schemeful_same_site_websockets_lax=${value}; sameSite=lax; path=/`;
+    await credFetch(SECURE_ORIGIN + "/cookies/resources/setSameSiteNone.py?" + value)
+    t.add_cleanup(async function() {
+      await credFetch(origin + "/cookies/resources/drop.py?name=" + "schemeful_same_site_websockets_strict");
+      await credFetch(origin + "/cookies/resources/drop.py?name=" + "schemeful_same_site_websockets_lax");
+      await credFetch(SECURE_ORIGIN + "/cookies/resources/dropSameSiteNone.py");
     });
 
-
     var ws = new WebSocket("ws://{{host}}:{{ports[ws][0]}}/echo-cookie");
-    ws.onclose = t.step_func_done(function () {
-      assert_unreached("'close' should not fire before 'open'.");
-    });
-    ws.onmessage = t.step_func(function (e) {
-      ws.onclose = null;
-      ws.close();
-      // Same-scheme WebSockets should get both cookies
-      assert_regexp_match(e.data, /samesite_strict=1/);
-      assert_regexp_match(e.data, /samesite_lax=1/);
-
-      var ws2 = new WebSocket("wss://{{host}}:{{ports[wss][0]}}/echo-cookie");
-      ws2.onclose = t.step_func_done(function () {
+    return new Promise((resolve, reject) => {
+      ws.onclose = t.step_func_done(function () {
         assert_unreached("'close' should not fire before 'open'.");
       });
-      ws2.onmessage = t.step_func_done(function (e2) {
-        ws2.onclose = null;
-        ws2.close();
-        // Cross-scheme WebSockets shouldn't get anything.
-        assert_regexp_match(e2.data, /^\(none\)$/, "Cross-scheme");
+      ws.onmessage = t.step_func(function (e) {
+        ws.onclose = null;
+        ws.close();
+        // Same-scheme WebSockets should get Lax and Strict cookies.
+        var strictRegex = new RegExp("schemeful_same_site_websockets_strict=" + value);
+        var laxRegex = new RegExp("schemeful_same_site_websockets_lax=" + value);
+        assert_regexp_match(e.data, strictRegex, "Same-scheme strict");
+        assert_regexp_match(e.data, laxRegex, "Same-scheme strict");
+
+        var ws2 = new WebSocket("wss://{{host}}:{{ports[wss][0]}}/echo-cookie");
+        ws2.onclose = t.step_func_done(function () {
+          assert_unreached("'close' should not fire before 'open'.");
+        });
+        ws2.onmessage = t.step_func(function (e2) {
+          ws2.onclose = null;
+          ws2.close();
+          // Cross-scheme WebSockets should only get samesite_none.
+          var noneRegex = new RegExp("samesite_none_secure=" + value);
+          assert_regexp_match(e2.data, noneRegex, "Cross-scheme none");
+          assert_false(strictRegex.test(e2.data), "Cross-scheme strict");
+          assert_false(laxRegex.test(e2.data), "Cross-scheme lax");
+          resolve();
+        });
       });
     });
   }, "Cross-scheme WebSockets are cross-site");
diff --git a/third_party/blink/web_tests/external/wpt/density-size-correction/density-corrected-natural-size.html b/third_party/blink/web_tests/external/wpt/density-size-correction/density-corrected-natural-size.html
index 0b90b74..b2241a6f 100644
--- a/third_party/blink/web_tests/external/wpt/density-size-correction/density-corrected-natural-size.html
+++ b/third_party/blink/web_tests/external/wpt/density-size-correction/density-corrected-natural-size.html
@@ -23,6 +23,7 @@
         await test_valid({width: 10, height: 20, preferredWidth: 20, preferredHeight: 10, resolutionX: 36, resolutionY: 144, resolutionUnit: 2})
         await test_valid({width: 10, height: 20, preferredWidth: 10, preferredHeight: 40, resolutionX: 72, resolutionY: 36, resolutionUnit: 2})
         await test_valid({width: 30, height: 30, preferredWidth: 90, preferredHeight: 30, resolutionX: 24, resolutionY: 72, resolutionUnit: 2})
+        await test_valid({width: 10, height: 20, preferredWidth: 20, preferredHeight: 40, resolutionX: [72 * 1000000, 2 * 1000000], resolutionY: [72 * 10000000, 2 * 10000000], resolutionUnit: 2})
 
         await test_invalid({width: 10, height: 20, preferredWidth: 20, preferredHeight: 30, resolutionX: 36, resolutionY: 36, resolutionUnit: 2})
         await test_invalid({width: 10, height: 20, preferredWidth: 33, preferredHeight: 40, resolutionX: 36, resolutionY: 36, resolutionUnit: 2})
diff --git a/third_party/blink/web_tests/external/wpt/density-size-correction/resources/exify.js b/third_party/blink/web_tests/external/wpt/density-size-correction/resources/exify.js
index c16b25e..b6c22e1 100644
--- a/third_party/blink/web_tests/external/wpt/density-size-correction/resources/exify.js
+++ b/third_party/blink/web_tests/external/wpt/density-size-correction/resources/exify.js
@@ -20,9 +20,9 @@
     if (orientation !== undefined)
         root[piexif.ExifIFD.Orientation] = orientation
     if (resolutionX !== undefined)
-        root[piexif.ImageIFD.XResolution] = [resolutionX, 1]
+        root[piexif.ImageIFD.XResolution] = Array.isArray(resolutionX) ? resolutionX : [resolutionX, 1]
     if (resolutionY !== undefined)
-        root[piexif.ImageIFD.YResolution] = [resolutionY, 1]
+        root[piexif.ImageIFD.YResolution] = Array.isArray(resolutionY) ? resolutionY : [resolutionY, 1]
     if (resolutionUnit !== undefined)
         root[piexif.ImageIFD.ResolutionUnit] = resolutionUnit
     if (preferredWidth !== undefined)
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/abort/cache.https.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/abort/cache.https.any.js
new file mode 100644
index 0000000..bdaf0e6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/abort/cache.https.any.js
@@ -0,0 +1,47 @@
+// META: title=Request signals &amp; the cache API
+// META: global=window,worker
+
+promise_test(async () => {
+  await caches.delete('test');
+  const controller = new AbortController();
+  const signal = controller.signal;
+  const request = new Request('../resources/data.json', { signal });
+
+  const cache = await caches.open('test');
+  await cache.put(request, new Response(''));
+
+  const requests = await cache.keys();
+
+  assert_equals(requests.length, 1, 'Ensuring cleanup worked');
+
+  const [cachedRequest] = requests;
+
+  controller.abort();
+
+  assert_false(cachedRequest.signal.aborted, "Request from cache shouldn't be aborted");
+
+  const data = await fetch(cachedRequest).then(r => r.json());
+  assert_equals(data.key, 'value', 'Fetch fully completes');
+}, "Signals are not stored in the cache API");
+
+promise_test(async () => {
+  await caches.delete('test');
+  const controller = new AbortController();
+  const signal = controller.signal;
+  const request = new Request('../resources/data.json', { signal });
+  controller.abort();
+
+  const cache = await caches.open('test');
+  await cache.put(request, new Response(''));
+
+  const requests = await cache.keys();
+
+  assert_equals(requests.length, 1, 'Ensuring cleanup worked');
+
+  const [cachedRequest] = requests;
+
+  assert_false(cachedRequest.signal.aborted, "Request from cache shouldn't be aborted");
+
+  const data = await fetch(cachedRequest).then(r => r.json());
+  assert_equals(data.key, 'value', 'Fetch fully completes');
+}, "Signals are not stored in the cache API, even if they're already aborted");
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/abort/cache.https.html b/third_party/blink/web_tests/external/wpt/fetch/api/abort/cache.https.html
deleted file mode 100644
index 25ed0e1..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/abort/cache.https.html
+++ /dev/null
@@ -1,57 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-  <meta charset="utf-8">
-  <title>Request signals &amp; the cache API</title>
-  <script src="/resources/testharness.js"></script>
-  <script src="/resources/testharnessreport.js"></script>
-</head>
-<body>
-<script>
-  promise_test(async () => {
-    await caches.delete('test');
-    const controller = new AbortController();
-    const signal = controller.signal;
-    const request = new Request('../resources/data.json', { signal });
-
-    const cache = await caches.open('test');
-    await cache.put(request, new Response(''));
-
-    const requests = await cache.keys();
-
-    assert_equals(requests.length, 1, 'Ensuring cleanup worked');
-
-    const [cachedRequest] = requests;
-
-    controller.abort();
-
-    assert_false(cachedRequest.signal.aborted, "Request from cache shouldn't be aborted");
-
-    const data = await fetch(cachedRequest).then(r => r.json());
-    assert_equals(data.key, 'value', 'Fetch fully completes');
-  }, "Signals are not stored in the cache API");
-
-  promise_test(async () => {
-    await caches.delete('test');
-    const controller = new AbortController();
-    const signal = controller.signal;
-    const request = new Request('../resources/data.json', { signal });
-    controller.abort();
-
-    const cache = await caches.open('test');
-    await cache.put(request, new Response(''));
-
-    const requests = await cache.keys();
-
-    assert_equals(requests.length, 1, 'Ensuring cleanup worked');
-
-    const [cachedRequest] = requests;
-
-    assert_false(cachedRequest.signal.aborted, "Request from cache shouldn't be aborted");
-
-    const data = await fetch(cachedRequest).then(r => r.json());
-    assert_equals(data.key, 'value', 'Fetch fully completes');
-  }, "Signals are not stored in the cache API, even if they're already aborted");
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/basic/accept-header.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/basic/accept-header.any.js
index 3d886df..cd54cf2a 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/basic/accept-header.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/basic/accept-header.any.js
@@ -1,3 +1,4 @@
+// META: global=window,worker
 // META: script=../resources/utils.js
 
 promise_test(function() {
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/basic/conditional-get.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/basic/conditional-get.any.js
new file mode 100644
index 0000000..2f9fa81c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/basic/conditional-get.any.js
@@ -0,0 +1,38 @@
+// META: title=Request ETag
+// META: global=window,worker
+// META: script=/common/utils.js
+
+promise_test(function() {
+  var cacheBuster = token(); // ensures first request is uncached
+  var url = "../resources/cache.py?v=" + cacheBuster;
+  var etag;
+
+  // make the first request
+  return fetch(url).then(function(response) {
+    // ensure we're getting the regular, uncached response
+    assert_equals(response.status, 200);
+    assert_equals(response.headers.get("X-HTTP-STATUS"), null)
+
+    return response.text(); // consuming the body, just to be safe
+  }).then(function(body) {
+    // make a second request
+    return fetch(url);
+  }).then(function(response) {
+    // while the server responds with 304 if our browser sent the correct
+    // If-None-Match request header, at the JavaScript level this surfaces
+    // as 200
+    assert_equals(response.status, 200);
+    assert_equals(response.headers.get("X-HTTP-STATUS"), "304")
+
+    etag = response.headers.get("ETag")
+
+    return response.text(); // consuming the body, just to be safe
+  }).then(function(body) {
+    // make a third request, explicitly setting If-None-Match request header
+    var headers = { "If-None-Match": etag }
+    return fetch(url, { headers: headers })
+  }).then(function(response) {
+    // 304 now surfaces thanks to the explicit If-None-Match request header
+    assert_equals(response.status, 304);
+  });
+}, "Testing conditional GET with ETags");
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/basic/conditional-get.html b/third_party/blink/web_tests/external/wpt/fetch/api/basic/conditional-get.html
deleted file mode 100644
index b80e929..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/basic/conditional-get.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Request ETag</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#request">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <script src="/common/utils.js"></script>
-  </head>
-  <body>
-    <script>
-    promise_test(function() {
-      var cacheBuster = token(); // ensures first request is uncached
-      var url = "../resources/cache.py?v=" + cacheBuster;
-      var etag;
-
-      // make the first request
-      return fetch(url).then(function(response) {
-        // ensure we're getting the regular, uncached response
-        assert_equals(response.status, 200);
-        assert_equals(response.headers.get("X-HTTP-STATUS"), null)
-
-        return response.text(); // consuming the body, just to be safe
-      }).then(function(body) {
-        // make a second request
-        return fetch(url);
-      }).then(function(response) {
-        // while the server responds with 304 if our browser sent the correct
-        // If-None-Match request header, at the JavaScript level this surfaces
-        // as 200
-        assert_equals(response.status, 200);
-        assert_equals(response.headers.get("X-HTTP-STATUS"), "304")
-
-        etag = response.headers.get("ETag")
-
-        return response.text(); // consuming the body, just to be safe
-      }).then(function(body) {
-        // make a third request, explicitly setting If-None-Match request header
-        var headers = { "If-None-Match": etag }
-        return fetch(url, { headers: headers })
-      }).then(function(response) {
-        // 304 now surfaces thanks to the explicit If-None-Match request header
-        assert_equals(response.status, 304);
-      });
-    }, "Testing conditional GET with ETags");
-
-    done();
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/basic/error-after-response.html b/third_party/blink/web_tests/external/wpt/fetch/api/basic/error-after-response.any.js
similarity index 68%
rename from third_party/blink/web_tests/external/wpt/fetch/api/basic/error-after-response.html
rename to third_party/blink/web_tests/external/wpt/fetch/api/basic/error-after-response.any.js
index 8db3429..f7114425 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/basic/error-after-response.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/basic/error-after-response.any.js
@@ -1,15 +1,8 @@
-<!doctype html>
-<html>
-  <head>
-    <title>Fetch: network timeout after receiving the HTTP response headers</title>
-    <meta name="timeout" content="long">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <script src="../resources/utils.js"></script>
-  </head>
-  <body>
-    <div id="log"></div>
-    <script>
+// META: title=Fetch: network timeout after receiving the HTTP response headers
+// META: global=window,worker
+// META: timeout=long
+// META: script=../resources/utils.js
+
 function checkReader(test, reader, promiseToTest)
 {
     return reader.read().then((value) => {
@@ -29,7 +22,3 @@
         return checkReader(test, response.body.getReader(), reader => reader.closed);
     });
 }, "Response reader closed promise should reject after a network error happening after resolving fetch promise");
-    </script>
-  </body>
-</html>
-
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/basic/historical.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/basic/historical.any.js
index aea4184a..c8081262 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/basic/historical.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/basic/historical.any.js
@@ -1,3 +1,5 @@
+// META: global=window,worker
+
 test(() => {
   assert_false("getAll" in new Headers());
   assert_false("getAll" in Headers.prototype);
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-forbidden-headers.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-forbidden-headers.any.js
index fedabed..5d85c4e 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-forbidden-headers.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-forbidden-headers.any.js
@@ -1,3 +1,4 @@
+// META: global=window,worker
 // META: script=../resources/utils.js
 
 function requestForbiddenHeaders(desc, forbiddenHeaders) {
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-head.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-head.any.js
index dc435bf0..e0b6afa 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-head.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-head.any.js
@@ -1,3 +1,5 @@
+// META: global=window,worker
+
 promise_test(function(test) {
   var requestInit = {"method": "HEAD", "body": "test"};
   return promise_rejects_js(test, TypeError, fetch(".", requestInit));
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-headers-case.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-headers-case.any.js
index 067eabb..4c10e71 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-headers-case.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-headers-case.any.js
@@ -1,3 +1,5 @@
+// META: global=window,worker
+
 promise_test(() => {
   return fetch("/xhr/resources/echo-headers.py", {headers: [["THIS-is-A-test", 1], ["THIS-IS-A-TEST", 2]] }).then(res => res.text()).then(body => {
     assert_regexp_match(body, /THIS-is-A-test: 1, 2/)
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-headers-nonascii.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-headers-nonascii.any.js
index 0d822fb..4a9a801 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-headers-nonascii.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-headers-nonascii.any.js
@@ -1,3 +1,5 @@
+// META: global=window,worker
+
 // This tests characters that are not
 // https://infra.spec.whatwg.org/#ascii-code-point
 // but are still
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-headers.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-headers.any.js
index 4ba70f7..ac54256e 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-headers.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-headers.any.js
@@ -1,3 +1,4 @@
+// META: global=window,worker
 // META: script=../resources/utils.js
 
 function checkContentType(contentType, body)
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-referrer.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-referrer.any.js
index 62fbd43e..0c33576 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-referrer.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-referrer.any.js
@@ -1,3 +1,4 @@
+// META: global=window,worker
 // META: script=../resources/utils.js
 
 function testReferrer(referrer, expected, desc) {
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-upload.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-upload.any.js
index 14f4a07..1412816 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-upload.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-upload.any.js
@@ -1,3 +1,4 @@
+// META: global=window,worker
 // META: script=../resources/utils.js
 
 function testUpload(desc, url, method, createBody, expectedBody) {
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-upload.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-upload.any.serviceworker-expected.txt
new file mode 100644
index 0000000..846995459
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-upload.any.serviceworker-expected.txt
@@ -0,0 +1,20 @@
+This is a testharness.js-based test.
+PASS Fetch with PUT with body
+PASS Fetch with POST with text body
+PASS Fetch with POST with URLSearchParams body
+PASS Fetch with POST with Blob body
+PASS Fetch with POST with ArrayBuffer body
+PASS Fetch with POST with Uint8Array body
+PASS Fetch with POST with Int8Array body
+PASS Fetch with POST with Float32Array body
+PASS Fetch with POST with Float64Array body
+PASS Fetch with POST with DataView body
+PASS Fetch with POST with Blob body with mime type
+FAIL Fetch with POST with ReadableStream promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch"
+PASS Fetch with POST with ReadableStream containing String
+PASS Fetch with POST with ReadableStream containing null
+PASS Fetch with POST with ReadableStream containing number
+PASS Fetch with POST with ReadableStream containing ArrayBuffer
+PASS Fetch with POST with ReadableStream containing Blob
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-upload.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-upload.any.sharedworker-expected.txt
new file mode 100644
index 0000000..846995459
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/basic/request-upload.any.sharedworker-expected.txt
@@ -0,0 +1,20 @@
+This is a testharness.js-based test.
+PASS Fetch with PUT with body
+PASS Fetch with POST with text body
+PASS Fetch with POST with URLSearchParams body
+PASS Fetch with POST with Blob body
+PASS Fetch with POST with ArrayBuffer body
+PASS Fetch with POST with Uint8Array body
+PASS Fetch with POST with Int8Array body
+PASS Fetch with POST with Float32Array body
+PASS Fetch with POST with Float64Array body
+PASS Fetch with POST with DataView body
+PASS Fetch with POST with Blob body with mime type
+FAIL Fetch with POST with ReadableStream promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch"
+PASS Fetch with POST with ReadableStream containing String
+PASS Fetch with POST with ReadableStream containing null
+PASS Fetch with POST with ReadableStream containing number
+PASS Fetch with POST with ReadableStream containing ArrayBuffer
+PASS Fetch with POST with ReadableStream containing Blob
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/basic/scheme-about.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/basic/scheme-about.any.js
index eb892d32..4329bd0 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/basic/scheme-about.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/basic/scheme-about.any.js
@@ -1,3 +1,4 @@
+// META: global=window,worker
 // META: script=../resources/utils.js
 
 function checkNetworkError(url, method) {
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/basic/scheme-data.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/basic/scheme-data.any.js
index e4a88071..1c3b5dc 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/basic/scheme-data.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/basic/scheme-data.any.js
@@ -1,3 +1,4 @@
+// META: global=window,worker
 // META: script=../resources/utils.js
 
 function checkFetchResponse(url, data, mime, fetchMode, method) {
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/basic/scheme-others.sub.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/basic/scheme-others.sub.any.js
index 9c3cad1..550f69c 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/basic/scheme-others.sub.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/basic/scheme-others.sub.any.js
@@ -1,3 +1,4 @@
+// META: global=window,worker
 // META: script=../resources/utils.js
 
 function checkKoUrl(url, desc) {
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/basic/stream-response.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/basic/stream-response.any.js
index 5b11018..4a8855a 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/basic/stream-response.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/basic/stream-response.any.js
@@ -1,3 +1,4 @@
+// META: global=window,worker
 // META: script=../resources/utils.js
 
 function streamBody(reader, test, count) {
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/basic/text-utf8.html b/third_party/blink/web_tests/external/wpt/fetch/api/basic/text-utf8.any.js
similarity index 91%
rename from third_party/blink/web_tests/external/wpt/fetch/api/basic/text-utf8.html
rename to third_party/blink/web_tests/external/wpt/fetch/api/basic/text-utf8.any.js
index e5c567b..05c8c888 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/basic/text-utf8.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/basic/text-utf8.any.js
@@ -1,12 +1,6 @@
-<!doctype html>
-<meta charset=utf-8>
-<title>Fetch: Request and Response text() should decode as UTF-8</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<link rel="help" href="https://fetch.spec.whatwg.org/#body-mixin" />
-
-<script src="../resources/utils.js"></script>
-<script>
+// META: title=Fetch: Request and Response text() should decode as UTF-8
+// META: global=window,worker
+// META: script=../resources/utils.js
 
 function testTextDecoding(body, expectedText, urlParameter, title)
 {
@@ -78,5 +72,3 @@
 var utf16WithoutBOMAsURLParameter = "%E6%00%F8%00%E5%00%0A%00%C6%30%B9%30%C8%30%0A%00";
 var utf16WithoutBOMDecoded = "\ufffd\u0000\ufffd\u0000\ufffd\u0000\u000a\u0000\ufffd\u0030\ufffd\u0030\ufffd\u0030\u000a\u0000";
 testTextDecoding(utf16WithoutBOM, utf16WithoutBOMDecoded, utf16WithoutBOMAsURLParameter, "UTF-16 without BOM decoded as UTF-8");
-
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/cors/cors-multiple-origins.sub.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/cors/cors-multiple-origins.sub.any.js
index b1034eb7..b3abb922 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/cors/cors-multiple-origins.sub.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/cors/cors-multiple-origins.sub.any.js
@@ -1,3 +1,4 @@
+// META: global=window,worker
 // META: script=../resources/utils.js
 
 function corsMultipleOrigins(originList) {
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/cors/cors-preflight-redirect.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/cors/cors-preflight-redirect.any.js
index 7ed54319..15f7659 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/cors/cors-preflight-redirect.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/cors/cors-preflight-redirect.any.js
@@ -1,3 +1,4 @@
+// META: global=window,worker
 // META: script=/common/utils.js
 // META: script=../resources/utils.js
 // META: script=/common/get-host-info.sub.js
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/cors/cors-preflight-redirect.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/cors/cors-preflight-redirect.any.sharedworker-expected.txt
new file mode 100644
index 0000000..1130f24
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/cors/cors-preflight-redirect.any.sharedworker-expected.txt
@@ -0,0 +1,13 @@
+This is a testharness.js-based test.
+PASS Redirection 301 on preflight failed
+FAIL Redirection 301 after preflight failed assert_unreached: Should have rejected: undefined Reached unreachable code
+PASS Redirection 302 on preflight failed
+FAIL Redirection 302 after preflight failed assert_unreached: Should have rejected: undefined Reached unreachable code
+PASS Redirection 303 on preflight failed
+FAIL Redirection 303 after preflight failed assert_unreached: Should have rejected: undefined Reached unreachable code
+PASS Redirection 307 on preflight failed
+FAIL Redirection 307 after preflight failed assert_unreached: Should have rejected: undefined Reached unreachable code
+PASS Redirection 308 on preflight failed
+FAIL Redirection 308 after preflight failed assert_unreached: Should have rejected: undefined Reached unreachable code
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/credentials/authentication-basic.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/credentials/authentication-basic.any.js
index 4969b304..babc5d0 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/credentials/authentication-basic.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/credentials/authentication-basic.any.js
@@ -1,3 +1,4 @@
+// META: global=window,worker
 // META: script=../resources/utils.js
 
 function basicAuth(desc, user, pass, mode, status) {
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/credentials/cookies.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/credentials/cookies.any.js
index b65a866..de30e47 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/credentials/cookies.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/credentials/cookies.any.js
@@ -1,3 +1,4 @@
+// META: global=window,worker
 // META: script=../resources/utils.js
 
 function cookies(desc, credentials1, credentials2 ,cookies) {
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/headers/header-values-normalize.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/headers/header-values-normalize.any.js
new file mode 100644
index 0000000..814789c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/headers/header-values-normalize.any.js
@@ -0,0 +1,70 @@
+// META: title=Header value normalizing test
+// META: global=window,worker
+// META: timeout=long
+
+for(let i = 0; i < 0x21; i++) {
+  let fail = false,
+      strip = false
+
+  // REMOVE 0x0B/0x0C exception once https://github.com/web-platform-tests/wpt/issues/8372 is fixed
+  if(i === 0x0B || i === 0x0C)
+    continue
+
+  if(i === 0) {
+    fail = true
+  }
+
+  if(i === 0x09 || i === 0x0A || i === 0x0D || i === 0x20) {
+    strip = true
+  }
+
+  let url = "../resources/inspect-headers.py?headers=val1|val2|val3",
+      val = String.fromCharCode(i),
+      expectedVal = strip ? "" : val,
+      val1 = val,
+      expectedVal1 = expectedVal,
+      val2 = "x" + val,
+      expectedVal2 = "x" + expectedVal,
+      val3 = val + "x",
+      expectedVal3 = expectedVal + "x"
+
+  // XMLHttpRequest is not available in service workers
+  if (!self.GLOBAL.isWorker()) {
+    async_test((t) => {
+      let xhr = new XMLHttpRequest()
+      xhr.open("POST", url)
+      if(fail) {
+          assert_throws_dom("SyntaxError", () => xhr.setRequestHeader("val1", val1))
+          assert_throws_dom("SyntaxError", () => xhr.setRequestHeader("val2", val2))
+          assert_throws_dom("SyntaxError", () => xhr.setRequestHeader("val3", val3))
+          t.done()
+      } else {
+        xhr.setRequestHeader("val1", val1)
+        xhr.setRequestHeader("val2", val2)
+        xhr.setRequestHeader("val3", val3)
+        xhr.onload = t.step_func_done(() => {
+          assert_equals(xhr.getResponseHeader("x-request-val1"), expectedVal1)
+          assert_equals(xhr.getResponseHeader("x-request-val2"), expectedVal2)
+          assert_equals(xhr.getResponseHeader("x-request-val3"), expectedVal3)
+        })
+        xhr.send()
+      }
+    }, "XMLHttpRequest with value " + encodeURI(val))
+  }
+
+  promise_test((t) => {
+    if(fail) {
+      return Promise.all([
+        promise_rejects_js(t, TypeError, fetch(url, { headers: {"val1": val1} })),
+        promise_rejects_js(t, TypeError, fetch(url, { headers: {"val2": val2} })),
+        promise_rejects_js(t, TypeError, fetch(url, { headers: {"val3": val3} }))
+      ])
+    } else {
+      return fetch(url, { headers: {"val1": val1, "val2": val2, "val3": val3} }).then((res) => {
+        assert_equals(res.headers.get("x-request-val1"), expectedVal1)
+        assert_equals(res.headers.get("x-request-val2"), expectedVal2)
+        assert_equals(res.headers.get("x-request-val3"), expectedVal3)
+      })
+    }
+  }, "fetch() with value " + encodeURI(val))
+}
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/headers/header-values-normalize.html b/third_party/blink/web_tests/external/wpt/fetch/api/headers/header-values-normalize.html
deleted file mode 100644
index d2da3233..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/headers/header-values-normalize.html
+++ /dev/null
@@ -1,72 +0,0 @@
-<!doctype html>
-<meta charset=utf8>
-<meta name=timeout content=long>
-<title>Header value normalizing test</title>
-<script src=/resources/testharness.js></script>
-<script src=/resources/testharnessreport.js></script>
-<div id=log></div>
-<script>
-for(let i = 0; i < 0x21; i++) {
-  let fail = false,
-      strip = false
-
-  // REMOVE 0x0B/0x0C exception once https://github.com/web-platform-tests/wpt/issues/8372 is fixed
-  if(i === 0x0B || i === 0x0C)
-    continue
-
-  if(i === 0) {
-    fail = true
-  }
-
-  if(i === 0x09 || i === 0x0A || i === 0x0D || i === 0x20) {
-    strip = true
-  }
-
-  let url = "../resources/inspect-headers.py?headers=val1|val2|val3",
-      val = String.fromCharCode(i),
-      expectedVal = strip ? "" : val,
-      val1 = val,
-      expectedVal1 = expectedVal,
-      val2 = "x" + val,
-      expectedVal2 = "x" + expectedVal,
-      val3 = val + "x",
-      expectedVal3 = expectedVal + "x"
-
-  async_test((t) => {
-    let xhr = new XMLHttpRequest()
-    xhr.open("POST", url)
-    if(fail) {
-        assert_throws_dom("SyntaxError", () => xhr.setRequestHeader("val1", val1))
-        assert_throws_dom("SyntaxError", () => xhr.setRequestHeader("val2", val2))
-        assert_throws_dom("SyntaxError", () => xhr.setRequestHeader("val3", val3))
-        t.done()
-    } else {
-      xhr.setRequestHeader("val1", val1)
-      xhr.setRequestHeader("val2", val2)
-      xhr.setRequestHeader("val3", val3)
-      xhr.onload = t.step_func_done(() => {
-        assert_equals(xhr.getResponseHeader("x-request-val1"), expectedVal1)
-        assert_equals(xhr.getResponseHeader("x-request-val2"), expectedVal2)
-        assert_equals(xhr.getResponseHeader("x-request-val3"), expectedVal3)
-      })
-      xhr.send()
-    }
-  }, "XMLHttpRequest with value " + encodeURI(val))
-
-  promise_test((t) => {
-    if(fail) {
-      return Promise.all([
-        promise_rejects_js(t, TypeError, fetch(url, { headers: {"val1": val1} })),
-        promise_rejects_js(t, TypeError, fetch(url, { headers: {"val2": val2} })),
-        promise_rejects_js(t, TypeError, fetch(url, { headers: {"val3": val3} }))
-      ])
-    } else {
-      return fetch(url, { headers: {"val1": val1, "val2": val2, "val3": val3} }).then((res) => {
-        assert_equals(res.headers.get("x-request-val1"), expectedVal1)
-        assert_equals(res.headers.get("x-request-val2"), expectedVal2)
-        assert_equals(res.headers.get("x-request-val3"), expectedVal3)
-      })
-    }
-  }, "fetch() with value " + encodeURI(val))
-}
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/headers/header-values.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/headers/header-values.any.js
new file mode 100644
index 0000000..9a829d8d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/headers/header-values.any.js
@@ -0,0 +1,61 @@
+// META: title=Header value test
+// META: global=window,worker
+// META: timeout=long
+
+// Invalid values
+[0, 0x0A, 0x0D].forEach(val => {
+  val = "x" + String.fromCharCode(val) + "x"
+
+  // XMLHttpRequest is not available in service workers
+  if (!self.GLOBAL.isWorker()) {
+    test(() => {
+      let xhr = new XMLHttpRequest()
+      xhr.open("POST", "/")
+      assert_throws_dom("SyntaxError", () => xhr.setRequestHeader("value-test", val))
+    }, "XMLHttpRequest with value " + encodeURI(val) + " needs to throw")
+  }
+
+  promise_test(t => promise_rejects_js(t, TypeError, fetch("/", { headers: {"value-test": val} })), "fetch() with value " + encodeURI(val) + " needs to throw")
+})
+
+// Valid values
+let headerValues =[]
+for(let i = 0; i < 0x100; i++) {
+  if(i === 0 || i === 0x0A || i === 0x0D) {
+    continue
+  }
+  headerValues.push("x" + String.fromCharCode(i) + "x")
+}
+var url = "../resources/inspect-headers.py?headers="
+headerValues.forEach((_, i) => {
+  url += "val" + i + "|"
+})
+
+// XMLHttpRequest is not available in service workers
+if (!self.GLOBAL.isWorker()) {
+  async_test((t) => {
+    let xhr = new XMLHttpRequest()
+    xhr.open("POST", url)
+    headerValues.forEach((val, i) => {
+      xhr.setRequestHeader("val" + i, val)
+    })
+    xhr.onload = t.step_func_done(() => {
+      headerValues.forEach((val, i) => {
+        assert_equals(xhr.getResponseHeader("x-request-val" + i), val)
+      })
+    })
+    xhr.send()
+  }, "XMLHttpRequest with all valid values")
+}
+
+promise_test((t) => {
+  const headers = new Headers
+  headerValues.forEach((val, i) => {
+    headers.append("val" + i, val)
+  })
+  return fetch(url, { headers }).then((res) => {
+    headerValues.forEach((val, i) => {
+      assert_equals(res.headers.get("x-request-val" + i), val)
+    })
+  })
+}, "fetch() with all valid values")
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/headers/header-values.html b/third_party/blink/web_tests/external/wpt/fetch/api/headers/header-values.html
deleted file mode 100644
index a68bfa9..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/headers/header-values.html
+++ /dev/null
@@ -1,59 +0,0 @@
-<!doctype html>
-<meta charset=utf8>
-<meta name=timeout content=long>
-<title>Header value test</title>
-<script src=/resources/testharness.js></script>
-<script src=/resources/testharnessreport.js></script>
-<div id=log></div>
-<script>
-// Invalid values
-[0, 0x0A, 0x0D].forEach(val => {
-  val = "x" + String.fromCharCode(val) + "x"
-  test(() => {
-    let xhr = new XMLHttpRequest()
-    xhr.open("POST", "/")
-    assert_throws_dom("SyntaxError", () => xhr.setRequestHeader("value-test", val))
-  }, "XMLHttpRequest with value " + encodeURI(val) + " needs to throw")
-
-  promise_test(t => promise_rejects_js(t, TypeError, fetch("/", { headers: {"value-test": val} })), "fetch() with value " + encodeURI(val) + " needs to throw")
-})
-
-// Valid values
-let headerValues =[]
-for(let i = 0; i < 0x100; i++) {
-  if(i === 0 || i === 0x0A || i === 0x0D) {
-    continue
-  }
-  headerValues.push("x" + String.fromCharCode(i) + "x")
-}
-var url = "../resources/inspect-headers.py?headers="
-headerValues.forEach((_, i) => {
-  url += "val" + i + "|"
-})
-
-async_test((t) => {
-  let xhr = new XMLHttpRequest()
-  xhr.open("POST", url)
-  headerValues.forEach((val, i) => {
-    xhr.setRequestHeader("val" + i, val)
-  })
-  xhr.onload = t.step_func_done(() => {
-    headerValues.forEach((val, i) => {
-      assert_equals(xhr.getResponseHeader("x-request-val" + i), val)
-    })
-  })
-  xhr.send()
-}, "XMLHttpRequest with all valid values")
-
-promise_test((t) => {
-  const headers = new Headers
-  headerValues.forEach((val, i) => {
-    headers.append("val" + i, val)
-  })
-  return fetch(url, { headers }).then((res) => {
-    headerValues.forEach((val, i) => {
-      assert_equals(res.headers.get("x-request-val" + i), val)
-    })
-  })
-}, "fetch() with all valid values")
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-basic.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-basic.any.js
new file mode 100644
index 0000000..5de71f4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-basic.any.js
@@ -0,0 +1,218 @@
+// META: title=Headers structure
+// META: global=window,worker
+
+test(function() {
+  new Headers();
+}, "Create headers from no parameter");
+
+test(function() {
+  new Headers(undefined);
+}, "Create headers from undefined parameter");
+
+test(function() {
+  new Headers({});
+}, "Create headers from empty object");
+
+var parameters = [null, 1];
+parameters.forEach(function(parameter) {
+  test(function() {
+    assert_throws_js(TypeError, function() { new Headers(parameter) });
+  }, "Create headers with " + parameter + " should throw");
+});
+
+var headerDict = {"name1": "value1",
+                  "name2": "value2",
+                  "name3": "value3",
+                  "name4": null,
+                  "name5": undefined,
+                  "name6": 1,
+                  "Content-Type": "value4"
+};
+
+var headerSeq = [];
+for (var name in headerDict)
+  headerSeq.push([name, headerDict[name]]);
+
+test(function() {
+  var headers = new Headers(headerSeq);
+  for (name in headerDict) {
+    assert_equals(headers.get(name), String(headerDict[name]),
+      "name: " + name + " has value: " + headerDict[name]);
+  }
+  assert_equals(headers.get("length"), null, "init should be treated as a sequence, not as a dictionary");
+}, "Create headers with sequence");
+
+test(function() {
+  var headers = new Headers(headerDict);
+  for (name in headerDict) {
+    assert_equals(headers.get(name), String(headerDict[name]),
+      "name: " + name + " has value: " + headerDict[name]);
+  }
+}, "Create headers with record");
+
+test(function() {
+  var headers = new Headers(headerDict);
+  var headers2 = new Headers(headers);
+  for (name in headerDict) {
+    assert_equals(headers2.get(name), String(headerDict[name]),
+      "name: " + name + " has value: " + headerDict[name]);
+  }
+}, "Create headers with existing headers");
+
+test(function() {
+  var headers = new Headers()
+  headers[Symbol.iterator] = function *() {
+    yield ["test", "test"]
+  }
+  var headers2 = new Headers(headers)
+  assert_equals(headers2.get("test"), "test")
+}, "Create headers with existing headers with custom iterator");
+
+test(function() {
+  var headers = new Headers();
+  for (name in headerDict) {
+    headers.append(name, headerDict[name]);
+    assert_equals(headers.get(name), String(headerDict[name]),
+      "name: " + name + " has value: " + headerDict[name]);
+  }
+}, "Check append method");
+
+test(function() {
+  var headers = new Headers();
+  for (name in headerDict) {
+    headers.set(name, headerDict[name]);
+    assert_equals(headers.get(name), String(headerDict[name]),
+      "name: " + name + " has value: " + headerDict[name]);
+  }
+}, "Check set method");
+
+test(function() {
+  var headers = new Headers(headerDict);
+  for (name in headerDict)
+    assert_true(headers.has(name),"headers has name " + name);
+
+  assert_false(headers.has("nameNotInHeaders"),"headers do not have header: nameNotInHeaders");
+}, "Check has method");
+
+test(function() {
+  var headers = new Headers(headerDict);
+  for (name in headerDict) {
+    assert_true(headers.has(name),"headers have a header: " + name);
+    headers.delete(name)
+    assert_true(!headers.has(name),"headers do not have anymore a header: " + name);
+  }
+}, "Check delete method");
+
+test(function() {
+  var headers = new Headers(headerDict);
+  for (name in headerDict)
+    assert_equals(headers.get(name), String(headerDict[name]),
+      "name: " + name + " has value: " + headerDict[name]);
+
+  assert_equals(headers.get("nameNotInHeaders"), null, "header: nameNotInHeaders has no value");
+}, "Check get method");
+
+var headerEntriesDict = {"name1": "value1",
+                          "Name2": "value2",
+                          "name": "value3",
+                          "content-Type": "value4",
+                          "Content-Typ": "value5",
+                          "Content-Types": "value6"
+};
+var sortedHeaderDict = {};
+var headerValues = [];
+var sortedHeaderKeys = Object.keys(headerEntriesDict).map(function(value) {
+  sortedHeaderDict[value.toLowerCase()] = headerEntriesDict[value];
+  headerValues.push(headerEntriesDict[value]);
+  return value.toLowerCase();
+}).sort();
+
+var iteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]()));
+function checkIteratorProperties(iterator) {
+  var prototype = Object.getPrototypeOf(iterator);
+  assert_equals(Object.getPrototypeOf(prototype), iteratorPrototype);
+
+  var descriptor = Object.getOwnPropertyDescriptor(prototype, "next");
+  assert_true(descriptor.configurable, "configurable");
+  assert_true(descriptor.enumerable, "enumerable");
+  assert_true(descriptor.writable, "writable");
+}
+
+test(function() {
+  var headers = new Headers(headerEntriesDict);
+  var actual = headers.keys();
+  checkIteratorProperties(actual);
+
+  sortedHeaderKeys.forEach(function(key) {
+      entry = actual.next();
+      assert_false(entry.done);
+      assert_equals(entry.value, key);
+  });
+  assert_true(actual.next().done);
+  assert_true(actual.next().done);
+
+  for (key of headers.keys())
+      assert_true(sortedHeaderKeys.indexOf(key) != -1);
+}, "Check keys method");
+
+test(function() {
+  var headers = new Headers(headerEntriesDict);
+  var actual = headers.values();
+  checkIteratorProperties(actual);
+
+  sortedHeaderKeys.forEach(function(key) {
+      entry = actual.next();
+      assert_false(entry.done);
+      assert_equals(entry.value, sortedHeaderDict[key]);
+  });
+  assert_true(actual.next().done);
+  assert_true(actual.next().done);
+
+  for (value of headers.values())
+      assert_true(headerValues.indexOf(value) != -1);
+}, "Check values method");
+
+test(function() {
+  var headers = new Headers(headerEntriesDict);
+  var actual = headers.entries();
+  checkIteratorProperties(actual);
+
+  sortedHeaderKeys.forEach(function(key) {
+      entry = actual.next();
+      assert_false(entry.done);
+      assert_equals(entry.value[0], key);
+      assert_equals(entry.value[1], sortedHeaderDict[key]);
+  });
+  assert_true(actual.next().done);
+  assert_true(actual.next().done);
+
+  for (entry of headers.entries())
+      assert_equals(entry[1], sortedHeaderDict[entry[0]]);
+}, "Check entries method");
+
+test(function() {
+  var headers = new Headers(headerEntriesDict);
+  var actual = headers[Symbol.iterator]();
+
+  sortedHeaderKeys.forEach(function(key) {
+      entry = actual.next();
+      assert_false(entry.done);
+      assert_equals(entry.value[0], key);
+      assert_equals(entry.value[1], sortedHeaderDict[key]);
+  });
+  assert_true(actual.next().done);
+  assert_true(actual.next().done);
+}, "Check Symbol.iterator method");
+
+test(function() {
+  var headers = new Headers(headerEntriesDict);
+  var reference = sortedHeaderKeys[Symbol.iterator]();
+  headers.forEach(function(value, key, container) {
+      assert_equals(headers, container);
+      entry = reference.next();
+      assert_false(entry.done);
+      assert_equals(key, entry.value);
+      assert_equals(value, sortedHeaderDict[entry.value]);
+  });
+  assert_true(reference.next().done);
+}, "Check forEach method");
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-basic.html b/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-basic.html
deleted file mode 100644
index 254ef051..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-basic.html
+++ /dev/null
@@ -1,230 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Headers structure</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#headers">
-    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-  </head>
-  <body>
-    <script>
-      test(function() {
-        new Headers();
-      }, "Create headers from no parameter");
-
-      test(function() {
-        new Headers(undefined);
-      }, "Create headers from undefined parameter");
-
-      test(function() {
-        new Headers({});
-      }, "Create headers from empty object");
-
-      var parameters = [null, 1];
-      parameters.forEach(function(parameter) {
-        test(function() {
-          assert_throws_js(TypeError, function() { new Headers(parameter) });
-        }, "Create headers with " + parameter + " should throw");
-      });
-
-      var headerDict = {"name1": "value1",
-                        "name2": "value2",
-                        "name3": "value3",
-                        "name4": null,
-                        "name5": undefined,
-                        "name6": 1,
-                        "Content-Type": "value4"
-      };
-
-      var headerSeq = [];
-      for (var name in headerDict)
-        headerSeq.push([name, headerDict[name]]);
-
-      test(function() {
-        var headers = new Headers(headerSeq);
-        for (name in headerDict) {
-          assert_equals(headers.get(name), String(headerDict[name]),
-            "name: " + name + " has value: " + headerDict[name]);
-        }
-        assert_equals(headers.get("length"), null, "init should be treated as a sequence, not as a dictionary");
-      }, "Create headers with sequence");
-
-      test(function() {
-        var headers = new Headers(headerDict);
-        for (name in headerDict) {
-          assert_equals(headers.get(name), String(headerDict[name]),
-            "name: " + name + " has value: " + headerDict[name]);
-        }
-      }, "Create headers with record");
-
-      test(function() {
-        var headers = new Headers(headerDict);
-        var headers2 = new Headers(headers);
-        for (name in headerDict) {
-          assert_equals(headers2.get(name), String(headerDict[name]),
-            "name: " + name + " has value: " + headerDict[name]);
-        }
-      }, "Create headers with existing headers");
-
-      test(function() {
-        var headers = new Headers()
-        headers[Symbol.iterator] = function *() {
-          yield ["test", "test"]
-        }
-        var headers2 = new Headers(headers)
-        assert_equals(headers2.get("test"), "test")
-      }, "Create headers with existing headers with custom iterator");
-
-      test(function() {
-        var headers = new Headers();
-        for (name in headerDict) {
-          headers.append(name, headerDict[name]);
-          assert_equals(headers.get(name), String(headerDict[name]),
-            "name: " + name + " has value: " + headerDict[name]);
-        }
-      }, "Check append method");
-
-      test(function() {
-        var headers = new Headers();
-        for (name in headerDict) {
-          headers.set(name, headerDict[name]);
-          assert_equals(headers.get(name), String(headerDict[name]),
-            "name: " + name + " has value: " + headerDict[name]);
-        }
-      }, "Check set method");
-
-      test(function() {
-        var headers = new Headers(headerDict);
-        for (name in headerDict)
-          assert_true(headers.has(name),"headers has name " + name);
-
-        assert_false(headers.has("nameNotInHeaders"),"headers do not have header: nameNotInHeaders");
-      }, "Check has method");
-
-      test(function() {
-        var headers = new Headers(headerDict);
-        for (name in headerDict) {
-          assert_true(headers.has(name),"headers have a header: " + name);
-          headers.delete(name)
-          assert_true(!headers.has(name),"headers do not have anymore a header: " + name);
-        }
-      }, "Check delete method");
-
-      test(function() {
-        var headers = new Headers(headerDict);
-        for (name in headerDict)
-          assert_equals(headers.get(name), String(headerDict[name]),
-            "name: " + name + " has value: " + headerDict[name]);
-
-        assert_equals(headers.get("nameNotInHeaders"), null, "header: nameNotInHeaders has no value");
-      }, "Check get method");
-
-      var headerEntriesDict = {"name1": "value1",
-                               "Name2": "value2",
-                               "name": "value3",
-                               "content-Type": "value4",
-                               "Content-Typ": "value5",
-                               "Content-Types": "value6"
-      };
-      var sortedHeaderDict = {};
-      var headerValues = [];
-      var sortedHeaderKeys = Object.keys(headerEntriesDict).map(function(value) {
-        sortedHeaderDict[value.toLowerCase()] = headerEntriesDict[value];
-        headerValues.push(headerEntriesDict[value]);
-        return value.toLowerCase();
-      }).sort();
-
-      var iteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]()));
-      function checkIteratorProperties(iterator) {
-        var prototype = Object.getPrototypeOf(iterator);
-        assert_equals(Object.getPrototypeOf(prototype), iteratorPrototype);
-
-        var descriptor = Object.getOwnPropertyDescriptor(prototype, "next");
-        assert_true(descriptor.configurable, "configurable");
-        assert_true(descriptor.enumerable, "enumerable");
-        assert_true(descriptor.writable, "writable");
-      }
-
-      test(function() {
-        var headers = new Headers(headerEntriesDict);
-        var actual = headers.keys();
-        checkIteratorProperties(actual);
-
-        sortedHeaderKeys.forEach(function(key) {
-            entry = actual.next();
-            assert_false(entry.done);
-            assert_equals(entry.value, key);
-        });
-        assert_true(actual.next().done);
-        assert_true(actual.next().done);
-
-        for (key of headers.keys())
-            assert_true(sortedHeaderKeys.indexOf(key) != -1);
-      }, "Check keys method");
-
-      test(function() {
-        var headers = new Headers(headerEntriesDict);
-        var actual = headers.values();
-        checkIteratorProperties(actual);
-
-        sortedHeaderKeys.forEach(function(key) {
-            entry = actual.next();
-            assert_false(entry.done);
-            assert_equals(entry.value, sortedHeaderDict[key]);
-        });
-        assert_true(actual.next().done);
-        assert_true(actual.next().done);
-
-        for (value of headers.values())
-            assert_true(headerValues.indexOf(value) != -1);
-      }, "Check values method");
-
-      test(function() {
-        var headers = new Headers(headerEntriesDict);
-        var actual = headers.entries();
-        checkIteratorProperties(actual);
-
-        sortedHeaderKeys.forEach(function(key) {
-            entry = actual.next();
-            assert_false(entry.done);
-            assert_equals(entry.value[0], key);
-            assert_equals(entry.value[1], sortedHeaderDict[key]);
-        });
-        assert_true(actual.next().done);
-        assert_true(actual.next().done);
-
-        for (entry of headers.entries())
-            assert_equals(entry[1], sortedHeaderDict[entry[0]]);
-      }, "Check entries method");
-
-      test(function() {
-        var headers = new Headers(headerEntriesDict);
-        var actual = headers[Symbol.iterator]();
-
-        sortedHeaderKeys.forEach(function(key) {
-            entry = actual.next();
-            assert_false(entry.done);
-            assert_equals(entry.value[0], key);
-            assert_equals(entry.value[1], sortedHeaderDict[key]);
-        });
-        assert_true(actual.next().done);
-        assert_true(actual.next().done);
-      }, "Check Symbol.iterator method");
-
-      test(function() {
-        var headers = new Headers(headerEntriesDict);
-        var reference = sortedHeaderKeys[Symbol.iterator]();
-        headers.forEach(function(value, key, container) {
-            assert_equals(headers, container);
-            entry = reference.next();
-            assert_false(entry.done);
-            assert_equals(key, entry.value);
-            assert_equals(value, sortedHeaderDict[entry.value]);
-        });
-        assert_true(reference.next().done);
-      }, "Check forEach method");
-   </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-casing.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-casing.any.js
new file mode 100644
index 0000000..57bec016
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-casing.any.js
@@ -0,0 +1,52 @@
+// META: title=Headers case management
+// META: global=window,worker
+
+var headerDictCase = {"UPPERCASE": "value1",
+                      "lowercase": "value2",
+                      "mixedCase": "value3",
+                      "Content-TYPE": "value4"
+                      };
+
+function checkHeadersCase(originalName, headersToCheck, expectedDict) {
+  var lowCaseName = originalName.toLowerCase();
+  var upCaseName = originalName.toUpperCase();
+  var expectedValue = expectedDict[originalName];
+  assert_equals(headersToCheck.get(originalName), expectedValue,
+      "name: " + originalName + " has value: " + expectedValue);
+  assert_equals(headersToCheck.get(lowCaseName), expectedValue,
+      "name: " + lowCaseName + " has value: " + expectedValue);
+  assert_equals(headersToCheck.get(upCaseName), expectedValue,
+      "name: " + upCaseName + " has value: " + expectedValue);
+}
+
+test(function() {
+  var headers = new Headers(headerDictCase);
+  for (name in headerDictCase)
+    checkHeadersCase(name, headers, headerDictCase)
+}, "Create headers, names use characters with different case");
+
+test(function() {
+  var headers = new Headers();
+  for (name in headerDictCase) {
+    headers.append(name, headerDictCase[name]);
+    checkHeadersCase(name, headers, headerDictCase);
+  }
+}, "Check append method, names use characters with different case");
+
+test(function() {
+  var headers = new Headers();
+  for (name in headerDictCase) {
+    headers.set(name, headerDictCase[name]);
+    checkHeadersCase(name, headers, headerDictCase);
+  }
+}, "Check set method, names use characters with different case");
+
+test(function() {
+  var headers = new Headers();
+  for (name in headerDictCase)
+    headers.set(name, headerDictCase[name]);
+  for (name in headerDictCase)
+    headers.delete(name.toLowerCase());
+  for (name in headerDictCase)
+    assert_false(headers.has(name), "header " + name + " should have been deleted");
+}, "Check delete method, names use characters with different case");
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-casing.html b/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-casing.html
deleted file mode 100644
index 1e505d81..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-casing.html
+++ /dev/null
@@ -1,64 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Headers case management</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#concept-header-list-append">
-    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-  </head>
-  <body>
-    <script>
-      var headerDictCase = {"UPPERCASE": "value1",
-                            "lowercase": "value2",
-                            "mixedCase": "value3",
-                            "Content-TYPE": "value4"
-                           };
-
-      function checkHeadersCase(originalName, headersToCheck, expectedDict) {
-        var lowCaseName = originalName.toLowerCase();
-        var upCaseName = originalName.toUpperCase();
-        var expectedValue = expectedDict[originalName];
-        assert_equals(headersToCheck.get(originalName), expectedValue,
-            "name: " + originalName + " has value: " + expectedValue);
-        assert_equals(headersToCheck.get(lowCaseName), expectedValue,
-            "name: " + lowCaseName + " has value: " + expectedValue);
-        assert_equals(headersToCheck.get(upCaseName), expectedValue,
-            "name: " + upCaseName + " has value: " + expectedValue);
-      }
-
-      test(function() {
-        var headers = new Headers(headerDictCase);
-        for (name in headerDictCase)
-          checkHeadersCase(name, headers, headerDictCase)
-      }, "Create headers, names use characters with different case");
-
-      test(function() {
-        var headers = new Headers();
-        for (name in headerDictCase) {
-          headers.append(name, headerDictCase[name]);
-          checkHeadersCase(name, headers, headerDictCase);
-        }
-      }, "Check append method, names use characters with different case");
-
-      test(function() {
-        var headers = new Headers();
-        for (name in headerDictCase) {
-          headers.set(name, headerDictCase[name]);
-          checkHeadersCase(name, headers, headerDictCase);
-        }
-      }, "Check set method, names use characters with different case");
-
-      test(function() {
-        var headers = new Headers();
-        for (name in headerDictCase)
-          headers.set(name, headerDictCase[name]);
-        for (name in headerDictCase)
-          headers.delete(name.toLowerCase());
-        for (name in headerDictCase)
-          assert_false(headers.has(name), "header " + name + " should have been deleted");
-      }, "Check delete method, names use characters with different case");
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-combine.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-combine.any.js
new file mode 100644
index 0000000..dab4788
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-combine.any.js
@@ -0,0 +1,64 @@
+// META: title=Headers have combined (and sorted) values
+// META: global=window,worker
+
+var headerSeqCombine = [["single", "singleValue"],
+                        ["double", "doubleValue1"],
+                        ["double", "doubleValue2"],
+                        ["triple", "tripleValue1"],
+                        ["triple", "tripleValue2"],
+                        ["triple", "tripleValue3"]
+];
+var expectedDict = {"single": "singleValue",
+                    "double": "doubleValue1, doubleValue2",
+                    "triple": "tripleValue1, tripleValue2, tripleValue3"
+};
+
+test(function() {
+  var headers = new Headers(headerSeqCombine);
+  for (name in expectedDict)
+    assert_equals(headers.get(name), expectedDict[name]);
+}, "Create headers using same name for different values");
+
+test(function() {
+  var headers = new Headers(headerSeqCombine);
+  for (name in expectedDict) {
+    assert_true(headers.has(name), "name: " + name + " has value(s)");
+    headers.delete(name);
+    assert_false(headers.has(name), "name: " + name + " has no value(s) anymore");
+  }
+}, "Check delete and has methods when using same name for different values");
+
+test(function() {
+  var headers = new Headers(headerSeqCombine);
+  for (name in expectedDict) {
+    headers.set(name,"newSingleValue");
+    assert_equals(headers.get(name), "newSingleValue", "name: " + name + " has value: newSingleValue");
+  }
+}, "Check set methods when called with already used name");
+
+test(function() {
+  var headers = new Headers(headerSeqCombine);
+  for (name in expectedDict) {
+    var value = headers.get(name);
+    headers.append(name,"newSingleValue");
+    assert_equals(headers.get(name), (value + ", " + "newSingleValue"));
+  }
+}, "Check append methods when called with already used name");
+
+test(() => {
+  const headers = new Headers([["1", "a"],["1", "b"]]);
+  for(let header of headers) {
+    assert_array_equals(header, ["1", "a, b"]);
+  }
+}, "Iterate combined values");
+
+test(() => {
+  const headers = new Headers([["2", "a"], ["1", "b"], ["2", "b"]]),
+        expected = [["1", "b"], ["2", "a, b"]];
+  let i = 0;
+  for(let header of headers) {
+    assert_array_equals(header, expected[i]);
+    i++;
+  }
+  assert_equals(i, 2);
+}, "Iterate combined values in sorted order")
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-combine.html b/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-combine.html
deleted file mode 100644
index 7341b77..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-combine.html
+++ /dev/null
@@ -1,76 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Headers have combined (and sorted) values</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#headers">
-    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-  </head>
-  <body>
-    <script>
-      var headerSeqCombine = [["single", "singleValue"],
-                              ["double", "doubleValue1"],
-                              ["double", "doubleValue2"],
-                              ["triple", "tripleValue1"],
-                              ["triple", "tripleValue2"],
-                              ["triple", "tripleValue3"]
-      ];
-      var expectedDict = {"single": "singleValue",
-                          "double": "doubleValue1, doubleValue2",
-                          "triple": "tripleValue1, tripleValue2, tripleValue3"
-      };
-
-      test(function() {
-        var headers = new Headers(headerSeqCombine);
-        for (name in expectedDict)
-          assert_equals(headers.get(name), expectedDict[name]);
-      }, "Create headers using same name for different values");
-
-      test(function() {
-        var headers = new Headers(headerSeqCombine);
-        for (name in expectedDict) {
-          assert_true(headers.has(name), "name: " + name + " has value(s)");
-          headers.delete(name);
-          assert_false(headers.has(name), "name: " + name + " has no value(s) anymore");
-        }
-      }, "Check delete and has methods when using same name for different values");
-
-      test(function() {
-        var headers = new Headers(headerSeqCombine);
-        for (name in expectedDict) {
-          headers.set(name,"newSingleValue");
-          assert_equals(headers.get(name), "newSingleValue", "name: " + name + " has value: newSingleValue");
-        }
-      }, "Check set methods when called with already used name");
-
-      test(function() {
-        var headers = new Headers(headerSeqCombine);
-        for (name in expectedDict) {
-          var value = headers.get(name);
-          headers.append(name,"newSingleValue");
-          assert_equals(headers.get(name), (value + ", " + "newSingleValue"));
-        }
-      }, "Check append methods when called with already used name");
-
-      test(() => {
-        const headers = new Headers([["1", "a"],["1", "b"]]);
-        for(let header of headers) {
-          assert_array_equals(header, ["1", "a, b"]);
-        }
-      }, "Iterate combined values");
-
-      test(() => {
-        const headers = new Headers([["2", "a"], ["1", "b"], ["2", "b"]]),
-              expected = [["1", "b"], ["2", "a, b"]];
-        let i = 0;
-        for(let header of headers) {
-          assert_array_equals(header, expected[i]);
-          i++;
-        }
-        assert_equals(i, 2);
-      }, "Iterate combined values in sorted order")
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-errors.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-errors.any.js
new file mode 100644
index 0000000..ab8a118
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-errors.any.js
@@ -0,0 +1,94 @@
+// META: title=Headers errors
+// META: global=window,worker
+
+test(function() {
+  assert_throws_js(TypeError, function() { new Headers([["name"]]); });
+}, "Create headers giving an array having one string as init argument");
+
+test(function() {
+  assert_throws_js(TypeError, function() { new Headers([["invalid", "invalidValue1", "invalidValue2"]]); });
+}, "Create headers giving an array having three strings as init argument");
+
+test(function() {
+  assert_throws_js(TypeError, function() { new Headers([["invalidĀ", "Value1"]]); });
+}, "Create headers giving bad header name as init argument");
+
+test(function() {
+  assert_throws_js(TypeError, function() { new Headers([["name", "invalidValueĀ"]]); });
+}, "Create headers giving bad header value as init argument");
+
+var badNames = ["invalidĀ", {}];
+var badValues = ["invalidĀ"];
+
+badNames.forEach(function(name) {
+  test(function() {
+    var headers = new Headers();
+    assert_throws_js(TypeError, function() { headers.get(name); });
+  }, "Check headers get with an invalid name " + name);
+});
+
+badNames.forEach(function(name) {
+  test(function() {
+    var headers = new Headers();
+    assert_throws_js(TypeError, function() { headers.delete(name); });
+  }, "Check headers delete with an invalid name " + name);
+});
+
+badNames.forEach(function(name) {
+  test(function() {
+    var headers = new Headers();
+    assert_throws_js(TypeError, function() { headers.has(name); });
+  }, "Check headers has with an invalid name " + name);
+});
+
+badNames.forEach(function(name) {
+  test(function() {
+    var headers = new Headers();
+    assert_throws_js(TypeError, function() { headers.set(name, "Value1"); });
+  }, "Check headers set with an invalid name " + name);
+});
+
+badValues.forEach(function(value) {
+  test(function() {
+    var headers = new Headers();
+    assert_throws_js(TypeError, function() { headers.set("name", value); });
+  }, "Check headers set with an invalid value " + value);
+});
+
+badNames.forEach(function(name) {
+  test(function() {
+    var headers = new Headers();
+    assert_throws_js(TypeError, function() { headers.append("invalidĀ", "Value1"); });
+  }, "Check headers append with an invalid name " + name);
+});
+
+badValues.forEach(function(value) {
+  test(function() {
+    var headers = new Headers();
+    assert_throws_js(TypeError, function() { headers.append("name", value); });
+  }, "Check headers append with an invalid value " + value);
+});
+
+test(function() {
+  var headers = new Headers([["name", "value"]]);
+  assert_throws_js(TypeError, function() { headers.forEach(); });
+  assert_throws_js(TypeError, function() { headers.forEach(undefined); });
+  assert_throws_js(TypeError, function() { headers.forEach(1); });
+}, "Headers forEach throws if argument is not callable");
+
+test(function() {
+  var headers = new Headers([["name1", "value1"], ["name2", "value2"], ["name3", "value3"]]);
+  var counter = 0;
+  try {
+      headers.forEach(function(value, name) {
+          counter++;
+          if (name == "name2")
+                throw "error";
+      });
+  } catch (e) {
+      assert_equals(counter, 2);
+      assert_equals(e, "error");
+      return;
+  }
+  assert_unreached();
+}, "Headers forEach loop should stop if callback is throwing exception");
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-errors.html b/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-errors.html
deleted file mode 100644
index 7f9916d8..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-errors.html
+++ /dev/null
@@ -1,107 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Headers errors</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#headers">
-    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-  </head>
-  <body>
-    <script>
-
-      test(function() {
-        assert_throws_js(TypeError, function() { new Headers([["name"]]); });
-      }, "Create headers giving an array having one string as init argument");
-
-      test(function() {
-        assert_throws_js(TypeError, function() { new Headers([["invalid", "invalidValue1", "invalidValue2"]]); });
-      }, "Create headers giving an array having three strings as init argument");
-
-      test(function() {
-        assert_throws_js(TypeError, function() { new Headers([["invalidĀ", "Value1"]]); });
-      }, "Create headers giving bad header name as init argument");
-
-      test(function() {
-        assert_throws_js(TypeError, function() { new Headers([["name", "invalidValueĀ"]]); });
-      }, "Create headers giving bad header value as init argument");
-
-      var badNames = ["invalidĀ", {}];
-      var badValues = ["invalidĀ"];
-
-      badNames.forEach(function(name) {
-        test(function() {
-          var headers = new Headers();
-          assert_throws_js(TypeError, function() { headers.get(name); });
-        }, "Check headers get with an invalid name " + name);
-      });
-
-      badNames.forEach(function(name) {
-        test(function() {
-          var headers = new Headers();
-          assert_throws_js(TypeError, function() { headers.delete(name); });
-        }, "Check headers delete with an invalid name " + name);
-      });
-
-      badNames.forEach(function(name) {
-        test(function() {
-          var headers = new Headers();
-          assert_throws_js(TypeError, function() { headers.has(name); });
-        }, "Check headers has with an invalid name " + name);
-      });
-
-      badNames.forEach(function(name) {
-        test(function() {
-          var headers = new Headers();
-          assert_throws_js(TypeError, function() { headers.set(name, "Value1"); });
-        }, "Check headers set with an invalid name " + name);
-      });
-
-      badValues.forEach(function(value) {
-        test(function() {
-          var headers = new Headers();
-          assert_throws_js(TypeError, function() { headers.set("name", value); });
-        }, "Check headers set with an invalid value " + value);
-      });
-
-      badNames.forEach(function(name) {
-        test(function() {
-          var headers = new Headers();
-          assert_throws_js(TypeError, function() { headers.append("invalidĀ", "Value1"); });
-        }, "Check headers append with an invalid name " + name);
-      });
-
-      badValues.forEach(function(value) {
-        test(function() {
-          var headers = new Headers();
-          assert_throws_js(TypeError, function() { headers.append("name", value); });
-        }, "Check headers append with an invalid value " + value);
-      });
-
-      test(function() {
-        var headers = new Headers([["name", "value"]]);
-        assert_throws_js(TypeError, function() { headers.forEach(); });
-        assert_throws_js(TypeError, function() { headers.forEach(undefined); });
-        assert_throws_js(TypeError, function() { headers.forEach(1); });
-      }, "Headers forEach throws if argument is not callable");
-
-      test(function() {
-        var headers = new Headers([["name1", "value1"], ["name2", "value2"], ["name3", "value3"]]);
-        var counter = 0;
-        try {
-            headers.forEach(function(value, name) {
-                counter++;
-                if (name == "name2")
-                     throw "error";
-            });
-        } catch (e) {
-            assert_equals(counter, 2);
-            assert_equals(e, "error");
-            return;
-        }
-        assert_unreached();
-      }, "Headers forEach loop should stop if callback is throwing exception");
-   </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-no-cors.window.js b/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-no-cors.any.js
similarity index 97%
rename from third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-no-cors.window.js
rename to third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-no-cors.any.js
index 2f3a819ba..c09658e 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-no-cors.window.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-no-cors.any.js
@@ -1,3 +1,5 @@
+// META: global=window,worker
+
 promise_test(() => fetch("../cors/resources/not-cors-safelisted.json").then(res => res.json().then(runTests)), "Loading data…");
 
 const longValue = "s".repeat(127);
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-normalize.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-normalize.any.js
new file mode 100644
index 0000000..5ebd7ae9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-normalize.any.js
@@ -0,0 +1,35 @@
+// META: title=Headers normalize values
+// META: global=window,worker
+
+var headerDictWS = {"name1": " space ",
+                    "name2": "\ttab\t",
+                    "name3": " spaceAndTab\t",
+                    "name4": "\r\n newLine", //obs-fold cases
+                    "name5": "newLine\r\n ",
+                    "name6": "\r\n\tnewLine",
+                    };
+
+test(function() {
+  var headers = new Headers(headerDictWS);
+  for (name in headerDictWS)
+    assert_equals(headers.get(name), headerDictWS[name].trim(),
+      "name: " + name + " has normalized value: " + headerDictWS[name].trim());
+}, "Create headers with not normalized values");
+
+test(function() {
+  var headers = new Headers();
+  for (name in headerDictWS) {
+    headers.append(name, headerDictWS[name]);
+    assert_equals(headers.get(name), headerDictWS[name].trim(),
+      "name: " + name + " has value: " + headerDictWS[name].trim());
+  }
+}, "Check append method with not normalized values");
+
+test(function() {
+  var headers = new Headers();
+  for (name in headerDictWS) {
+    headers.set(name, headerDictWS[name]);
+    assert_equals(headers.get(name), headerDictWS[name].trim(),
+      "name: " + name + " has value: " + headerDictWS[name].trim());
+  }
+}, "Check set method with not normalized values");
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-normalize.html b/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-normalize.html
deleted file mode 100644
index 6dfcf9d..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-normalize.html
+++ /dev/null
@@ -1,47 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Headers normalize values</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#concept-header-value-normalize">
-    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-  </head>
-  <body>
-    <script>
-      var headerDictWS = {"name1": " space ",
-                          "name2": "\ttab\t",
-                          "name3": " spaceAndTab\t",
-                          "name4": "\r\n newLine", //obs-fold cases
-                          "name5": "newLine\r\n ",
-                          "name6": "\r\n\tnewLine",
-                         };
-
-      test(function() {
-        var headers = new Headers(headerDictWS);
-        for (name in headerDictWS)
-          assert_equals(headers.get(name), headerDictWS[name].trim(),
-            "name: " + name + " has normalized value: " + headerDictWS[name].trim());
-      }, "Create headers with not normalized values");
-
-      test(function() {
-        var headers = new Headers();
-        for (name in headerDictWS) {
-          headers.append(name, headerDictWS[name]);
-          assert_equals(headers.get(name), headerDictWS[name].trim(),
-            "name: " + name + " has value: " + headerDictWS[name].trim());
-        }
-      }, "Check append method with not normalized values");
-
-      test(function() {
-        var headers = new Headers();
-        for (name in headerDictWS) {
-          headers.set(name, headerDictWS[name]);
-          assert_equals(headers.get(name), headerDictWS[name].trim(),
-            "name: " + name + " has value: " + headerDictWS[name].trim());
-        }
-      }, "Check set method with not normalized values");
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-record.html b/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-record.any.js
similarity index 98%
rename from third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-record.html
rename to third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-record.any.js
index c7d8d99a..55036c2 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-record.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-record.any.js
@@ -1,9 +1,5 @@
-<!doctype html>
-<meta charset=utf-8>
-<title></title>
-<script src=/resources/testharness.js></script>
-<script src=/resources/testharnessreport.js></script>
-<script>
+// META: global=window,worker
+
 var log = [];
 function clearLog() {
   log = [];
@@ -357,4 +353,3 @@
   assert_true(h.has("c"));
   assert_equals(h.get("c"), "d");
 }, "Operation with non-enumerable Symbol keys");
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-structure.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-structure.any.js
new file mode 100644
index 0000000..c47290e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-structure.any.js
@@ -0,0 +1,18 @@
+// META: title=Headers basic
+// META: global=window,worker
+
+var headers = new Headers();
+var methods = ["append",
+                "delete",
+                "get",
+                "has",
+                "set",
+                //Headers is iterable
+                "entries",
+                "keys",
+                "values"
+                ];
+for (var idx in methods)
+  test(function() {
+    assert_true(methods[idx] in headers, "headers has " + methods[idx] + " method");
+  }, "Headers has " + methods[idx] + " method");
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-structure.html b/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-structure.html
deleted file mode 100644
index 9448e450..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-structure.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Headers basic</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#headers">
-    <meta name="help" href="https://heycam.github.io/webidl/#idl-iterable">
-    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-  </head>
-  <body>
-    <script>
-        var headers = new Headers();
-        var methods = ["append",
-                       "delete",
-                       "get",
-                       "has",
-                       "set",
-                       //Headers is iterable
-                       "entries",
-                       "keys",
-                       "values"
-                       ];
-        for (var idx in methods)
-          test(function() {
-            assert_true(methods[idx] in headers, "headers has " + methods[idx] + " method");
-          }, "Headers has " + methods[idx] + " method");
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-back-to-original-origin.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-back-to-original-origin.any.js
index 32d413cb..74d731f2 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-back-to-original-origin.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-back-to-original-origin.any.js
@@ -1,3 +1,4 @@
+// META: global=window,worker
 // META: script=/common/get-host-info.sub.js
 
 const BASE = location.href;
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-count.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-count.any.js
index 4ce080e..dda5d7f 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-count.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-count.any.js
@@ -1,3 +1,4 @@
+// META: global=window,worker
 // META: script=../resources/utils.js
 // META: script=/common/utils.js
 // META: timeout=long
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-empty-location.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-empty-location.any.js
index 79b04f5..487f4d42e 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-empty-location.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-empty-location.any.js
@@ -1,3 +1,4 @@
+// META: global=window,worker
 // META: script=../resources/utils.js
 
 // Tests receiving a redirect response with a Location header with an empty
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-empty-location.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-empty-location.any.serviceworker-expected.txt
new file mode 100644
index 0000000..9b61ad26
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-empty-location.any.serviceworker-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL redirect response with empty Location, follow mode assert_unreached: Should have rejected: undefined Reached unreachable code
+PASS redirect response with empty Location, manual mode
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-empty-location.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-empty-location.any.sharedworker-expected.txt
new file mode 100644
index 0000000..9b61ad26
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-empty-location.any.sharedworker-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL redirect response with empty Location, follow mode assert_unreached: Should have rejected: undefined Reached unreachable code
+PASS redirect response with empty Location, manual mode
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-location-escape.tentative.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-location-escape.tentative.any.js
index 2975e5f..779ad70 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-location-escape.tentative.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-location-escape.tentative.any.js
@@ -1,3 +1,4 @@
+// META: global=window,worker
 // META: script=../resources/utils.js
 
 // See https://github.com/whatwg/fetch/issues/883 for the behavior covered by
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-location.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-location.any.js
index 91da260..5cb6cc2 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-location.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-location.any.js
@@ -1,3 +1,4 @@
+// META: global=window,worker
 // META: script=../resources/utils.js
 
 function redirectLocation(desc, redirectUrl, redirectLocation, redirectStatus, redirectMode, shouldPass) {
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-location.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-location.any.serviceworker-expected.txt
new file mode 100644
index 0000000..2195cb15
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-location.any.serviceworker-expected.txt
@@ -0,0 +1,33 @@
+This is a testharness.js-based test.
+PASS Redirect 301 in "follow" mode without location
+PASS Redirect 301 in "manual" mode without location
+PASS Redirect 301 in "follow" mode with invalid location
+PASS Redirect 301 in "manual" mode with invalid location
+PASS Redirect 301 in "follow" mode with data location
+FAIL Redirect 301 in "manual" mode with data location promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch"
+PASS Redirect 302 in "follow" mode without location
+PASS Redirect 302 in "manual" mode without location
+PASS Redirect 302 in "follow" mode with invalid location
+PASS Redirect 302 in "manual" mode with invalid location
+PASS Redirect 302 in "follow" mode with data location
+FAIL Redirect 302 in "manual" mode with data location promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch"
+PASS Redirect 303 in "follow" mode without location
+PASS Redirect 303 in "manual" mode without location
+PASS Redirect 303 in "follow" mode with invalid location
+PASS Redirect 303 in "manual" mode with invalid location
+PASS Redirect 303 in "follow" mode with data location
+FAIL Redirect 303 in "manual" mode with data location promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch"
+PASS Redirect 307 in "follow" mode without location
+PASS Redirect 307 in "manual" mode without location
+PASS Redirect 307 in "follow" mode with invalid location
+PASS Redirect 307 in "manual" mode with invalid location
+PASS Redirect 307 in "follow" mode with data location
+FAIL Redirect 307 in "manual" mode with data location promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch"
+PASS Redirect 308 in "follow" mode without location
+PASS Redirect 308 in "manual" mode without location
+PASS Redirect 308 in "follow" mode with invalid location
+PASS Redirect 308 in "manual" mode with invalid location
+PASS Redirect 308 in "follow" mode with data location
+FAIL Redirect 308 in "manual" mode with data location promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-location.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-location.any.sharedworker-expected.txt
new file mode 100644
index 0000000..2195cb15
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-location.any.sharedworker-expected.txt
@@ -0,0 +1,33 @@
+This is a testharness.js-based test.
+PASS Redirect 301 in "follow" mode without location
+PASS Redirect 301 in "manual" mode without location
+PASS Redirect 301 in "follow" mode with invalid location
+PASS Redirect 301 in "manual" mode with invalid location
+PASS Redirect 301 in "follow" mode with data location
+FAIL Redirect 301 in "manual" mode with data location promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch"
+PASS Redirect 302 in "follow" mode without location
+PASS Redirect 302 in "manual" mode without location
+PASS Redirect 302 in "follow" mode with invalid location
+PASS Redirect 302 in "manual" mode with invalid location
+PASS Redirect 302 in "follow" mode with data location
+FAIL Redirect 302 in "manual" mode with data location promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch"
+PASS Redirect 303 in "follow" mode without location
+PASS Redirect 303 in "manual" mode without location
+PASS Redirect 303 in "follow" mode with invalid location
+PASS Redirect 303 in "manual" mode with invalid location
+PASS Redirect 303 in "follow" mode with data location
+FAIL Redirect 303 in "manual" mode with data location promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch"
+PASS Redirect 307 in "follow" mode without location
+PASS Redirect 307 in "manual" mode without location
+PASS Redirect 307 in "follow" mode with invalid location
+PASS Redirect 307 in "manual" mode with invalid location
+PASS Redirect 307 in "follow" mode with data location
+FAIL Redirect 307 in "manual" mode with data location promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch"
+PASS Redirect 308 in "follow" mode without location
+PASS Redirect 308 in "manual" mode without location
+PASS Redirect 308 in "follow" mode with invalid location
+PASS Redirect 308 in "manual" mode with invalid location
+PASS Redirect 308 in "follow" mode with data location
+FAIL Redirect 308 in "manual" mode with data location promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-method.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-method.any.js
index b24bb092..9fe086a 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-method.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-method.any.js
@@ -1,3 +1,4 @@
+// META: global=window,worker
 // META: script=../resources/utils.js
 
 // Creates a promise_test that fetches a URL that returns a redirect response.
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-schemes.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-schemes.any.js
new file mode 100644
index 0000000..31ec124fd
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-schemes.any.js
@@ -0,0 +1,19 @@
+// META: title=Fetch: handling different schemes in redirects
+// META: global=window,worker
+// META: script=/common/get-host-info.sub.js
+
+// All non-HTTP(S) schemes cannot survive redirects
+var url = "../resources/redirect.py?location=";
+var tests = [
+  url + "mailto:a@a.com",
+  url + "data:,HI",
+  url + "facetime:a@a.org",
+  url + "about:blank",
+  url + "about:unicorn",
+  url + "blob:djfksfjs"
+];
+tests.forEach(function(url) {
+  promise_test(function(test) {
+    return promise_rejects_js(test, TypeError, fetch(url))
+  })
+})
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-schemes.html b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-schemes.html
deleted file mode 100644
index 2aa7bce..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-schemes.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<!doctype html>
-<meta charset="utf-8">
-<title>Fetch: handling different schemes in redirects</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<div id=log></div>
-<script>
-  // All non-HTTP(S) schemes cannot survive redirects
-  var url = "../resources/redirect.py?location=";
-  var tests = [
-    url + "mailto:a@a.com",
-    url + "data:,HI",
-    url + "facetime:a@a.org",
-    url + "about:blank",
-    url + "about:unicorn",
-    url + "blob:djfksfjs"
-  ];
-  tests.forEach(function(url) {
-    promise_test(function(test) {
-      return promise_rejects_js(test, TypeError, fetch(url))
-    })
-  })
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-to-dataurl.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-to-dataurl.any.js
index 2f36f0b..9d0f147 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-to-dataurl.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-to-dataurl.any.js
@@ -1,3 +1,4 @@
+// META: global=window,worker
 // META: script=/common/get-host-info.sub.js
 
 var dataURL = "data:text/plain;base64,cmVzcG9uc2UncyBib2R5";
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-bad-port.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-bad-port.any.js
new file mode 100644
index 0000000..8614192
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-bad-port.any.js
@@ -0,0 +1,79 @@
+// META: global=window,worker
+
+// list of bad ports according to
+// https://fetch.spec.whatwg.org/#port-blocking
+var BLOCKED_PORTS_LIST = [
+    1,    // tcpmux
+    7,    // echo
+    9,    // discard
+    11,   // systat
+    13,   // daytime
+    15,   // netstat
+    17,   // qotd
+    19,   // chargen
+    20,   // ftp-data
+    21,   // ftp
+    22,   // ssh
+    23,   // telnet
+    25,   // smtp
+    37,   // time
+    42,   // name
+    43,   // nicname
+    53,   // domain
+    77,   // priv-rjs
+    79,   // finger
+    87,   // ttylink
+    95,   // supdup
+    101,  // hostriame
+    102,  // iso-tsap
+    103,  // gppitnp
+    104,  // acr-nema
+    109,  // pop2
+    110,  // pop3
+    111,  // sunrpc
+    113,  // auth
+    115,  // sftp
+    117,  // uucp-path
+    119,  // nntp
+    123,  // ntp
+    135,  // loc-srv / epmap
+    139,  // netbios
+    143,  // imap2
+    179,  // bgp
+    389,  // ldap
+    427,  // afp (alternate)
+    465,  // smtp (alternate)
+    512,  // print / exec
+    513,  // login
+    514,  // shell
+    515,  // printer
+    526,  // tempo
+    530,  // courier
+    531,  // chat
+    532,  // netnews
+    540,  // uucp
+    548,  // afp
+    556,  // remotefs
+    563,  // nntp+ssl
+    587,  // smtp (outgoing)
+    601,  // syslog-conn
+    636,  // ldap+ssl
+    993,  // ldap+ssl
+    995,  // pop3+ssl
+    2049, // nfs
+    3659, // apple-sasl
+    4045, // lockd
+    6000, // x11
+    6665, // irc (alternate)
+    6666, // irc (alternate)
+    6667, // irc (default)
+    6668, // irc (alternate)
+    6669, // irc (alternate)
+    6697, // irc+tls
+];
+
+BLOCKED_PORTS_LIST.map(function(a){
+    promise_test(function(t){
+        return promise_rejects_js(t, TypeError, fetch("http://example.com:" + a))
+    }, 'Request on bad port ' + a + ' should throw TypeError.');
+});
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-bad-port.html b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-bad-port.html
deleted file mode 100644
index d1d42cc..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-bad-port.html
+++ /dev/null
@@ -1,85 +0,0 @@
-<!doctype html>
-<meta charset="utf-8">
-<title></title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script>
-
-    // list of bad ports according to
-    // https://fetch.spec.whatwg.org/#port-blocking
-    var BLOCKED_PORTS_LIST = [
-        1,    // tcpmux
-        7,    // echo
-        9,    // discard
-        11,   // systat
-        13,   // daytime
-        15,   // netstat
-        17,   // qotd
-        19,   // chargen
-        20,   // ftp-data
-        21,   // ftp
-        22,   // ssh
-        23,   // telnet
-        25,   // smtp
-        37,   // time
-        42,   // name
-        43,   // nicname
-        53,   // domain
-        77,   // priv-rjs
-        79,   // finger
-        87,   // ttylink
-        95,   // supdup
-        101,  // hostriame
-        102,  // iso-tsap
-        103,  // gppitnp
-        104,  // acr-nema
-        109,  // pop2
-        110,  // pop3
-        111,  // sunrpc
-        113,  // auth
-        115,  // sftp
-        117,  // uucp-path
-        119,  // nntp
-        123,  // ntp
-        135,  // loc-srv / epmap
-        139,  // netbios
-        143,  // imap2
-        179,  // bgp
-        389,  // ldap
-        427,  // afp (alternate)
-        465,  // smtp (alternate)
-        512,  // print / exec
-        513,  // login
-        514,  // shell
-        515,  // printer
-        526,  // tempo
-        530,  // courier
-        531,  // chat
-        532,  // netnews
-        540,  // uucp
-        548,  // afp
-        556,  // remotefs
-        563,  // nntp+ssl
-        587,  // smtp (outgoing)
-        601,  // syslog-conn
-        636,  // ldap+ssl
-        993,  // ldap+ssl
-        995,  // pop3+ssl
-        2049, // nfs
-        3659, // apple-sasl
-        4045, // lockd
-        6000, // x11
-        6665, // irc (alternate)
-        6666, // irc (alternate)
-        6667, // irc (default)
-        6668, // irc (alternate)
-        6669, // irc (alternate)
-        6697, // irc+tls
-    ];
-
-    BLOCKED_PORTS_LIST.map(function(a){
-    	promise_test(function(t){
-            return promise_rejects_js(t, TypeError, fetch("http://example.com:" + a))
-        }, 'Request on bad port ' + a + ' should throw TypeError.');
-    });
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-default-conditional.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-default-conditional.any.js
new file mode 100644
index 0000000..c5b2001
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-default-conditional.any.js
@@ -0,0 +1,170 @@
+// META: global=window,worker
+// META: title=Request cache - default with conditional requests
+// META: timeout=long
+// META: script=/common/utils.js
+// META: script=/common/get-host-info.sub.js
+// META: script=request-cache.js
+
+var tests = [
+  {
+    name: 'RequestCache "default" mode with an If-Modified-Since header (following a request without additional headers) is treated similarly to "no-store"',
+    state: "stale",
+    request_cache: ["default", "default"],
+    request_headers: [{}, {"If-Modified-Since": now.toGMTString()}],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [false, true],
+  },
+  {
+    name: 'RequestCache "default" mode with an If-Modified-Since header (following a request without additional headers) is treated similarly to "no-store"',
+    state: "fresh",
+    request_cache: ["default", "default"],
+    request_headers: [{}, {"If-Modified-Since": now.toGMTString()}],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [false, true],
+  },
+  {
+    name: 'RequestCache "default" mode with an If-Modified-Since header is treated similarly to "no-store"',
+    state: "stale",
+    request_cache: ["default", "default"],
+    request_headers: [{"If-Modified-Since": now.toGMTString()}, {}],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [true, false],
+  },
+  {
+    name: 'RequestCache "default" mode with an If-Modified-Since header is treated similarly to "no-store"',
+    state: "fresh",
+    request_cache: ["default", "default"],
+    request_headers: [{"If-Modified-Since": now.toGMTString()}, {}],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [true, false],
+  },
+  {
+    name: 'RequestCache "default" mode with an If-None-Match header (following a request without additional headers) is treated similarly to "no-store"',
+    state: "stale",
+    request_cache: ["default", "default"],
+    request_headers: [{}, {"If-None-Match": '"foo"'}],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [false, true],
+  },
+  {
+    name: 'RequestCache "default" mode with an If-None-Match header (following a request without additional headers) is treated similarly to "no-store"',
+    state: "fresh",
+    request_cache: ["default", "default"],
+    request_headers: [{}, {"If-None-Match": '"foo"'}],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [false, true],
+  },
+  {
+    name: 'RequestCache "default" mode with an If-None-Match header is treated similarly to "no-store"',
+    state: "stale",
+    request_cache: ["default", "default"],
+    request_headers: [{"If-None-Match": '"foo"'}, {}],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [true, false],
+  },
+  {
+    name: 'RequestCache "default" mode with an If-None-Match header is treated similarly to "no-store"',
+    state: "fresh",
+    request_cache: ["default", "default"],
+    request_headers: [{"If-None-Match": '"foo"'}, {}],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [true, false],
+  },
+  {
+    name: 'RequestCache "default" mode with an If-Unmodified-Since header (following a request without additional headers) is treated similarly to "no-store"',
+    state: "stale",
+    request_cache: ["default", "default"],
+    request_headers: [{}, {"If-Unmodified-Since": now.toGMTString()}],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [false, true],
+  },
+  {
+    name: 'RequestCache "default" mode with an If-Unmodified-Since header (following a request without additional headers) is treated similarly to "no-store"',
+    state: "fresh",
+    request_cache: ["default", "default"],
+    request_headers: [{}, {"If-Unmodified-Since": now.toGMTString()}],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [false, true],
+  },
+  {
+    name: 'RequestCache "default" mode with an If-Unmodified-Since header is treated similarly to "no-store"',
+    state: "stale",
+    request_cache: ["default", "default"],
+    request_headers: [{"If-Unmodified-Since": now.toGMTString()}, {}],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [true, false],
+  },
+  {
+    name: 'RequestCache "default" mode with an If-Unmodified-Since header is treated similarly to "no-store"',
+    state: "fresh",
+    request_cache: ["default", "default"],
+    request_headers: [{"If-Unmodified-Since": now.toGMTString()}, {}],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [true, false],
+  },
+  {
+    name: 'RequestCache "default" mode with an If-Match header (following a request without additional headers) is treated similarly to "no-store"',
+    state: "stale",
+    request_cache: ["default", "default"],
+    request_headers: [{}, {"If-Match": '"foo"'}],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [false, true],
+  },
+  {
+    name: 'RequestCache "default" mode with an If-Match header (following a request without additional headers) is treated similarly to "no-store"',
+    state: "fresh",
+    request_cache: ["default", "default"],
+    request_headers: [{}, {"If-Match": '"foo"'}],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [false, true],
+  },
+  {
+    name: 'RequestCache "default" mode with an If-Match header is treated similarly to "no-store"',
+    state: "stale",
+    request_cache: ["default", "default"],
+    request_headers: [{"If-Match": '"foo"'}, {}],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [true, false],
+  },
+  {
+    name: 'RequestCache "default" mode with an If-Match header is treated similarly to "no-store"',
+    state: "fresh",
+    request_cache: ["default", "default"],
+    request_headers: [{"If-Match": '"foo"'}, {}],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [true, false],
+  },
+  {
+    name: 'RequestCache "default" mode with an If-Range header (following a request without additional headers) is treated similarly to "no-store"',
+    state: "stale",
+    request_cache: ["default", "default"],
+    request_headers: [{}, {"If-Range": '"foo"'}],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [false, true],
+  },
+  {
+    name: 'RequestCache "default" mode with an If-Range header (following a request without additional headers) is treated similarly to "no-store"',
+    state: "fresh",
+    request_cache: ["default", "default"],
+    request_headers: [{}, {"If-Range": '"foo"'}],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [false, true],
+  },
+  {
+    name: 'RequestCache "default" mode with an If-Range header is treated similarly to "no-store"',
+    state: "stale",
+    request_cache: ["default", "default"],
+    request_headers: [{"If-Range": '"foo"'}, {}],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [true, false],
+  },
+  {
+    name: 'RequestCache "default" mode with an If-Range header is treated similarly to "no-store"',
+    state: "fresh",
+    request_cache: ["default", "default"],
+    request_headers: [{"If-Range": '"foo"'}, {}],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [true, false],
+  },
+];
+run_tests(tests);
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-default-conditional.html b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-default-conditional.html
deleted file mode 100644
index 145b3026..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-default-conditional.html
+++ /dev/null
@@ -1,181 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Request cache - default with conditional requests</title>
-    <meta name="timeout" content="long">
-    <meta name="help" href="https://fetch.spec.whatwg.org/#request">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <script src="/common/utils.js"></script>
-    <script src="/common/get-host-info.sub.js"></script>
-    <script src="request-cache.js"></script>
-  </head>
-  <body>
-    <script>
-    var tests = [
-      {
-        name: 'RequestCache "default" mode with an If-Modified-Since header (following a request without additional headers) is treated similarly to "no-store"',
-        state: "stale",
-        request_cache: ["default", "default"],
-        request_headers: [{}, {"If-Modified-Since": now.toGMTString()}],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [false, true],
-      },
-      {
-        name: 'RequestCache "default" mode with an If-Modified-Since header (following a request without additional headers) is treated similarly to "no-store"',
-        state: "fresh",
-        request_cache: ["default", "default"],
-        request_headers: [{}, {"If-Modified-Since": now.toGMTString()}],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [false, true],
-      },
-      {
-        name: 'RequestCache "default" mode with an If-Modified-Since header is treated similarly to "no-store"',
-        state: "stale",
-        request_cache: ["default", "default"],
-        request_headers: [{"If-Modified-Since": now.toGMTString()}, {}],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [true, false],
-      },
-      {
-        name: 'RequestCache "default" mode with an If-Modified-Since header is treated similarly to "no-store"',
-        state: "fresh",
-        request_cache: ["default", "default"],
-        request_headers: [{"If-Modified-Since": now.toGMTString()}, {}],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [true, false],
-      },
-      {
-        name: 'RequestCache "default" mode with an If-None-Match header (following a request without additional headers) is treated similarly to "no-store"',
-        state: "stale",
-        request_cache: ["default", "default"],
-        request_headers: [{}, {"If-None-Match": '"foo"'}],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [false, true],
-      },
-      {
-        name: 'RequestCache "default" mode with an If-None-Match header (following a request without additional headers) is treated similarly to "no-store"',
-        state: "fresh",
-        request_cache: ["default", "default"],
-        request_headers: [{}, {"If-None-Match": '"foo"'}],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [false, true],
-      },
-      {
-        name: 'RequestCache "default" mode with an If-None-Match header is treated similarly to "no-store"',
-        state: "stale",
-        request_cache: ["default", "default"],
-        request_headers: [{"If-None-Match": '"foo"'}, {}],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [true, false],
-      },
-      {
-        name: 'RequestCache "default" mode with an If-None-Match header is treated similarly to "no-store"',
-        state: "fresh",
-        request_cache: ["default", "default"],
-        request_headers: [{"If-None-Match": '"foo"'}, {}],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [true, false],
-      },
-      {
-        name: 'RequestCache "default" mode with an If-Unmodified-Since header (following a request without additional headers) is treated similarly to "no-store"',
-        state: "stale",
-        request_cache: ["default", "default"],
-        request_headers: [{}, {"If-Unmodified-Since": now.toGMTString()}],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [false, true],
-      },
-      {
-        name: 'RequestCache "default" mode with an If-Unmodified-Since header (following a request without additional headers) is treated similarly to "no-store"',
-        state: "fresh",
-        request_cache: ["default", "default"],
-        request_headers: [{}, {"If-Unmodified-Since": now.toGMTString()}],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [false, true],
-      },
-      {
-        name: 'RequestCache "default" mode with an If-Unmodified-Since header is treated similarly to "no-store"',
-        state: "stale",
-        request_cache: ["default", "default"],
-        request_headers: [{"If-Unmodified-Since": now.toGMTString()}, {}],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [true, false],
-      },
-      {
-        name: 'RequestCache "default" mode with an If-Unmodified-Since header is treated similarly to "no-store"',
-        state: "fresh",
-        request_cache: ["default", "default"],
-        request_headers: [{"If-Unmodified-Since": now.toGMTString()}, {}],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [true, false],
-      },
-      {
-        name: 'RequestCache "default" mode with an If-Match header (following a request without additional headers) is treated similarly to "no-store"',
-        state: "stale",
-        request_cache: ["default", "default"],
-        request_headers: [{}, {"If-Match": '"foo"'}],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [false, true],
-      },
-      {
-        name: 'RequestCache "default" mode with an If-Match header (following a request without additional headers) is treated similarly to "no-store"',
-        state: "fresh",
-        request_cache: ["default", "default"],
-        request_headers: [{}, {"If-Match": '"foo"'}],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [false, true],
-      },
-      {
-        name: 'RequestCache "default" mode with an If-Match header is treated similarly to "no-store"',
-        state: "stale",
-        request_cache: ["default", "default"],
-        request_headers: [{"If-Match": '"foo"'}, {}],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [true, false],
-      },
-      {
-        name: 'RequestCache "default" mode with an If-Match header is treated similarly to "no-store"',
-        state: "fresh",
-        request_cache: ["default", "default"],
-        request_headers: [{"If-Match": '"foo"'}, {}],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [true, false],
-      },
-      {
-        name: 'RequestCache "default" mode with an If-Range header (following a request without additional headers) is treated similarly to "no-store"',
-        state: "stale",
-        request_cache: ["default", "default"],
-        request_headers: [{}, {"If-Range": '"foo"'}],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [false, true],
-      },
-      {
-        name: 'RequestCache "default" mode with an If-Range header (following a request without additional headers) is treated similarly to "no-store"',
-        state: "fresh",
-        request_cache: ["default", "default"],
-        request_headers: [{}, {"If-Range": '"foo"'}],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [false, true],
-      },
-      {
-        name: 'RequestCache "default" mode with an If-Range header is treated similarly to "no-store"',
-        state: "stale",
-        request_cache: ["default", "default"],
-        request_headers: [{"If-Range": '"foo"'}, {}],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [true, false],
-      },
-      {
-        name: 'RequestCache "default" mode with an If-Range header is treated similarly to "no-store"',
-        state: "fresh",
-        request_cache: ["default", "default"],
-        request_headers: [{"If-Range": '"foo"'}, {}],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [true, false],
-      },
-    ];
-    run_tests(tests);
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-default.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-default.any.js
new file mode 100644
index 0000000..dfa8369
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-default.any.js
@@ -0,0 +1,39 @@
+// META: global=window,worker
+// META: title=Request cache - default
+// META: script=/common/utils.js
+// META: script=/common/get-host-info.sub.js
+// META: script=request-cache.js
+
+var tests = [
+  {
+    name: 'RequestCache "default" mode checks the cache for previously cached content and goes to the network for stale responses',
+    state: "stale",
+    request_cache: ["default", "default"],
+    expected_validation_headers: [false, true],
+    expected_no_cache_headers: [false, false],
+  },
+  {
+    name: 'RequestCache "default" mode checks the cache for previously cached content and avoids going to the network if a fresh response exists',
+    state: "fresh",
+    request_cache: ["default", "default"],
+    expected_validation_headers: [false],
+    expected_no_cache_headers: [false],
+  },
+  {
+    name: 'Responses with the "Cache-Control: no-store" header are not stored in the cache',
+    state: "stale",
+    cache_control: "no-store",
+    request_cache: ["default", "default"],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [false, false],
+  },
+  {
+    name: 'Responses with the "Cache-Control: no-store" header are not stored in the cache',
+    state: "fresh",
+    cache_control: "no-store",
+    request_cache: ["default", "default"],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [false, false],
+  },
+];
+run_tests(tests);
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-default.html b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-default.html
deleted file mode 100644
index c0e37b2..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-default.html
+++ /dev/null
@@ -1,50 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Request cache - default</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#request">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <script src="/common/utils.js"></script>
-    <script src="/common/get-host-info.sub.js"></script>
-    <script src="request-cache.js"></script>
-  </head>
-  <body>
-    <script>
-    var tests = [
-      {
-        name: 'RequestCache "default" mode checks the cache for previously cached content and goes to the network for stale responses',
-        state: "stale",
-        request_cache: ["default", "default"],
-        expected_validation_headers: [false, true],
-        expected_no_cache_headers: [false, false],
-      },
-      {
-        name: 'RequestCache "default" mode checks the cache for previously cached content and avoids going to the network if a fresh response exists',
-        state: "fresh",
-        request_cache: ["default", "default"],
-        expected_validation_headers: [false],
-        expected_no_cache_headers: [false],
-      },
-      {
-        name: 'Responses with the "Cache-Control: no-store" header are not stored in the cache',
-        state: "stale",
-        cache_control: "no-store",
-        request_cache: ["default", "default"],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [false, false],
-      },
-      {
-        name: 'Responses with the "Cache-Control: no-store" header are not stored in the cache',
-        state: "fresh",
-        cache_control: "no-store",
-        request_cache: ["default", "default"],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [false, false],
-      },
-    ];
-    run_tests(tests);
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-force-cache.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-force-cache.any.js
new file mode 100644
index 0000000..00dce09
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-force-cache.any.js
@@ -0,0 +1,67 @@
+// META: global=window,worker
+// META: title=Request cache - force-cache
+// META: script=/common/utils.js
+// META: script=/common/get-host-info.sub.js
+// META: script=request-cache.js
+
+var tests = [
+  {
+    name: 'RequestCache "force-cache" mode checks the cache for previously cached content and avoid revalidation for stale responses',
+    state: "stale",
+    request_cache: ["default", "force-cache"],
+    expected_validation_headers: [false],
+    expected_no_cache_headers: [false],
+  },
+  {
+    name: 'RequestCache "force-cache" mode checks the cache for previously cached content and avoid revalidation for fresh responses',
+    state: "fresh",
+    request_cache: ["default", "force-cache"],
+    expected_validation_headers: [false],
+    expected_no_cache_headers: [false],
+  },
+  {
+    name: 'RequestCache "force-cache" mode checks the cache for previously cached content and goes to the network if a cached response is not found',
+    state: "stale",
+    request_cache: ["force-cache"],
+    expected_validation_headers: [false],
+    expected_no_cache_headers: [false],
+  },
+  {
+    name: 'RequestCache "force-cache" mode checks the cache for previously cached content and goes to the network if a cached response is not found',
+    state: "fresh",
+    request_cache: ["force-cache"],
+    expected_validation_headers: [false],
+    expected_no_cache_headers: [false],
+  },
+  {
+    name: 'RequestCache "force-cache" mode checks the cache for previously cached content and goes to the network if a cached response would vary',
+    state: "stale",
+    vary: "*",
+    request_cache: ["default", "force-cache"],
+    expected_validation_headers: [false, true],
+    expected_no_cache_headers: [false, false],
+  },
+  {
+    name: 'RequestCache "force-cache" mode checks the cache for previously cached content and goes to the network if a cached response would vary',
+    state: "fresh",
+    vary: "*",
+    request_cache: ["default", "force-cache"],
+    expected_validation_headers: [false, true],
+    expected_no_cache_headers: [false, false],
+  },
+  {
+    name: 'RequestCache "force-cache" stores the response in the cache if it goes to the network',
+    state: "stale",
+    request_cache: ["force-cache", "default"],
+    expected_validation_headers: [false, true],
+    expected_no_cache_headers: [false, false],
+  },
+  {
+    name: 'RequestCache "force-cache" stores the response in the cache if it goes to the network',
+    state: "fresh",
+    request_cache: ["force-cache", "default"],
+    expected_validation_headers: [false],
+    expected_no_cache_headers: [false],
+  },
+];
+run_tests(tests);
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-force-cache.html b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-force-cache.html
deleted file mode 100644
index ed45726..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-force-cache.html
+++ /dev/null
@@ -1,78 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Request cache - force-cache</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#request">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <script src="/common/utils.js"></script>
-    <script src="/common/get-host-info.sub.js"></script>
-    <script src="request-cache.js"></script>
-  </head>
-  <body>
-    <script>
-    var tests = [
-      {
-        name: 'RequestCache "force-cache" mode checks the cache for previously cached content and avoid revalidation for stale responses',
-        state: "stale",
-        request_cache: ["default", "force-cache"],
-        expected_validation_headers: [false],
-        expected_no_cache_headers: [false],
-      },
-      {
-        name: 'RequestCache "force-cache" mode checks the cache for previously cached content and avoid revalidation for fresh responses',
-        state: "fresh",
-        request_cache: ["default", "force-cache"],
-        expected_validation_headers: [false],
-        expected_no_cache_headers: [false],
-      },
-      {
-        name: 'RequestCache "force-cache" mode checks the cache for previously cached content and goes to the network if a cached response is not found',
-        state: "stale",
-        request_cache: ["force-cache"],
-        expected_validation_headers: [false],
-        expected_no_cache_headers: [false],
-      },
-      {
-        name: 'RequestCache "force-cache" mode checks the cache for previously cached content and goes to the network if a cached response is not found',
-        state: "fresh",
-        request_cache: ["force-cache"],
-        expected_validation_headers: [false],
-        expected_no_cache_headers: [false],
-      },
-      {
-        name: 'RequestCache "force-cache" mode checks the cache for previously cached content and goes to the network if a cached response would vary',
-        state: "stale",
-        vary: "*",
-        request_cache: ["default", "force-cache"],
-        expected_validation_headers: [false, true],
-        expected_no_cache_headers: [false, false],
-      },
-      {
-        name: 'RequestCache "force-cache" mode checks the cache for previously cached content and goes to the network if a cached response would vary',
-        state: "fresh",
-        vary: "*",
-        request_cache: ["default", "force-cache"],
-        expected_validation_headers: [false, true],
-        expected_no_cache_headers: [false, false],
-      },
-      {
-        name: 'RequestCache "force-cache" stores the response in the cache if it goes to the network',
-        state: "stale",
-        request_cache: ["force-cache", "default"],
-        expected_validation_headers: [false, true],
-        expected_no_cache_headers: [false, false],
-      },
-      {
-        name: 'RequestCache "force-cache" stores the response in the cache if it goes to the network',
-        state: "fresh",
-        request_cache: ["force-cache", "default"],
-        expected_validation_headers: [false],
-        expected_no_cache_headers: [false],
-      },
-    ];
-    run_tests(tests);
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-no-cache.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-no-cache.any.js
new file mode 100644
index 0000000..41fc22b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-no-cache.any.js
@@ -0,0 +1,25 @@
+// META: global=window,worker
+// META: title=Request cache : no-cache
+// META: script=/common/utils.js
+// META: script=/common/get-host-info.sub.js
+// META: script=request-cache.js
+
+var tests = [
+  {
+    name: 'RequestCache "no-cache" mode revalidates stale responses found in the cache',
+    state: "stale",
+    request_cache: ["default", "no-cache"],
+    expected_validation_headers: [false, true],
+    expected_no_cache_headers: [false, false],
+    expected_max_age_headers: [false, true],
+  },
+  {
+    name: 'RequestCache "no-cache" mode revalidates fresh responses found in the cache',
+    state: "fresh",
+    request_cache: ["default", "no-cache"],
+    expected_validation_headers: [false, true],
+    expected_no_cache_headers: [false, false],
+    expected_max_age_headers: [false, true],
+  },
+];
+run_tests(tests);
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-no-cache.html b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-no-cache.html
deleted file mode 100644
index d30ed16..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-no-cache.html
+++ /dev/null
@@ -1,36 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Request cache : no-cache</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#request">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <script src="/common/utils.js"></script>
-    <script src="/common/get-host-info.sub.js"></script>
-    <script src="request-cache.js"></script>
-  </head>
-  <body>
-    <script>
-    var tests = [
-      {
-        name: 'RequestCache "no-cache" mode revalidates stale responses found in the cache',
-        state: "stale",
-        request_cache: ["default", "no-cache"],
-        expected_validation_headers: [false, true],
-        expected_no_cache_headers: [false, false],
-        expected_max_age_headers: [false, true],
-      },
-      {
-        name: 'RequestCache "no-cache" mode revalidates fresh responses found in the cache',
-        state: "fresh",
-        request_cache: ["default", "no-cache"],
-        expected_validation_headers: [false, true],
-        expected_no_cache_headers: [false, false],
-        expected_max_age_headers: [false, true],
-      },
-    ];
-    run_tests(tests);
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-no-store.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-no-store.any.js
new file mode 100644
index 0000000..9a28718
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-no-store.any.js
@@ -0,0 +1,37 @@
+// META: global=window,worker
+// META: title=Request cache - no store
+// META: script=/common/utils.js
+// META: script=/common/get-host-info.sub.js
+// META: script=request-cache.js
+
+var tests = [
+  {
+    name: 'RequestCache "no-store" mode does not check the cache for previously cached content and goes to the network regardless',
+    state: "stale",
+    request_cache: ["default", "no-store"],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [false, true],
+  },
+  {
+    name: 'RequestCache "no-store" mode does not check the cache for previously cached content and goes to the network regardless',
+    state: "fresh",
+    request_cache: ["default", "no-store"],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [false, true],
+  },
+  {
+    name: 'RequestCache "no-store" mode does not store the response in the cache',
+    state: "stale",
+    request_cache: ["no-store", "default"],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [true, false],
+  },
+  {
+    name: 'RequestCache "no-store" mode does not store the response in the cache',
+    state: "fresh",
+    request_cache: ["no-store", "default"],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [true, false],
+  },
+];
+run_tests(tests);
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-no-store.html b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-no-store.html
deleted file mode 100644
index 396b6a6..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-no-store.html
+++ /dev/null
@@ -1,48 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Request cache - no store</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#request">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <script src="/common/utils.js"></script>
-    <script src="/common/get-host-info.sub.js"></script>
-    <script src="request-cache.js"></script>
-  </head>
-  <body>
-    <script>
-    var tests = [
-      {
-        name: 'RequestCache "no-store" mode does not check the cache for previously cached content and goes to the network regardless',
-        state: "stale",
-        request_cache: ["default", "no-store"],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [false, true],
-      },
-      {
-        name: 'RequestCache "no-store" mode does not check the cache for previously cached content and goes to the network regardless',
-        state: "fresh",
-        request_cache: ["default", "no-store"],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [false, true],
-      },
-      {
-        name: 'RequestCache "no-store" mode does not store the response in the cache',
-        state: "stale",
-        request_cache: ["no-store", "default"],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [true, false],
-      },
-      {
-        name: 'RequestCache "no-store" mode does not store the response in the cache',
-        state: "fresh",
-        request_cache: ["no-store", "default"],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [true, false],
-      },
-    ];
-    run_tests(tests);
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-only-if-cached.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-only-if-cached.any.js
new file mode 100644
index 0000000..1305787
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-only-if-cached.any.js
@@ -0,0 +1,66 @@
+// META: global=window,dedicatedworker,sharedworker
+// META: title=Request cache - only-if-cached
+// META: script=/common/utils.js
+// META: script=/common/get-host-info.sub.js
+// META: script=request-cache.js
+
+// FIXME: avoid mixed content requests to enable service worker global
+var tests = [
+  {
+    name: 'RequestCache "only-if-cached" mode checks the cache for previously cached content and avoids revalidation for stale responses',
+    state: "stale",
+    request_cache: ["default", "only-if-cached"],
+    expected_validation_headers: [false],
+    expected_no_cache_headers: [false]
+  },
+  {
+    name: 'RequestCache "only-if-cached" mode checks the cache for previously cached content and avoids revalidation for fresh responses',
+    state: "fresh",
+    request_cache: ["default", "only-if-cached"],
+    expected_validation_headers: [false],
+    expected_no_cache_headers: [false]
+  },
+  {
+    name: 'RequestCache "only-if-cached" mode checks the cache for previously cached content and does not go to the network if a cached response is not found',
+    state: "fresh",
+    request_cache: ["only-if-cached"],
+    response: ["error"],
+    expected_validation_headers: [],
+    expected_no_cache_headers: []
+  },
+  {
+    name: 'RequestCache "only-if-cached" (with "same-origin") uses cached same-origin redirects to same-origin content',
+    state: "fresh",
+    request_cache: ["default", "only-if-cached"],
+    redirect: "same-origin",
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [false, false],
+  },
+  {
+    name: 'RequestCache "only-if-cached" (with "same-origin") uses cached same-origin redirects to same-origin content',
+    state: "stale",
+    request_cache: ["default", "only-if-cached"],
+    redirect: "same-origin",
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [false, false],
+  },
+  {
+    name: 'RequestCache "only-if-cached" (with "same-origin") does not follow redirects across origins and rejects',
+    state: "fresh",
+    request_cache: ["default", "only-if-cached"],
+    redirect: "cross-origin",
+    response: [null, "error"],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [false, false],
+  },
+  {
+    name: 'RequestCache "only-if-cached" (with "same-origin") does not follow redirects across origins and rejects',
+    state: "stale",
+    request_cache: ["default", "only-if-cached"],
+    redirect: "cross-origin",
+    response: [null, "error"],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [false, false],
+  },
+];
+run_tests(tests);
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-only-if-cached.html b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-only-if-cached.html
deleted file mode 100644
index adb31a3..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-only-if-cached.html
+++ /dev/null
@@ -1,76 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Request cache - only-if-cached</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#request">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <script src="/common/utils.js"></script>
-    <script src="/common/get-host-info.sub.js"></script>
-    <script src="request-cache.js"></script>
-  </head>
-  <body>
-    <script>
-    var tests = [
-      {
-        name: 'RequestCache "only-if-cached" mode checks the cache for previously cached content and avoids revalidation for stale responses',
-        state: "stale",
-        request_cache: ["default", "only-if-cached"],
-        expected_validation_headers: [false],
-        expected_no_cache_headers: [false]
-      },
-      {
-        name: 'RequestCache "only-if-cached" mode checks the cache for previously cached content and avoids revalidation for fresh responses',
-        state: "fresh",
-        request_cache: ["default", "only-if-cached"],
-        expected_validation_headers: [false],
-        expected_no_cache_headers: [false]
-      },
-      {
-        name: 'RequestCache "only-if-cached" mode checks the cache for previously cached content and does not go to the network if a cached response is not found',
-        state: "fresh",
-        request_cache: ["only-if-cached"],
-        response: ["error"],
-        expected_validation_headers: [],
-        expected_no_cache_headers: []
-      },
-      {
-        name: 'RequestCache "only-if-cached" (with "same-origin") uses cached same-origin redirects to same-origin content',
-        state: "fresh",
-        request_cache: ["default", "only-if-cached"],
-        redirect: "same-origin",
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [false, false],
-      },
-      {
-        name: 'RequestCache "only-if-cached" (with "same-origin") uses cached same-origin redirects to same-origin content',
-        state: "stale",
-        request_cache: ["default", "only-if-cached"],
-        redirect: "same-origin",
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [false, false],
-      },
-      {
-        name: 'RequestCache "only-if-cached" (with "same-origin") does not follow redirects across origins and rejects',
-        state: "fresh",
-        request_cache: ["default", "only-if-cached"],
-        redirect: "cross-origin",
-        response: [null, "error"],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [false, false],
-      },
-      {
-        name: 'RequestCache "only-if-cached" (with "same-origin") does not follow redirects across origins and rejects',
-        state: "stale",
-        request_cache: ["default", "only-if-cached"],
-        redirect: "cross-origin",
-        response: [null, "error"],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [false, false],
-      },
-    ];
-    run_tests(tests);
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-reload.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-reload.any.js
new file mode 100644
index 0000000..c7bfffb3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-reload.any.js
@@ -0,0 +1,51 @@
+// META: global=window,worker
+// META: title=Request cache - reload
+// META: script=/common/utils.js
+// META: script=/common/get-host-info.sub.js
+// META: script=request-cache.js
+
+var tests = [
+  {
+    name: 'RequestCache "reload" mode does not check the cache for previously cached content and goes to the network regardless',
+    state: "stale",
+    request_cache: ["default", "reload"],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [false, true],
+  },
+  {
+    name: 'RequestCache "reload" mode does not check the cache for previously cached content and goes to the network regardless',
+    state: "fresh",
+    request_cache: ["default", "reload"],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [false, true],
+  },
+  {
+    name: 'RequestCache "reload" mode does store the response in the cache',
+    state: "stale",
+    request_cache: ["reload", "default"],
+    expected_validation_headers: [false, true],
+    expected_no_cache_headers: [true, false],
+  },
+  {
+    name: 'RequestCache "reload" mode does store the response in the cache',
+    state: "fresh",
+    request_cache: ["reload", "default"],
+    expected_validation_headers: [false],
+    expected_no_cache_headers: [true],
+  },
+  {
+    name: 'RequestCache "reload" mode does store the response in the cache even if a previous response is already stored',
+    state: "stale",
+    request_cache: ["default", "reload", "default"],
+    expected_validation_headers: [false, false, true],
+    expected_no_cache_headers: [false, true, false],
+  },
+  {
+    name: 'RequestCache "reload" mode does store the response in the cache even if a previous response is already stored',
+    state: "fresh",
+    request_cache: ["default", "reload", "default"],
+    expected_validation_headers: [false, false],
+    expected_no_cache_headers: [false, true],
+  },
+];
+run_tests(tests);
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-reload.html b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-reload.html
deleted file mode 100644
index 45ff583..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-cache-reload.html
+++ /dev/null
@@ -1,62 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Request cache - reload</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#request">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <script src="/common/utils.js"></script>
-    <script src="/common/get-host-info.sub.js"></script>
-    <script src="request-cache.js"></script>
-  </head>
-  <body>
-    <script>
-    var tests = [
-      {
-        name: 'RequestCache "reload" mode does not check the cache for previously cached content and goes to the network regardless',
-        state: "stale",
-        request_cache: ["default", "reload"],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [false, true],
-      },
-      {
-        name: 'RequestCache "reload" mode does not check the cache for previously cached content and goes to the network regardless',
-        state: "fresh",
-        request_cache: ["default", "reload"],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [false, true],
-      },
-      {
-        name: 'RequestCache "reload" mode does store the response in the cache',
-        state: "stale",
-        request_cache: ["reload", "default"],
-        expected_validation_headers: [false, true],
-        expected_no_cache_headers: [true, false],
-      },
-      {
-        name: 'RequestCache "reload" mode does store the response in the cache',
-        state: "fresh",
-        request_cache: ["reload", "default"],
-        expected_validation_headers: [false],
-        expected_no_cache_headers: [true],
-      },
-      {
-        name: 'RequestCache "reload" mode does store the response in the cache even if a previous response is already stored',
-        state: "stale",
-        request_cache: ["default", "reload", "default"],
-        expected_validation_headers: [false, false, true],
-        expected_no_cache_headers: [false, true, false],
-      },
-      {
-        name: 'RequestCache "reload" mode does store the response in the cache even if a previous response is already stored',
-        state: "fresh",
-        request_cache: ["default", "reload", "default"],
-        expected_validation_headers: [false, false],
-        expected_no_cache_headers: [false, true],
-      },
-    ];
-    run_tests(tests);
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-consume-empty.any-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-consume-empty.any-expected.txt
new file mode 100644
index 0000000..9c23dfe
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-consume-empty.any-expected.txt
@@ -0,0 +1,17 @@
+This is a testharness.js-based test.
+PASS Consume request's body as text
+PASS Consume request's body as blob
+PASS Consume request's body as arrayBuffer
+PASS Consume request's body as json (error case)
+PASS Consume request's body as formData with correct multipart type (error case)
+PASS Consume request's body as formData with correct urlencoded type
+PASS Consume request's body as formData without correct type (error case)
+PASS Consume empty blob request body as arrayBuffer
+PASS Consume empty text request body as arrayBuffer
+PASS Consume empty blob request body as text
+PASS Consume empty text request body as text
+PASS Consume empty URLSearchParams request body as text
+FAIL Consume empty FormData request body as text assert_equals: Resolved value should be empty expected 0 but got 44
+PASS Consume empty ArrayBuffer request body as text
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-consume-empty.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-consume-empty.any.js
new file mode 100644
index 0000000..034a860
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-consume-empty.any.js
@@ -0,0 +1,101 @@
+// META: global=window,worker
+// META: title=Request consume empty bodies
+
+function checkBodyText(test, request) {
+  return request.text().then(function(bodyAsText) {
+    assert_equals(bodyAsText, "", "Resolved value should be empty");
+    assert_false(request.bodyUsed);
+  });
+}
+
+function checkBodyBlob(test, request) {
+  return request.blob().then(function(bodyAsBlob) {
+    var promise = new Promise(function(resolve, reject) {
+      var reader = new FileReader();
+      reader.onload = function(evt) {
+        resolve(reader.result)
+      };
+      reader.onerror = function() {
+        reject("Blob's reader failed");
+      };
+      reader.readAsText(bodyAsBlob);
+    });
+    return promise.then(function(body) {
+      assert_equals(body, "", "Resolved value should be empty");
+      assert_false(request.bodyUsed);
+    });
+  });
+}
+
+function checkBodyArrayBuffer(test, request) {
+  return request.arrayBuffer().then(function(bodyAsArrayBuffer) {
+    assert_equals(bodyAsArrayBuffer.byteLength, 0, "Resolved value should be empty");
+    assert_false(request.bodyUsed);
+  });
+}
+
+function checkBodyJSON(test, request) {
+  return request.json().then(
+    function(bodyAsJSON) {
+      assert_unreached("JSON parsing should fail");
+    },
+    function() {
+      assert_false(request.bodyUsed);
+    });
+}
+
+function checkBodyFormData(test, request) {
+  return request.formData().then(function(bodyAsFormData) {
+    assert_true(bodyAsFormData instanceof FormData, "Should receive a FormData");
+    assert_false(request.bodyUsed);
+  });
+}
+
+function checkBodyFormDataError(test, request) {
+  return promise_rejects_js(test, TypeError, request.formData()).then(function() {
+    assert_false(request.bodyUsed);
+  });
+}
+
+function checkRequestWithNoBody(bodyType, checkFunction, headers = []) {
+  promise_test(function(test) {
+    var request = new Request("", {"method": "POST", "headers": headers});
+    assert_false(request.bodyUsed);
+    return checkFunction(test, request);
+  }, "Consume request's body as " + bodyType);
+}
+
+checkRequestWithNoBody("text", checkBodyText);
+checkRequestWithNoBody("blob", checkBodyBlob);
+checkRequestWithNoBody("arrayBuffer", checkBodyArrayBuffer);
+checkRequestWithNoBody("json (error case)", checkBodyJSON);
+checkRequestWithNoBody("formData with correct multipart type (error case)", checkBodyFormDataError, [["Content-Type", 'multipart/form-data; boundary="boundary"']]);
+checkRequestWithNoBody("formData with correct urlencoded type", checkBodyFormData, [["Content-Type", "application/x-www-form-urlencoded;charset=UTF-8"]]);
+checkRequestWithNoBody("formData without correct type (error case)", checkBodyFormDataError);
+
+function checkRequestWithEmptyBody(bodyType, body, asText) {
+  promise_test(function(test) {
+    var request = new Request("", {"method": "POST", "body": body});
+    assert_false(request.bodyUsed, "bodyUsed is false at init");
+    if (asText) {
+      return request.text().then(function(bodyAsString) {
+        assert_equals(bodyAsString.length, 0, "Resolved value should be empty");
+        assert_true(request.bodyUsed, "bodyUsed is true after being consumed");
+      });
+    }
+    return request.arrayBuffer().then(function(bodyAsArrayBuffer) {
+      assert_equals(bodyAsArrayBuffer.byteLength, 0, "Resolved value should be empty");
+      assert_true(request.bodyUsed, "bodyUsed is true after being consumed");
+    });
+  }, "Consume empty " + bodyType + " request body as " + (asText ? "text" : "arrayBuffer"));
+}
+
+// FIXME: Add BufferSource, FormData and URLSearchParams.
+checkRequestWithEmptyBody("blob", new Blob([], { "type" : "text/plain" }), false);
+checkRequestWithEmptyBody("text", "", false);
+checkRequestWithEmptyBody("blob", new Blob([], { "type" : "text/plain" }), true);
+checkRequestWithEmptyBody("text", "", true);
+checkRequestWithEmptyBody("URLSearchParams", new URLSearchParams(""), true);
+// FIXME: This test assumes that the empty string be returned but it is not clear whether that is right. See https://github.com/web-platform-tests/wpt/pull/3950.
+checkRequestWithEmptyBody("FormData", new FormData(), true);
+checkRequestWithEmptyBody("ArrayBuffer", new ArrayBuffer(), true);
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-consume-empty.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-consume-empty.any.serviceworker-expected.txt
new file mode 100644
index 0000000..9c23dfe
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-consume-empty.any.serviceworker-expected.txt
@@ -0,0 +1,17 @@
+This is a testharness.js-based test.
+PASS Consume request's body as text
+PASS Consume request's body as blob
+PASS Consume request's body as arrayBuffer
+PASS Consume request's body as json (error case)
+PASS Consume request's body as formData with correct multipart type (error case)
+PASS Consume request's body as formData with correct urlencoded type
+PASS Consume request's body as formData without correct type (error case)
+PASS Consume empty blob request body as arrayBuffer
+PASS Consume empty text request body as arrayBuffer
+PASS Consume empty blob request body as text
+PASS Consume empty text request body as text
+PASS Consume empty URLSearchParams request body as text
+FAIL Consume empty FormData request body as text assert_equals: Resolved value should be empty expected 0 but got 44
+PASS Consume empty ArrayBuffer request body as text
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-consume-empty.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-consume-empty.any.sharedworker-expected.txt
new file mode 100644
index 0000000..9c23dfe
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-consume-empty.any.sharedworker-expected.txt
@@ -0,0 +1,17 @@
+This is a testharness.js-based test.
+PASS Consume request's body as text
+PASS Consume request's body as blob
+PASS Consume request's body as arrayBuffer
+PASS Consume request's body as json (error case)
+PASS Consume request's body as formData with correct multipart type (error case)
+PASS Consume request's body as formData with correct urlencoded type
+PASS Consume request's body as formData without correct type (error case)
+PASS Consume empty blob request body as arrayBuffer
+PASS Consume empty text request body as arrayBuffer
+PASS Consume empty blob request body as text
+PASS Consume empty text request body as text
+PASS Consume empty URLSearchParams request body as text
+FAIL Consume empty FormData request body as text assert_equals: Resolved value should be empty expected 0 but got 44
+PASS Consume empty ArrayBuffer request body as text
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-consume-empty.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-consume-empty.any.worker-expected.txt
new file mode 100644
index 0000000..9c23dfe
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-consume-empty.any.worker-expected.txt
@@ -0,0 +1,17 @@
+This is a testharness.js-based test.
+PASS Consume request's body as text
+PASS Consume request's body as blob
+PASS Consume request's body as arrayBuffer
+PASS Consume request's body as json (error case)
+PASS Consume request's body as formData with correct multipart type (error case)
+PASS Consume request's body as formData with correct urlencoded type
+PASS Consume request's body as formData without correct type (error case)
+PASS Consume empty blob request body as arrayBuffer
+PASS Consume empty text request body as arrayBuffer
+PASS Consume empty blob request body as text
+PASS Consume empty text request body as text
+PASS Consume empty URLSearchParams request body as text
+FAIL Consume empty FormData request body as text assert_equals: Resolved value should be empty expected 0 but got 44
+PASS Consume empty ArrayBuffer request body as text
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-consume-empty.html b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-consume-empty.html
deleted file mode 100644
index 4159958..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-consume-empty.html
+++ /dev/null
@@ -1,114 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Request consume empty bodies</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#request">
-    <meta name="help" href="https://fetch.spec.whatwg.org/#body-mixin">
-    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-  </head>
-  <body>
-    <script>
-    function checkBodyText(test, request) {
-      return request.text().then(function(bodyAsText) {
-        assert_equals(bodyAsText, "", "Resolved value should be empty");
-        assert_false(request.bodyUsed);
-      });
-    }
-
-    function checkBodyBlob(test, request) {
-      return request.blob().then(function(bodyAsBlob) {
-        var promise = new Promise(function(resolve, reject) {
-          var reader = new FileReader();
-          reader.onload = function(evt) {
-            resolve(reader.result)
-          };
-          reader.onerror = function() {
-            reject("Blob's reader failed");
-          };
-          reader.readAsText(bodyAsBlob);
-        });
-        return promise.then(function(body) {
-          assert_equals(body, "", "Resolved value should be empty");
-          assert_false(request.bodyUsed);
-        });
-      });
-    }
-
-    function checkBodyArrayBuffer(test, request) {
-      return request.arrayBuffer().then(function(bodyAsArrayBuffer) {
-        assert_equals(bodyAsArrayBuffer.byteLength, 0, "Resolved value should be empty");
-        assert_false(request.bodyUsed);
-      });
-    }
-
-    function checkBodyJSON(test, request) {
-      return request.json().then(
-        function(bodyAsJSON) {
-          assert_unreached("JSON parsing should fail");
-        },
-        function() {
-          assert_false(request.bodyUsed);
-        });
-    }
-
-    function checkBodyFormData(test, request) {
-      return request.formData().then(function(bodyAsFormData) {
-        assert_true(bodyAsFormData instanceof FormData, "Should receive a FormData");
-        assert_false(request.bodyUsed);
-     });
-    }
-
-    function checkBodyFormDataError(test, request) {
-      return promise_rejects_js(test, TypeError, request.formData()).then(function() {
-        assert_false(request.bodyUsed);
-      });
-    }
-
-    function checkRequestWithNoBody(bodyType, checkFunction, headers = []) {
-      promise_test(function(test) {
-        var request = new Request("", {"method": "POST", "headers": headers});
-        assert_false(request.bodyUsed);
-        return checkFunction(test, request);
-      }, "Consume request's body as " + bodyType);
-    }
-
-    checkRequestWithNoBody("text", checkBodyText);
-    checkRequestWithNoBody("blob", checkBodyBlob);
-    checkRequestWithNoBody("arrayBuffer", checkBodyArrayBuffer);
-    checkRequestWithNoBody("json (error case)", checkBodyJSON);
-    checkRequestWithNoBody("formData with correct multipart type (error case)", checkBodyFormDataError, [["Content-Type", 'multipart/form-data; boundary="boundary"']]);
-    checkRequestWithNoBody("formData with correct urlencoded type", checkBodyFormData, [["Content-Type", "application/x-www-form-urlencoded;charset=UTF-8"]]);
-    checkRequestWithNoBody("formData without correct type (error case)", checkBodyFormDataError);
-
-    function checkRequestWithEmptyBody(bodyType, body, asText) {
-      promise_test(function(test) {
-        var request = new Request("", {"method": "POST", "body": body});
-        assert_false(request.bodyUsed, "bodyUsed is false at init");
-        if (asText) {
-          return request.text().then(function(bodyAsString) {
-            assert_equals(bodyAsString.length, 0, "Resolved value should be empty");
-            assert_true(request.bodyUsed, "bodyUsed is true after being consumed");
-          });
-        }
-        return request.arrayBuffer().then(function(bodyAsArrayBuffer) {
-          assert_equals(bodyAsArrayBuffer.byteLength, 0, "Resolved value should be empty");
-          assert_true(request.bodyUsed, "bodyUsed is true after being consumed");
-        });
-      }, "Consume empty " + bodyType + " request body as " + (asText ? "text" : "arrayBuffer"));
-    }
-
-    // FIXME: Add BufferSource, FormData and URLSearchParams.
-    checkRequestWithEmptyBody("blob", new Blob([], { "type" : "text/plain" }), false);
-    checkRequestWithEmptyBody("text", "", false);
-    checkRequestWithEmptyBody("blob", new Blob([], { "type" : "text/plain" }), true);
-    checkRequestWithEmptyBody("text", "", true);
-    checkRequestWithEmptyBody("URLSearchParams", new URLSearchParams(""), true);
-    // FIXME: This test assumes that the empty string be returned but it is not clear whether that is right. See https://github.com/web-platform-tests/wpt/pull/3950.
-    checkRequestWithEmptyBody("FormData", new FormData(), true);
-    checkRequestWithEmptyBody("ArrayBuffer", new ArrayBuffer(), true);
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-consume.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-consume.any.js
new file mode 100644
index 0000000..aff5d652
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-consume.any.js
@@ -0,0 +1,145 @@
+// META: global=window,worker
+// META: title=Request consume
+// META: script=../resources/utils.js
+
+function checkBodyText(request, expectedBody) {
+  return request.text().then(function(bodyAsText) {
+    assert_equals(bodyAsText, expectedBody, "Retrieve and verify request's body");
+    assert_true(request.bodyUsed, "body as text: bodyUsed turned true");
+  });
+}
+
+function checkBodyBlob(request, expectedBody, checkContentType) {
+  return request.blob().then(function(bodyAsBlob) {
+    if (checkContentType)
+      assert_equals(bodyAsBlob.type, "text/plain", "Blob body type should be computed from the request Content-Type");
+
+    var promise = new Promise(function (resolve, reject) {
+      var reader = new FileReader();
+      reader.onload = function(evt) {
+        resolve(reader.result)
+      };
+      reader.onerror = function() {
+        reject("Blob's reader failed");
+      };
+      reader.readAsText(bodyAsBlob);
+    });
+    return promise.then(function(body) {
+      assert_equals(body, expectedBody, "Retrieve and verify request's body");
+      assert_true(request.bodyUsed, "body as blob: bodyUsed turned true");
+    });
+  });
+}
+
+function checkBodyArrayBuffer(request, expectedBody) {
+  return request.arrayBuffer().then(function(bodyAsArrayBuffer) {
+    validateBufferFromString(bodyAsArrayBuffer, expectedBody, "Retrieve and verify request's body");
+    assert_true(request.bodyUsed, "body as arrayBuffer: bodyUsed turned true");
+  });
+}
+
+function checkBodyJSON(request, expectedBody) {
+  return request.json().then(function(bodyAsJSON) {
+    var strBody = JSON.stringify(bodyAsJSON)
+    assert_equals(strBody, expectedBody, "Retrieve and verify request's body");
+    assert_true(request.bodyUsed, "body as json: bodyUsed turned true");
+  });
+}
+
+function checkBodyFormData(request, expectedBody) {
+  return request.formData().then(function(bodyAsFormData) {
+    assert_true(bodyAsFormData instanceof FormData, "Should receive a FormData");
+    assert_true(request.bodyUsed, "body as formData: bodyUsed turned true");
+  });
+}
+
+function checkRequestBody(body, expected, bodyType) {
+  promise_test(function(test) {
+    var request = new Request("", {"method": "POST", "body": body, "headers": [["Content-Type", "text/PLAIN"]] });
+    assert_false(request.bodyUsed, "bodyUsed is false at init");
+    return checkBodyText(request, expected);
+  }, "Consume " + bodyType  + " request's body as text");
+  promise_test(function(test) {
+    var request = new Request("", {"method": "POST", "body": body });
+    assert_false(request.bodyUsed, "bodyUsed is false at init");
+    return checkBodyBlob(request, expected);
+  }, "Consume " + bodyType  + " request's body as blob");
+  promise_test(function(test) {
+    var request = new Request("", {"method": "POST", "body": body });
+    assert_false(request.bodyUsed, "bodyUsed is false at init");
+    return checkBodyArrayBuffer(request, expected);
+  }, "Consume " + bodyType  + " request's body as arrayBuffer");
+  promise_test(function(test) {
+    var request = new Request("", {"method": "POST", "body": body });
+    assert_false(request.bodyUsed, "bodyUsed is false at init");
+    return checkBodyJSON(request, expected);
+  }, "Consume " + bodyType  + " request's body as JSON");
+}
+
+var textData = JSON.stringify("This is response's body");
+var blob = new Blob([textData], { "type" : "text/plain" });
+
+checkRequestBody(textData, textData, "String");
+
+var string = "\"123456\"";
+function getArrayBuffer() {
+    var arrayBuffer = new ArrayBuffer(8);
+    var int8Array = new Int8Array(arrayBuffer);
+    for (var cptr = 0; cptr < 8; cptr++)
+        int8Array[cptr] = string.charCodeAt(cptr);
+    return arrayBuffer;
+}
+
+function getArrayBufferWithZeros() {
+    var arrayBuffer = new ArrayBuffer(10);
+    var int8Array = new Int8Array(arrayBuffer);
+    for (var cptr = 0; cptr < 8; cptr++)
+        int8Array[cptr + 1] = string.charCodeAt(cptr);
+    return arrayBuffer;
+}
+
+checkRequestBody(getArrayBuffer(), string, "ArrayBuffer");
+checkRequestBody(new Uint8Array(getArrayBuffer()), string, "Uint8Array");
+checkRequestBody(new Int8Array(getArrayBufferWithZeros(), 1, 8), string, "Int8Array");
+checkRequestBody(new Float32Array(getArrayBuffer()), string, "Float32Array");
+checkRequestBody(new DataView(getArrayBufferWithZeros(), 1, 8), string, "DataView");
+
+promise_test(function(test) {
+  var formData = new FormData();
+  formData.append("name", "value")
+  var request = new Request("", {"method": "POST", "body": formData });
+  assert_false(request.bodyUsed, "bodyUsed is false at init");
+  return checkBodyFormData(request, formData);
+}, "Consume FormData request's body as FormData");
+
+function checkBlobResponseBody(blobBody, blobData, bodyType, checkFunction) {
+  promise_test(function(test) {
+    var response = new Response(blobBody);
+    assert_false(response.bodyUsed, "bodyUsed is false at init");
+    return checkFunction(response, blobData);
+  }, "Consume blob response's body as " + bodyType);
+}
+
+checkBlobResponseBody(blob, textData, "blob", checkBodyBlob);
+checkBlobResponseBody(blob, textData, "text", checkBodyText);
+checkBlobResponseBody(blob, textData, "json", checkBodyJSON);
+checkBlobResponseBody(blob, textData, "arrayBuffer", checkBodyArrayBuffer);
+checkBlobResponseBody(new Blob([""]), "", "blob (empty blob as input)", checkBodyBlob);
+
+var goodJSONValues = ["null", "1", "true", "\"string\""];
+goodJSONValues.forEach(function(value) {
+  promise_test(function(test) {
+    var request = new Request("", {"method": "POST", "body": value});
+    return request.json().then(function(v) {
+      assert_equals(v, JSON.parse(value));
+    });
+  }, "Consume JSON from text: '" + JSON.stringify(value) + "'");
+});
+
+var badJSONValues = ["undefined", "{", "a", "["];
+badJSONValues.forEach(function(value) {
+  promise_test(function(test) {
+    var request = new Request("", {"method": "POST", "body": value});
+    return promise_rejects_js(test, SyntaxError, request.json());
+  }, "Trying to consume bad JSON text as JSON: '" + value + "'");
+});
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-consume.html b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-consume.html
deleted file mode 100644
index 06ef8a7d..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-consume.html
+++ /dev/null
@@ -1,158 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Request consume</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#request">
-    <meta name="help" href="https://fetch.spec.whatwg.org/#body-mixin">
-    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <script src="../resources/utils.js"></script>
-  </head>
-  <body>
-    <script>
-    function checkBodyText(request, expectedBody) {
-      return request.text().then(function(bodyAsText) {
-        assert_equals(bodyAsText, expectedBody, "Retrieve and verify request's body");
-        assert_true(request.bodyUsed, "body as text: bodyUsed turned true");
-      });
-    }
-
-    function checkBodyBlob(request, expectedBody, checkContentType) {
-      return request.blob().then(function(bodyAsBlob) {
-        if (checkContentType)
-          assert_equals(bodyAsBlob.type, "text/plain", "Blob body type should be computed from the request Content-Type");
-
-        var promise = new Promise(function (resolve, reject) {
-          var reader = new FileReader();
-          reader.onload = function(evt) {
-            resolve(reader.result)
-          };
-          reader.onerror = function() {
-            reject("Blob's reader failed");
-          };
-          reader.readAsText(bodyAsBlob);
-        });
-        return promise.then(function(body) {
-          assert_equals(body, expectedBody, "Retrieve and verify request's body");
-          assert_true(request.bodyUsed, "body as blob: bodyUsed turned true");
-        });
-      });
-    }
-
-    function checkBodyArrayBuffer(request, expectedBody) {
-      return request.arrayBuffer().then(function(bodyAsArrayBuffer) {
-        validateBufferFromString(bodyAsArrayBuffer, expectedBody, "Retrieve and verify request's body");
-        assert_true(request.bodyUsed, "body as arrayBuffer: bodyUsed turned true");
-      });
-    }
-
-    function checkBodyJSON(request, expectedBody) {
-      return request.json().then(function(bodyAsJSON) {
-        var strBody = JSON.stringify(bodyAsJSON)
-        assert_equals(strBody, expectedBody, "Retrieve and verify request's body");
-        assert_true(request.bodyUsed, "body as json: bodyUsed turned true");
-      });
-    }
-
-    function checkBodyFormData(request, expectedBody) {
-      return request.formData().then(function(bodyAsFormData) {
-        assert_true(bodyAsFormData instanceof FormData, "Should receive a FormData");
-        assert_true(request.bodyUsed, "body as formData: bodyUsed turned true");
-     });
-    }
-
-    function checkRequestBody(body, expected, bodyType) {
-      promise_test(function(test) {
-        var request = new Request("", {"method": "POST", "body": body, "headers": [["Content-Type", "text/PLAIN"]] });
-        assert_false(request.bodyUsed, "bodyUsed is false at init");
-        return checkBodyText(request, expected);
-      }, "Consume " + bodyType  + " request's body as text");
-      promise_test(function(test) {
-        var request = new Request("", {"method": "POST", "body": body });
-        assert_false(request.bodyUsed, "bodyUsed is false at init");
-        return checkBodyBlob(request, expected);
-      }, "Consume " + bodyType  + " request's body as blob");
-      promise_test(function(test) {
-        var request = new Request("", {"method": "POST", "body": body });
-        assert_false(request.bodyUsed, "bodyUsed is false at init");
-        return checkBodyArrayBuffer(request, expected);
-      }, "Consume " + bodyType  + " request's body as arrayBuffer");
-      promise_test(function(test) {
-        var request = new Request("", {"method": "POST", "body": body });
-        assert_false(request.bodyUsed, "bodyUsed is false at init");
-        return checkBodyJSON(request, expected);
-      }, "Consume " + bodyType  + " request's body as JSON");
-    }
-
-    var textData = JSON.stringify("This is response's body");
-    var blob = new Blob([textData], { "type" : "text/plain" });
-
-    checkRequestBody(textData, textData, "String");
-
-    var string = "\"123456\"";
-    function getArrayBuffer() {
-        var arrayBuffer = new ArrayBuffer(8);
-        var int8Array = new Int8Array(arrayBuffer);
-        for (var cptr = 0; cptr < 8; cptr++)
-            int8Array[cptr] = string.charCodeAt(cptr);
-        return arrayBuffer;
-    }
-
-    function getArrayBufferWithZeros() {
-        var arrayBuffer = new ArrayBuffer(10);
-        var int8Array = new Int8Array(arrayBuffer);
-        for (var cptr = 0; cptr < 8; cptr++)
-            int8Array[cptr + 1] = string.charCodeAt(cptr);
-        return arrayBuffer;
-    }
-
-    checkRequestBody(getArrayBuffer(), string, "ArrayBuffer");
-    checkRequestBody(new Uint8Array(getArrayBuffer()), string, "Uint8Array");
-    checkRequestBody(new Int8Array(getArrayBufferWithZeros(), 1, 8), string, "Int8Array");
-    checkRequestBody(new Float32Array(getArrayBuffer()), string, "Float32Array");
-    checkRequestBody(new DataView(getArrayBufferWithZeros(), 1, 8), string, "DataView");
-
-    promise_test(function(test) {
-      var formData = new FormData();
-      formData.append("name", "value")
-      var request = new Request("", {"method": "POST", "body": formData });
-      assert_false(request.bodyUsed, "bodyUsed is false at init");
-      return checkBodyFormData(request, formData);
-    }, "Consume FormData request's body as FormData");
-
-    function checkBlobResponseBody(blobBody, blobData, bodyType, checkFunction) {
-      promise_test(function(test) {
-        var response = new Response(blobBody);
-        assert_false(response.bodyUsed, "bodyUsed is false at init");
-        return checkFunction(response, blobData);
-      }, "Consume blob response's body as " + bodyType);
-    }
-
-    checkBlobResponseBody(blob, textData, "blob", checkBodyBlob);
-    checkBlobResponseBody(blob, textData, "text", checkBodyText);
-    checkBlobResponseBody(blob, textData, "json", checkBodyJSON);
-    checkBlobResponseBody(blob, textData, "arrayBuffer", checkBodyArrayBuffer);
-    checkBlobResponseBody(new Blob([""]), "", "blob (empty blob as input)", checkBodyBlob);
-
-    var goodJSONValues = ["null", "1", "true", "\"string\""];
-    goodJSONValues.forEach(function(value) {
-      promise_test(function(test) {
-        var request = new Request("", {"method": "POST", "body": value});
-        return request.json().then(function(v) {
-          assert_equals(v, JSON.parse(value));
-        });
-      }, "Consume JSON from text: '" + JSON.stringify(value) + "'");
-    });
-
-    var badJSONValues = ["undefined", "{", "a", "["];
-    badJSONValues.forEach(function(value) {
-      promise_test(function(test) {
-        var request = new Request("", {"method": "POST", "body": value});
-        return promise_rejects_js(test, SyntaxError, request.json());
-      }, "Trying to consume bad JSON text as JSON: '" + value + "'");
-    });
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-disturbed.any-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-disturbed.any-expected.txt
new file mode 100644
index 0000000..d46bdb8c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-disturbed.any-expected.txt
@@ -0,0 +1,12 @@
+This is a testharness.js-based test.
+PASS Request's body: initial state
+PASS Request without body cannot be disturbed
+PASS Check cloning a disturbed request
+PASS Check creating a new request from a disturbed request
+PASS Check creating a new request with a new body from a disturbed request
+FAIL Input request used for creating new request became disturbed assert_equals: body should not change expected object "[object ReadableStream]" but got object "[object ReadableStream]"
+FAIL Input request used for creating new request became disturbed even if body is not used assert_equals: body should not change expected object "[object ReadableStream]" but got object "[object ReadableStream]"
+PASS Check consuming a disturbed request
+PASS Request construction failure should not set "bodyUsed"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-disturbed.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-disturbed.any.js
new file mode 100644
index 0000000..8a11de7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-disturbed.any.js
@@ -0,0 +1,109 @@
+// META: global=window,worker
+// META: title=Request disturbed
+// META: script=../resources/utils.js
+
+var initValuesDict = {"method" : "POST",
+                      "body" : "Request's body"
+};
+
+var noBodyConsumed = new Request("");
+var bodyConsumed = new Request("", initValuesDict);
+
+test(() => {
+  assert_equals(noBodyConsumed.body, null, "body's default value is null");
+  assert_false(noBodyConsumed.bodyUsed , "bodyUsed is false when request is not disturbed");
+  assert_not_equals(bodyConsumed.body, null, "non-null body");
+  assert_true(bodyConsumed.body instanceof ReadableStream, "non-null body type");
+  assert_false(noBodyConsumed.bodyUsed, "bodyUsed is false when request is not disturbed");
+}, "Request's body: initial state");
+
+noBodyConsumed.blob();
+bodyConsumed.blob();
+
+test(function() {
+  assert_false(noBodyConsumed.bodyUsed , "bodyUsed is false when request is not disturbed");
+  try {
+    noBodyConsumed.clone();
+  } catch (e) {
+    assert_unreached("Can use request not disturbed for creating or cloning request");
+  }
+}, "Request without body cannot be disturbed");
+
+test(function() {
+  assert_true(bodyConsumed.bodyUsed , "bodyUsed is true when request is disturbed");
+  assert_throws_js(TypeError, function() { bodyConsumed.clone(); });
+}, "Check cloning a disturbed request");
+
+test(function() {
+  assert_true(bodyConsumed.bodyUsed , "bodyUsed is true when request is disturbed");
+  assert_throws_js(TypeError, function() { new Request(bodyConsumed); });
+}, "Check creating a new request from a disturbed request");
+
+promise_test(function() {
+  assert_true(bodyConsumed.bodyUsed , "bodyUsed is true when request is disturbed");
+  const originalBody = bodyConsumed.body;
+  const bodyReplaced = new Request(bodyConsumed, { body: "Replaced body" });
+  assert_not_equals(bodyReplaced.body, originalBody, "new request's body is new");
+  assert_false(bodyReplaced.bodyUsed, "bodyUsed is false when request is not disturbed");
+  return bodyReplaced.text().then(text => {
+    assert_equals(text, "Replaced body");
+  });
+}, "Check creating a new request with a new body from a disturbed request");
+
+promise_test(function() {
+  var bodyRequest = new Request("", initValuesDict);
+  const originalBody = bodyRequest.body;
+  assert_false(bodyRequest.bodyUsed , "bodyUsed is false when request is not disturbed");
+  var requestFromRequest = new Request(bodyRequest);
+  assert_true(bodyRequest.bodyUsed , "bodyUsed is true when request is disturbed");
+  assert_equals(bodyRequest.body, originalBody, "body should not change");
+  assert_not_equals(originalBody, undefined, "body should not be undefined");
+  assert_not_equals(originalBody, null, "body should not be null");
+  assert_not_equals(requestFromRequest.body, originalBody, "new request's body is new");
+  return requestFromRequest.text().then(text => {
+    assert_equals(text, "Request's body");
+  });
+}, "Input request used for creating new request became disturbed");
+
+promise_test(() => {
+  const bodyRequest = new Request("", initValuesDict);
+  const originalBody = bodyRequest.body;
+  assert_false(bodyRequest.bodyUsed , "bodyUsed is false when request is not disturbed");
+  const requestFromRequest = new Request(bodyRequest, { body : "init body" });
+  assert_true(bodyRequest.bodyUsed , "bodyUsed is true when request is disturbed");
+  assert_equals(bodyRequest.body, originalBody, "body should not change");
+  assert_not_equals(originalBody, undefined, "body should not be undefined");
+  assert_not_equals(originalBody, null, "body should not be null");
+  assert_not_equals(requestFromRequest.body, originalBody, "new request's body is new");
+
+  return requestFromRequest.text().then(text => {
+    assert_equals(text, "init body");
+  });
+}, "Input request used for creating new request became disturbed even if body is not used");
+
+promise_test(function(test) {
+  assert_true(bodyConsumed.bodyUsed , "bodyUsed is true when request is disturbed");
+  return promise_rejects_js(test, TypeError, bodyConsumed.blob());
+}, "Check consuming a disturbed request");
+
+test(function() {
+  var req = new Request(URL, {method: 'POST', body: 'hello'});
+  assert_false(req.bodyUsed,
+                'Request should not be flagged as used if it has not been ' +
+                'consumed.');
+  assert_throws_js(TypeError,
+    function() { new Request(req, {method: 'GET'}); },
+    'A get request may not have body.');
+
+  assert_false(req.bodyUsed, 'After the GET case');
+
+  assert_throws_js(TypeError,
+    function() { new Request(req, {method: 'CONNECT'}); },
+    'Request() with a forbidden method must throw.');
+
+  assert_false(req.bodyUsed, 'After the forbidden method case');
+
+  var req2 = new Request(req);
+  assert_true(req.bodyUsed,
+              'Request should be flagged as used if it has been consumed.');
+}, 'Request construction failure should not set "bodyUsed"');
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-disturbed.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-disturbed.any.serviceworker-expected.txt
new file mode 100644
index 0000000..d46bdb8c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-disturbed.any.serviceworker-expected.txt
@@ -0,0 +1,12 @@
+This is a testharness.js-based test.
+PASS Request's body: initial state
+PASS Request without body cannot be disturbed
+PASS Check cloning a disturbed request
+PASS Check creating a new request from a disturbed request
+PASS Check creating a new request with a new body from a disturbed request
+FAIL Input request used for creating new request became disturbed assert_equals: body should not change expected object "[object ReadableStream]" but got object "[object ReadableStream]"
+FAIL Input request used for creating new request became disturbed even if body is not used assert_equals: body should not change expected object "[object ReadableStream]" but got object "[object ReadableStream]"
+PASS Check consuming a disturbed request
+PASS Request construction failure should not set "bodyUsed"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-disturbed.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-disturbed.any.sharedworker-expected.txt
new file mode 100644
index 0000000..d46bdb8c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-disturbed.any.sharedworker-expected.txt
@@ -0,0 +1,12 @@
+This is a testharness.js-based test.
+PASS Request's body: initial state
+PASS Request without body cannot be disturbed
+PASS Check cloning a disturbed request
+PASS Check creating a new request from a disturbed request
+PASS Check creating a new request with a new body from a disturbed request
+FAIL Input request used for creating new request became disturbed assert_equals: body should not change expected object "[object ReadableStream]" but got object "[object ReadableStream]"
+FAIL Input request used for creating new request became disturbed even if body is not used assert_equals: body should not change expected object "[object ReadableStream]" but got object "[object ReadableStream]"
+PASS Check consuming a disturbed request
+PASS Request construction failure should not set "bodyUsed"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-disturbed.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-disturbed.any.worker-expected.txt
new file mode 100644
index 0000000..d46bdb8c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-disturbed.any.worker-expected.txt
@@ -0,0 +1,12 @@
+This is a testharness.js-based test.
+PASS Request's body: initial state
+PASS Request without body cannot be disturbed
+PASS Check cloning a disturbed request
+PASS Check creating a new request from a disturbed request
+PASS Check creating a new request with a new body from a disturbed request
+FAIL Input request used for creating new request became disturbed assert_equals: body should not change expected object "[object ReadableStream]" but got object "[object ReadableStream]"
+FAIL Input request used for creating new request became disturbed even if body is not used assert_equals: body should not change expected object "[object ReadableStream]" but got object "[object ReadableStream]"
+PASS Check consuming a disturbed request
+PASS Request construction failure should not set "bodyUsed"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-disturbed.html b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-disturbed.html
deleted file mode 100644
index 18d8a334..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-disturbed.html
+++ /dev/null
@@ -1,121 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Request disturbed</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#request">
-    <meta name="help" href="https://fetch.spec.whatwg.org/#body-mixin">
-    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-  </head>
-  <body>
-    <script>
-      var initValuesDict = {"method" : "POST",
-                            "body" : "Request's body"
-      };
-
-      var noBodyConsumed = new Request("");
-      var bodyConsumed = new Request("", initValuesDict);
-
-      test(() => {
-        assert_equals(noBodyConsumed.body, null, "body's default value is null");
-        assert_false(noBodyConsumed.bodyUsed , "bodyUsed is false when request is not disturbed");
-        assert_not_equals(bodyConsumed.body, null, "non-null body");
-        assert_true(bodyConsumed.body instanceof ReadableStream, "non-null body type");
-        assert_false(noBodyConsumed.bodyUsed, "bodyUsed is false when request is not disturbed");
-      }, "Request's body: initial state");
-
-      noBodyConsumed.blob();
-      bodyConsumed.blob();
-
-      test(function() {
-        assert_false(noBodyConsumed.bodyUsed , "bodyUsed is false when request is not disturbed");
-        try {
-          noBodyConsumed.clone();
-        } catch (e) {
-          assert_unreached("Can use request not disturbed for creating or cloning request");
-        }
-      }, "Request without body cannot be disturbed");
-
-      test(function() {
-        assert_true(bodyConsumed.bodyUsed , "bodyUsed is true when request is disturbed");
-        assert_throws_js(TypeError, function() { bodyConsumed.clone(); });
-      }, "Check cloning a disturbed request");
-
-      test(function() {
-        assert_true(bodyConsumed.bodyUsed , "bodyUsed is true when request is disturbed");
-        assert_throws_js(TypeError, function() { new Request(bodyConsumed); });
-      }, "Check creating a new request from a disturbed request");
-
-      promise_test(function() {
-        assert_true(bodyConsumed.bodyUsed , "bodyUsed is true when request is disturbed");
-        const originalBody = bodyConsumed.body;
-        const bodyReplaced = new Request(bodyConsumed, { body: "Replaced body" });
-        assert_not_equals(bodyReplaced.body, originalBody, "new request's body is new");
-        assert_false(bodyReplaced.bodyUsed, "bodyUsed is false when request is not disturbed");
-        return bodyReplaced.text().then(text => {
-          assert_equals(text, "Replaced body");
-        });
-      }, "Check creating a new request with a new body from a disturbed request");
-
-      promise_test(function() {
-        var bodyRequest = new Request("", initValuesDict);
-        const originalBody = bodyRequest.body;
-        assert_false(bodyRequest.bodyUsed , "bodyUsed is false when request is not disturbed");
-        var requestFromRequest = new Request(bodyRequest);
-        assert_true(bodyRequest.bodyUsed , "bodyUsed is true when request is disturbed");
-        assert_equals(bodyRequest.body, originalBody, "body should not change");
-        assert_not_equals(originalBody, undefined, "body should not be undefined");
-        assert_not_equals(originalBody, null, "body should not be null");
-        assert_not_equals(requestFromRequest.body, originalBody, "new request's body is new");
-        return requestFromRequest.text().then(text => {
-          assert_equals(text, "Request's body");
-        });
-      }, "Input request used for creating new request became disturbed");
-
-      promise_test(() => {
-        const bodyRequest = new Request("", initValuesDict);
-        const originalBody = bodyRequest.body;
-        assert_false(bodyRequest.bodyUsed , "bodyUsed is false when request is not disturbed");
-        const requestFromRequest = new Request(bodyRequest, { body : "init body" });
-        assert_true(bodyRequest.bodyUsed , "bodyUsed is true when request is disturbed");
-        assert_equals(bodyRequest.body, originalBody, "body should not change");
-        assert_not_equals(originalBody, undefined, "body should not be undefined");
-        assert_not_equals(originalBody, null, "body should not be null");
-        assert_not_equals(requestFromRequest.body, originalBody, "new request's body is new");
-
-        return requestFromRequest.text().then(text => {
-          assert_equals(text, "init body");
-        });
-      }, "Input request used for creating new request became disturbed even if body is not used");
-
-      promise_test(function(test) {
-        assert_true(bodyConsumed.bodyUsed , "bodyUsed is true when request is disturbed");
-        return promise_rejects_js(test, TypeError, bodyConsumed.blob());
-      }, "Check consuming a disturbed request");
-
-      test(function() {
-        var req = new Request(URL, {method: 'POST', body: 'hello'});
-        assert_false(req.bodyUsed,
-                     'Request should not be flagged as used if it has not been ' +
-                     'consumed.');
-        assert_throws_js(TypeError,
-          function() { new Request(req, {method: 'GET'}); },
-          'A get request may not have body.');
-
-        assert_false(req.bodyUsed, 'After the GET case');
-
-        assert_throws_js(TypeError,
-          function() { new Request(req, {method: 'CONNECT'}); },
-          'Request() with a forbidden method must throw.');
-
-        assert_false(req.bodyUsed, 'After the forbidden method case');
-
-        var req2 = new Request(req);
-        assert_true(req.bodyUsed,
-                    'Request should be flagged as used if it has been consumed.');
-      }, 'Request construction failure should not set "bodyUsed"');
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-error.any-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-error.any-expected.txt
new file mode 100644
index 0000000..f3363b8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-error.any-expected.txt
@@ -0,0 +1,24 @@
+This is a testharness.js-based test.
+FAIL RequestInit's window is not null assert_throws_js: Expect TypeError exception function "() => new Request(...args)" did not throw
+PASS Input URL is not valid
+PASS Input URL has credentials
+PASS RequestInit's mode is navigate
+PASS RequestInit's referrer is invalid
+PASS RequestInit's method is invalid
+PASS RequestInit's method is forbidden
+PASS RequestInit's mode is no-cors and method is not simple
+PASS RequestInit's cache mode is only-if-cached and mode is not same-origin
+PASS Request with cache mode: only-if-cached and fetch mode cors
+PASS Request with cache mode: only-if-cached and fetch mode no-cors
+PASS Bad referrerPolicy init parameter value
+PASS Bad mode init parameter value
+PASS Bad credentials init parameter value
+PASS Bad cache init parameter value
+PASS Bad redirect init parameter value
+PASS Request should get its content-type from the init request
+PASS Request should not get its content-type from the init request if init headers are provided
+PASS Request should get its content-type from the body if none is provided
+PASS Request should get its content-type from init headers if one is provided
+PASS Request with cache mode: only-if-cached and fetch mode: same-origin
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-error.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-error.any.js
new file mode 100644
index 0000000..67ed70c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-error.any.js
@@ -0,0 +1,48 @@
+// META: global=window,worker
+// META: title=Request error
+// META: script=request-error.js
+
+// badRequestArgTests is from response-error.js
+for (const { args, testName } of badRequestArgTests) {
+  test(() => {
+    assert_throws_js(
+      TypeError,
+      () => new Request(...args),
+      "Expect TypeError exception"
+    );
+  }, testName);
+}
+
+test(function() {
+  var initialHeaders = new Headers([["Content-Type", "potato"]]);
+  var initialRequest = new Request("", {"headers" : initialHeaders});
+  var request = new Request(initialRequest);
+  assert_equals(request.headers.get("Content-Type"), "potato");
+}, "Request should get its content-type from the init request");
+
+test(function() {
+  var initialHeaders = new Headers([["Content-Type", "potato"]]);
+  var initialRequest = new Request("", {"headers" : initialHeaders});
+  var headers = new Headers([]);
+  var request = new Request(initialRequest, {"headers" : headers});
+  assert_false(request.headers.has("Content-Type"));
+}, "Request should not get its content-type from the init request if init headers are provided");
+
+test(function() {
+  var initialHeaders = new Headers([["Content-Type-Extra", "potato"]]);
+  var initialRequest = new Request("", {"headers" : initialHeaders, "body" : "this is my plate", "method" : "POST"});
+  var request = new Request(initialRequest);
+  assert_equals(request.headers.get("Content-Type"), "text/plain;charset=UTF-8");
+}, "Request should get its content-type from the body if none is provided");
+
+test(function() {
+  var initialHeaders = new Headers([["Content-Type", "potato"]]);
+  var initialRequest = new Request("", {"headers" : initialHeaders, "body" : "this is my plate", "method" : "POST"});
+  var request = new Request(initialRequest);
+  assert_equals(request.headers.get("Content-Type"), "potato");
+}, "Request should get its content-type from init headers if one is provided");
+
+test(function() {
+  var options = {"cache": "only-if-cached", "mode": "same-origin"};
+  new Request("test", options);
+}, "Request with cache mode: only-if-cached and fetch mode: same-origin");
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-error.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-error.any.serviceworker-expected.txt
new file mode 100644
index 0000000..f3363b8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-error.any.serviceworker-expected.txt
@@ -0,0 +1,24 @@
+This is a testharness.js-based test.
+FAIL RequestInit's window is not null assert_throws_js: Expect TypeError exception function "() => new Request(...args)" did not throw
+PASS Input URL is not valid
+PASS Input URL has credentials
+PASS RequestInit's mode is navigate
+PASS RequestInit's referrer is invalid
+PASS RequestInit's method is invalid
+PASS RequestInit's method is forbidden
+PASS RequestInit's mode is no-cors and method is not simple
+PASS RequestInit's cache mode is only-if-cached and mode is not same-origin
+PASS Request with cache mode: only-if-cached and fetch mode cors
+PASS Request with cache mode: only-if-cached and fetch mode no-cors
+PASS Bad referrerPolicy init parameter value
+PASS Bad mode init parameter value
+PASS Bad credentials init parameter value
+PASS Bad cache init parameter value
+PASS Bad redirect init parameter value
+PASS Request should get its content-type from the init request
+PASS Request should not get its content-type from the init request if init headers are provided
+PASS Request should get its content-type from the body if none is provided
+PASS Request should get its content-type from init headers if one is provided
+PASS Request with cache mode: only-if-cached and fetch mode: same-origin
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-error.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-error.any.sharedworker-expected.txt
new file mode 100644
index 0000000..f3363b8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-error.any.sharedworker-expected.txt
@@ -0,0 +1,24 @@
+This is a testharness.js-based test.
+FAIL RequestInit's window is not null assert_throws_js: Expect TypeError exception function "() => new Request(...args)" did not throw
+PASS Input URL is not valid
+PASS Input URL has credentials
+PASS RequestInit's mode is navigate
+PASS RequestInit's referrer is invalid
+PASS RequestInit's method is invalid
+PASS RequestInit's method is forbidden
+PASS RequestInit's mode is no-cors and method is not simple
+PASS RequestInit's cache mode is only-if-cached and mode is not same-origin
+PASS Request with cache mode: only-if-cached and fetch mode cors
+PASS Request with cache mode: only-if-cached and fetch mode no-cors
+PASS Bad referrerPolicy init parameter value
+PASS Bad mode init parameter value
+PASS Bad credentials init parameter value
+PASS Bad cache init parameter value
+PASS Bad redirect init parameter value
+PASS Request should get its content-type from the init request
+PASS Request should not get its content-type from the init request if init headers are provided
+PASS Request should get its content-type from the body if none is provided
+PASS Request should get its content-type from init headers if one is provided
+PASS Request with cache mode: only-if-cached and fetch mode: same-origin
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-error.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-error.any.worker-expected.txt
new file mode 100644
index 0000000..f3363b8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-error.any.worker-expected.txt
@@ -0,0 +1,24 @@
+This is a testharness.js-based test.
+FAIL RequestInit's window is not null assert_throws_js: Expect TypeError exception function "() => new Request(...args)" did not throw
+PASS Input URL is not valid
+PASS Input URL has credentials
+PASS RequestInit's mode is navigate
+PASS RequestInit's referrer is invalid
+PASS RequestInit's method is invalid
+PASS RequestInit's method is forbidden
+PASS RequestInit's mode is no-cors and method is not simple
+PASS RequestInit's cache mode is only-if-cached and mode is not same-origin
+PASS Request with cache mode: only-if-cached and fetch mode cors
+PASS Request with cache mode: only-if-cached and fetch mode no-cors
+PASS Bad referrerPolicy init parameter value
+PASS Bad mode init parameter value
+PASS Bad credentials init parameter value
+PASS Bad cache init parameter value
+PASS Bad redirect init parameter value
+PASS Request should get its content-type from the init request
+PASS Request should not get its content-type from the init request if init headers are provided
+PASS Request should get its content-type from the body if none is provided
+PASS Request should get its content-type from init headers if one is provided
+PASS Request with cache mode: only-if-cached and fetch mode: same-origin
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-error.html b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-error.html
deleted file mode 100644
index 622ba3f..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-error.html
+++ /dev/null
@@ -1,61 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Request error</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#request">
-    <meta name="help" href="https://fetch.spec.whatwg.org/#body-mixin">
-    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <script src="request-error.js"></script>
-  </head>
-  <body>
-    <script>
-      // badRequestArgTests is from response-error.js
-      for (const { args, testName } of badRequestArgTests) {
-        test(() => {
-          assert_throws_js(
-            TypeError,
-            () => new Request(...args),
-            "Expect TypeError exception"
-          );
-        }, testName);
-      }
-
-      test(function() {
-        var initialHeaders = new Headers([["Content-Type", "potato"]]);
-        var initialRequest = new Request("", {"headers" : initialHeaders});
-        var request = new Request(initialRequest);
-        assert_equals(request.headers.get("Content-Type"), "potato");
-      }, "Request should get its content-type from the init request");
-
-      test(function() {
-        var initialHeaders = new Headers([["Content-Type", "potato"]]);
-        var initialRequest = new Request("", {"headers" : initialHeaders});
-        var headers = new Headers([]);
-        var request = new Request(initialRequest, {"headers" : headers});
-        assert_false(request.headers.has("Content-Type"));
-      }, "Request should not get its content-type from the init request if init headers are provided");
-
-      test(function() {
-        var initialHeaders = new Headers([["Content-Type-Extra", "potato"]]);
-        var initialRequest = new Request("", {"headers" : initialHeaders, "body" : "this is my plate", "method" : "POST"});
-        var request = new Request(initialRequest);
-        assert_equals(request.headers.get("Content-Type"), "text/plain;charset=UTF-8");
-      }, "Request should get its content-type from the body if none is provided");
-
-      test(function() {
-        var initialHeaders = new Headers([["Content-Type", "potato"]]);
-        var initialRequest = new Request("", {"headers" : initialHeaders, "body" : "this is my plate", "method" : "POST"});
-        var request = new Request(initialRequest);
-        assert_equals(request.headers.get("Content-Type"), "potato");
-      }, "Request should get its content-type from init headers if one is provided");
-
-      test(function() {
-        var options = {"cache": "only-if-cached", "mode": "same-origin"};
-        new Request("test", options);
-      }, "Request with cache mode: only-if-cached and fetch mode: same-origin");
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-headers.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-headers.any.js
new file mode 100644
index 0000000..c48e24e5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-headers.any.js
@@ -0,0 +1,173 @@
+// META: global=window,worker
+// META: title=Request Headers
+
+var validRequestHeaders = [
+  ["Content-Type", "OK"],
+  ["Potato", "OK"],
+  ["proxy", "OK"],
+  ["proxya", "OK"],
+  ["sec", "OK"],
+  ["secb", "OK"],
+];
+var invalidRequestHeaders = [
+  ["Accept-Charset", "KO"],
+  ["accept-charset", "KO"],
+  ["ACCEPT-ENCODING", "KO"],
+  ["Accept-Encoding", "KO"],
+  ["Access-Control-Request-Headers", "KO"],
+  ["Access-Control-Request-Method", "KO"],
+  ["Connection", "KO"],
+  ["Content-Length", "KO"],
+  ["Cookie", "KO"],
+  ["Cookie2", "KO"],
+  ["Date", "KO"],
+  ["DNT", "KO"],
+  ["Expect", "KO"],
+  ["Host", "KO"],
+  ["Keep-Alive", "KO"],
+  ["Origin", "KO"],
+  ["Referer", "KO"],
+  ["TE", "KO"],
+  ["Trailer", "KO"],
+  ["Transfer-Encoding", "KO"],
+  ["Upgrade", "KO"],
+  ["Via", "KO"],
+  ["Proxy-", "KO"],
+  ["proxy-a", "KO"],
+  ["Sec-", "KO"],
+  ["sec-b", "KO"],
+];
+
+var validRequestNoCorsHeaders = [
+  ["Accept", "OK"],
+  ["Accept-Language", "OK"],
+  ["content-language", "OK"],
+  ["content-type", "application/x-www-form-urlencoded"],
+  ["content-type", "application/x-www-form-urlencoded;charset=UTF-8"],
+  ["content-type", "multipart/form-data"],
+  ["content-type", "multipart/form-data;charset=UTF-8"],
+  ["content-TYPE", "text/plain"],
+  ["CONTENT-type", "text/plain;charset=UTF-8"],
+];
+var invalidRequestNoCorsHeaders = [
+  ["Content-Type", "KO"],
+  ["Potato", "KO"],
+  ["proxy", "KO"],
+  ["proxya", "KO"],
+  ["sec", "KO"],
+  ["secb", "KO"],
+];
+
+validRequestHeaders.forEach(function(header) {
+  test(function() {
+    var request = new Request("");
+    request.headers.set(header[0], header[1]);
+    assert_equals(request.headers.get(header[0]), header[1]);
+  }, "Adding valid request header \"" + header[0] + ": " + header[1] + "\"");
+});
+invalidRequestHeaders.forEach(function(header) {
+  test(function() {
+    var request = new Request("");
+    request.headers.set(header[0], header[1]);
+    assert_equals(request.headers.get(header[0]), null);
+  }, "Adding invalid request header \"" + header[0] + ": " + header[1] + "\"");
+});
+
+validRequestNoCorsHeaders.forEach(function(header) {
+  test(function() {
+    var requestNoCors = new Request("", {"mode": "no-cors"});
+    requestNoCors.headers.set(header[0], header[1]);
+    assert_equals(requestNoCors.headers.get(header[0]), header[1]);
+  }, "Adding valid no-cors request header \"" + header[0] + ": " + header[1] + "\"");
+});
+invalidRequestNoCorsHeaders.forEach(function(header) {
+  test(function() {
+    var requestNoCors = new Request("", {"mode": "no-cors"});
+    requestNoCors.headers.set(header[0], header[1]);
+    assert_equals(requestNoCors.headers.get(header[0]), null);
+  }, "Adding invalid no-cors request header \"" + header[0] + ": " + header[1] + "\"");
+});
+
+test(function() {
+  var headers = new Headers([["Cookie2", "potato"]]);
+  var request = new Request("", {"headers": headers});
+  assert_equals(request.headers.get("Cookie2"), null);
+}, "Check that request constructor is filtering headers provided as init parameter");
+
+test(function() {
+  var headers = new Headers([["Content-Type", "potato"]]);
+  var request = new Request("", {"headers": headers, "mode": "no-cors"});
+  assert_equals(request.headers.get("Content-Type"), null);
+}, "Check that no-cors request constructor is filtering headers provided as init parameter");
+
+test(function() {
+  var headers = new Headers([["Content-Type", "potato"]]);
+  var initialRequest = new Request("", {"headers": headers});
+  var request = new Request(initialRequest, {"mode": "no-cors"});
+  assert_equals(request.headers.get("Content-Type"), null);
+}, "Check that no-cors request constructor is filtering headers provided as part of request parameter");
+
+test(function() {
+  var initialHeaders = new Headers([["Content-Type", "potato"]]);
+  var initialRequest = new Request("", {"headers" : initialHeaders});
+  var request = new Request(initialRequest);
+  assert_equals(request.headers.get("Content-Type"), "potato");
+}, "Request should get its content-type from the init request");
+
+test(function() {
+  var initialHeaders = new Headers([["Content-Type", "potato"]]);
+  var initialRequest = new Request("", {"headers" : initialHeaders});
+  var headers = new Headers([]);
+  var request = new Request(initialRequest, {"headers" : headers});
+  assert_false(request.headers.has("Content-Type"));
+}, "Request should not get its content-type from the init request if init headers are provided");
+
+test(function() {
+  var initialHeaders = new Headers([["Content-Type-Extra", "potato"]]);
+  var initialRequest = new Request("", {"headers" : initialHeaders, "body" : "this is my plate", "method" : "POST"});
+  var request = new Request(initialRequest);
+  assert_equals(request.headers.get("Content-Type"), "text/plain;charset=UTF-8");
+}, "Request should get its content-type from the body if none is provided");
+
+test(function() {
+  var initialHeaders = new Headers([["Content-Type", "potato"]]);
+  var initialRequest = new Request("", {"headers" : initialHeaders, "body" : "this is my plate", "method" : "POST"});
+  var request = new Request(initialRequest);
+  assert_equals(request.headers.get("Content-Type"), "potato");
+}, "Request should get its content-type from init headers if one is provided");
+
+test(function() {
+  var array = [["hello", "worldAHH"]];
+  var object = {"hello": 'worldOOH'};
+  var headers = new Headers(array);
+
+  assert_equals(headers.get("hello"), "worldAHH");
+
+  var request1 = new Request("", {"headers": headers});
+  var request2 = new Request("", {"headers": array});
+  var request3 = new Request("", {"headers": object});
+
+  assert_equals(request1.headers.get("hello"), "worldAHH");
+  assert_equals(request2.headers.get("hello"), "worldAHH");
+  assert_equals(request3.headers.get("hello"), "worldOOH");
+}, "Testing request header creations with various objects");
+
+promise_test(function(test) {
+  var request = new Request("", {"headers" : [["Content-Type", ""]], "body" : "this is my plate", "method" : "POST"});
+  return request.blob().then(function(blob) {
+    assert_equals(blob.type, "", "Blob type should be the empty string");
+  });
+}, "Testing empty Request Content-Type header");
+
+test(function() {
+  const request1 = new Request("");
+  assert_equals(request1.headers, request1.headers);
+
+  const request2 = new Request("", {"headers": {"X-Foo": "bar"}});
+  assert_equals(request2.headers, request2.headers);
+  const headers = request2.headers;
+  request2.headers.set("X-Foo", "quux");
+  assert_equals(headers, request2.headers);
+  headers.set("X-Other-Header", "baz");
+  assert_equals(headers, request2.headers);
+}, "Test that Request.headers has the [SameObject] extended attribute");
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-headers.html b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-headers.html
deleted file mode 100644
index 014f2fb..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-headers.html
+++ /dev/null
@@ -1,186 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Request Headers</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#request">
-    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-  </head>
-  <body>
-    <script>
-      var validRequestHeaders = [
-        ["Content-Type", "OK"],
-        ["Potato", "OK"],
-        ["proxy", "OK"],
-        ["proxya", "OK"],
-        ["sec", "OK"],
-        ["secb", "OK"],
-      ];
-      var invalidRequestHeaders = [
-        ["Accept-Charset", "KO"],
-        ["accept-charset", "KO"],
-        ["ACCEPT-ENCODING", "KO"],
-        ["Accept-Encoding", "KO"],
-        ["Access-Control-Request-Headers", "KO"],
-        ["Access-Control-Request-Method", "KO"],
-        ["Connection", "KO"],
-        ["Content-Length", "KO"],
-        ["Cookie", "KO"],
-        ["Cookie2", "KO"],
-        ["Date", "KO"],
-        ["DNT", "KO"],
-        ["Expect", "KO"],
-        ["Host", "KO"],
-        ["Keep-Alive", "KO"],
-        ["Origin", "KO"],
-        ["Referer", "KO"],
-        ["TE", "KO"],
-        ["Trailer", "KO"],
-        ["Transfer-Encoding", "KO"],
-        ["Upgrade", "KO"],
-        ["Via", "KO"],
-        ["Proxy-", "KO"],
-        ["proxy-a", "KO"],
-        ["Sec-", "KO"],
-        ["sec-b", "KO"],
-      ];
-
-      var validRequestNoCorsHeaders = [
-        ["Accept", "OK"],
-        ["Accept-Language", "OK"],
-        ["content-language", "OK"],
-        ["content-type", "application/x-www-form-urlencoded"],
-        ["content-type", "application/x-www-form-urlencoded;charset=UTF-8"],
-        ["content-type", "multipart/form-data"],
-        ["content-type", "multipart/form-data;charset=UTF-8"],
-        ["content-TYPE", "text/plain"],
-        ["CONTENT-type", "text/plain;charset=UTF-8"],
-      ];
-      var invalidRequestNoCorsHeaders = [
-        ["Content-Type", "KO"],
-        ["Potato", "KO"],
-        ["proxy", "KO"],
-        ["proxya", "KO"],
-        ["sec", "KO"],
-        ["secb", "KO"],
-      ];
-
-      validRequestHeaders.forEach(function(header) {
-        test(function() {
-          var request = new Request("");
-          request.headers.set(header[0], header[1]);
-          assert_equals(request.headers.get(header[0]), header[1]);
-        }, "Adding valid request header \"" + header[0] + ": " + header[1] + "\"");
-      });
-      invalidRequestHeaders.forEach(function(header) {
-        test(function() {
-          var request = new Request("");
-          request.headers.set(header[0], header[1]);
-          assert_equals(request.headers.get(header[0]), null);
-        }, "Adding invalid request header \"" + header[0] + ": " + header[1] + "\"");
-      });
-
-      validRequestNoCorsHeaders.forEach(function(header) {
-        test(function() {
-          var requestNoCors = new Request("", {"mode": "no-cors"});
-          requestNoCors.headers.set(header[0], header[1]);
-          assert_equals(requestNoCors.headers.get(header[0]), header[1]);
-        }, "Adding valid no-cors request header \"" + header[0] + ": " + header[1] + "\"");
-      });
-      invalidRequestNoCorsHeaders.forEach(function(header) {
-        test(function() {
-          var requestNoCors = new Request("", {"mode": "no-cors"});
-          requestNoCors.headers.set(header[0], header[1]);
-          assert_equals(requestNoCors.headers.get(header[0]), null);
-        }, "Adding invalid no-cors request header \"" + header[0] + ": " + header[1] + "\"");
-      });
-
-      test(function() {
-        var headers = new Headers([["Cookie2", "potato"]]);
-        var request = new Request("", {"headers": headers});
-        assert_equals(request.headers.get("Cookie2"), null);
-      }, "Check that request constructor is filtering headers provided as init parameter");
-
-      test(function() {
-        var headers = new Headers([["Content-Type", "potato"]]);
-        var request = new Request("", {"headers": headers, "mode": "no-cors"});
-        assert_equals(request.headers.get("Content-Type"), null);
-      }, "Check that no-cors request constructor is filtering headers provided as init parameter");
-
-      test(function() {
-        var headers = new Headers([["Content-Type", "potato"]]);
-        var initialRequest = new Request("", {"headers": headers});
-        var request = new Request(initialRequest, {"mode": "no-cors"});
-        assert_equals(request.headers.get("Content-Type"), null);
-      }, "Check that no-cors request constructor is filtering headers provided as part of request parameter");
-
-      test(function() {
-        var initialHeaders = new Headers([["Content-Type", "potato"]]);
-        var initialRequest = new Request("", {"headers" : initialHeaders});
-        var request = new Request(initialRequest);
-        assert_equals(request.headers.get("Content-Type"), "potato");
-      }, "Request should get its content-type from the init request");
-
-      test(function() {
-        var initialHeaders = new Headers([["Content-Type", "potato"]]);
-        var initialRequest = new Request("", {"headers" : initialHeaders});
-        var headers = new Headers([]);
-        var request = new Request(initialRequest, {"headers" : headers});
-        assert_false(request.headers.has("Content-Type"));
-      }, "Request should not get its content-type from the init request if init headers are provided");
-
-      test(function() {
-        var initialHeaders = new Headers([["Content-Type-Extra", "potato"]]);
-        var initialRequest = new Request("", {"headers" : initialHeaders, "body" : "this is my plate", "method" : "POST"});
-        var request = new Request(initialRequest);
-        assert_equals(request.headers.get("Content-Type"), "text/plain;charset=UTF-8");
-      }, "Request should get its content-type from the body if none is provided");
-
-      test(function() {
-        var initialHeaders = new Headers([["Content-Type", "potato"]]);
-        var initialRequest = new Request("", {"headers" : initialHeaders, "body" : "this is my plate", "method" : "POST"});
-        var request = new Request(initialRequest);
-        assert_equals(request.headers.get("Content-Type"), "potato");
-      }, "Request should get its content-type from init headers if one is provided");
-
-      test(function() {
-        var array = [["hello", "worldAHH"]];
-        var object = {"hello": 'worldOOH'};
-        var headers = new Headers(array);
-
-        assert_equals(headers.get("hello"), "worldAHH");
-
-        var request1 = new Request("", {"headers": headers});
-        var request2 = new Request("", {"headers": array});
-        var request3 = new Request("", {"headers": object});
-
-        assert_equals(request1.headers.get("hello"), "worldAHH");
-        assert_equals(request2.headers.get("hello"), "worldAHH");
-        assert_equals(request3.headers.get("hello"), "worldOOH");
-      }, "Testing request header creations with various objects");
-
-      promise_test(function(test) {
-        var request = new Request("", {"headers" : [["Content-Type", ""]], "body" : "this is my plate", "method" : "POST"});
-        return request.blob().then(function(blob) {
-          assert_equals(blob.type, "", "Blob type should be the empty string");
-        });
-      }, "Testing empty Request Content-Type header");
-
-      test(function() {
-        const request1 = new Request("");
-        assert_equals(request1.headers, request1.headers);
-
-        const request2 = new Request("", {"headers": {"X-Foo": "bar"}});
-        assert_equals(request2.headers, request2.headers);
-        const headers = request2.headers;
-        request2.headers.set("X-Foo", "quux");
-        assert_equals(headers, request2.headers);
-        headers.set("X-Other-Header", "baz");
-        assert_equals(headers, request2.headers);
-      }, "Test that Request.headers has the [SameObject] extended attribute");
-
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-init-002.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-init-002.any.js
new file mode 100644
index 0000000..abb6689f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-init-002.any.js
@@ -0,0 +1,60 @@
+// META: global=window,worker
+// META: title=Request init: headers and body
+
+test(function() {
+  var headerDict = {"name1": "value1",
+                    "name2": "value2",
+                    "name3": "value3"
+                    };
+  var headers = new Headers(headerDict);
+  var request = new Request("", { "headers" : headers })
+  for (var name in headerDict) {
+    assert_equals(request.headers.get(name), headerDict[name],
+      "request's headers has " + name + " : " + headerDict[name]);
+  }
+}, "Initialize Request with headers values");
+
+function makeRequestInit(body, method) {
+  return {"method": method, "body": body};
+}
+
+function checkRequestInit(body, bodyType, expectedTextBody) {
+  promise_test(function(test) {
+    var request = new Request("", makeRequestInit(body, "POST"));
+    if (body) {
+      assert_throws_js(TypeError, function() { new Request("", makeRequestInit(body, "GET")); });
+      assert_throws_js(TypeError, function() { new Request("", makeRequestInit(body, "HEAD")); });
+    } else {
+      new Request("", makeRequestInit(body, "GET")); // should not throw
+    }
+    var reqHeaders = request.headers;
+    var mime = reqHeaders.get("Content-Type");
+    assert_true(!body || (mime && mime.search(bodyType) > -1), "Content-Type header should be \"" + bodyType + "\", not \"" + mime + "\"");
+    return request.text().then(function(bodyAsText) {
+      //not equals: cannot guess formData exact value
+      assert_true( bodyAsText.search(expectedTextBody) > -1, "Retrieve and verify request body");
+    });
+  }, `Initialize Request's body with "${body}", ${bodyType}`);
+}
+
+var blob = new Blob(["This is a blob"], {type: "application/octet-binary"});
+var formaData = new FormData();
+formaData.append("name", "value");
+var usvString = "This is a USVString"
+
+checkRequestInit(undefined, undefined, "");
+checkRequestInit(null, null, "");
+checkRequestInit(blob, "application/octet-binary", "This is a blob");
+checkRequestInit(formaData, "multipart/form-data", "name=\"name\"\r\n\r\nvalue");
+checkRequestInit(usvString, "text/plain;charset=UTF-8", "This is a USVString");
+checkRequestInit({toString: () => "hi!"}, "text/plain;charset=UTF-8", "hi!");
+
+// Ensure test does not time out in case of missing URLSearchParams support.
+if (self.URLSearchParams) {
+  var urlSearchParams = new URLSearchParams("name=value");
+  checkRequestInit(urlSearchParams, "application/x-www-form-urlencoded;charset=UTF-8", "name=value");
+} else {
+  promise_test(function(test) {
+    return Promise.reject("URLSearchParams not supported");
+  }, "Initialize Request's body with application/x-www-form-urlencoded;charset=UTF-8");
+}
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-init-002.html b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-init-002.html
deleted file mode 100644
index 14be277..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-init-002.html
+++ /dev/null
@@ -1,72 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Request init: headers and body</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#request">
-    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-  </head>
-  <body>
-    <script>
-      test(function() {
-        var headerDict = {"name1": "value1",
-                          "name2": "value2",
-                          "name3": "value3"
-                         };
-        var headers = new Headers(headerDict);
-        var request = new Request("", { "headers" : headers })
-        for (var name in headerDict) {
-          assert_equals(request.headers.get(name), headerDict[name],
-           "request's headers has " + name + " : " + headerDict[name]);
-        }
-      }, "Initialize Request with headers values");
-
-      function makeRequestInit(body, method) {
-        return {"method": method, "body": body};
-      }
-
-      function checkRequestInit(body, bodyType, expectedTextBody) {
-        promise_test(function(test) {
-          var request = new Request("", makeRequestInit(body, "POST"));
-          if (body) {
-            assert_throws_js(TypeError, function() { new Request("", makeRequestInit(body, "GET")); });
-            assert_throws_js(TypeError, function() { new Request("", makeRequestInit(body, "HEAD")); });
-          } else {
-            new Request("", makeRequestInit(body, "GET")); // should not throw
-          }
-          var reqHeaders = request.headers;
-          var mime = reqHeaders.get("Content-Type");
-          assert_true(!body || (mime && mime.search(bodyType) > -1), "Content-Type header should be \"" + bodyType + "\", not \"" + mime + "\"");
-          return request.text().then(function(bodyAsText) {
-            //not equals: cannot guess formData exact value
-            assert_true( bodyAsText.search(expectedTextBody) > -1, "Retrieve and verify request body");
-          });
-        }, `Initialize Request's body with "${body}", ${bodyType}`);
-      }
-
-      var blob = new Blob(["This is a blob"], {type: "application/octet-binary"});
-      var formaData = new FormData();
-      formaData.append("name", "value");
-      var usvString = "This is a USVString"
-
-      checkRequestInit(undefined, undefined, "");
-      checkRequestInit(null, null, "");
-      checkRequestInit(blob, "application/octet-binary", "This is a blob");
-      checkRequestInit(formaData, "multipart/form-data", "name=\"name\"\r\n\r\nvalue");
-      checkRequestInit(usvString, "text/plain;charset=UTF-8", "This is a USVString");
-      checkRequestInit({toString: () => "hi!"}, "text/plain;charset=UTF-8", "hi!");
-
-      // Ensure test does not time out in case of missing URLSearchParams support.
-      if (window.URLSearchParams) {
-        var urlSearchParams = new URLSearchParams("name=value");
-        checkRequestInit(urlSearchParams, "application/x-www-form-urlencoded;charset=UTF-8", "name=value");
-      } else {
-        promise_test(function(test) {
-          return Promise.reject("URLSearchParams not supported");
-        }, "Initialize Request's body with application/x-www-form-urlencoded;charset=UTF-8");
-      }
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-keepalive.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-keepalive.any.js
new file mode 100644
index 0000000..cb4506d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-keepalive.any.js
@@ -0,0 +1,17 @@
+// META: global=window,worker
+// META: title=Request keepalive
+// META: script=/common/utils.js
+// META: script=/common/get-host-info.sub.js
+
+test(() => {
+  assert_false(new Request('/').keepalive, 'default');
+  assert_true(new Request('/', {keepalive: true}).keepalive, 'true');
+  assert_false(new Request('/', {keepalive: false}).keepalive, 'false');
+  assert_true(new Request('/', {keepalive: 1}).keepalive, 'truish');
+  assert_false(new Request('/', {keepalive: 0}).keepalive, 'falsy');
+}, 'keepalive flag');
+
+test(() => {
+  const init = {method: 'POST', keepalive: true, body: new ReadableStream()};
+  assert_throws_js(TypeError, () => {new Request('/', init)});
+}, 'keepalive flag with stream body');
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-keepalive.html b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-keepalive.html
deleted file mode 100644
index e165422..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-keepalive.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<!doctype html>
-<html>
-<head>
-<meta charset="utf-8">
-<title>Request keepalive</title>
-<meta name="help" href="https://fetch.spec.whatwg.org/#request">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/common/utils.js"></script>
-<script src="/common/get-host-info.sub.js"></script>
-</head>
-<body>
-<script>
-test(() => {
-  assert_false(new Request('/').keepalive, 'default');
-  assert_true(new Request('/', {keepalive: true}).keepalive, 'true');
-  assert_false(new Request('/', {keepalive: false}).keepalive, 'false');
-  assert_true(new Request('/', {keepalive: 1}).keepalive, 'truish');
-  assert_false(new Request('/', {keepalive: 0}).keepalive, 'falsy');
-}, 'keepalive flag');
-
-test(() => {
-  const init = {method: 'POST', keepalive: true, body: new ReadableStream()};
-  assert_throws_js(TypeError, () => {new Request('/', init)});
-}, 'keepalive flag with stream body');
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-structure.any-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-structure.any-expected.txt
new file mode 100644
index 0000000..fcdfb85
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-structure.any-expected.txt
@@ -0,0 +1,23 @@
+This is a testharness.js-based test.
+PASS Request has clone method
+PASS Request has arrayBuffer method
+PASS Request has blob method
+PASS Request has formData method
+PASS Request has json method
+PASS Request has text method
+PASS Check method attribute
+PASS Check url attribute
+PASS Check headers attribute
+PASS Check destination attribute
+PASS Check referrer attribute
+PASS Check referrerPolicy attribute
+PASS Check mode attribute
+PASS Check credentials attribute
+PASS Check cache attribute
+PASS Check redirect attribute
+PASS Check integrity attribute
+FAIL Check isReloadNavigation attribute assert_true: request has isReloadNavigation attribute expected true got false
+PASS Check isHistoryNavigation attribute
+PASS Check bodyUsed attribute
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-structure.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-structure.any.js
new file mode 100644
index 0000000..65f1b96
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-structure.any.js
@@ -0,0 +1,128 @@
+// META: global=window,worker
+// META: title=Request structure
+
+var request = new Request("");
+var methods = ["clone",
+                //Request implements Body
+                "arrayBuffer",
+                "blob",
+                "formData",
+                "json",
+                "text"
+              ];
+var attributes = ["method",
+                  "url",
+                  "headers",
+                  "destination",
+                  "referrer",
+                  "referrerPolicy",
+                  "mode",
+                  "credentials",
+                  "cache",
+                  "redirect",
+                  "integrity",
+                  "isReloadNavigation",
+                  "isHistoryNavigation",
+                  //Request implements Body
+                  "bodyUsed"
+                  ];
+
+function IsreadOnly(request, attributeToCheck) {
+  var defaultValue = undefined;
+  var newValue = undefined;
+  switch (attributeToCheck) {
+    case "method":
+      defaultValue = "GET";
+      newValue = "POST";
+      break;
+
+    case "url":
+      //default value is base url
+      //i.e http://example.com/fetch/api/request-structure.html
+      newValue = "http://url.test";
+      break;
+
+    case "headers":
+      request.headers = new Headers ({"name":"value"});
+      assert_false(request.headers.has("name"), "Headers attribute is read only");
+      return;
+      break;
+
+    case "destination":
+      defaultValue = "";
+      newValue = "worker";
+      break;
+
+    case "referrer":
+      defaultValue = "about:client";
+      newValue = "http://url.test";
+      break;
+
+    case "referrerPolicy":
+      defaultValue = "";
+      newValue = "unsafe-url";
+      break;
+
+    case "mode":
+      defaultValue = "cors";
+      newValue = "navigate";
+      break;
+
+    case "credentials":
+      defaultValue = "same-origin";
+      newValue = "cors";
+      break;
+
+    case "cache":
+      defaultValue = "default";
+      newValue = "reload";
+      break;
+
+    case "redirect":
+      defaultValue = "follow";
+      newValue = "manual";
+      break;
+
+    case "integrity":
+      newValue = "CannotWriteIntegrity";
+      break;
+
+    case "bodyUsed":
+      defaultValue = false;
+      newValue = true;
+      break;
+
+    case "isReloadNavigation":
+      defaultValue = false;
+      newValue = true;
+      break;
+
+    case "isHistoryNavigation":
+      defaultValue = false;
+      newValue = true;
+      break;
+
+    default:
+      return;
+  }
+
+  request[attributeToCheck] = newValue;
+  if (defaultValue === undefined)
+    assert_not_equals(request[attributeToCheck], newValue, "Attribute " + attributeToCheck + " is read only");
+  else
+    assert_equals(request[attributeToCheck], defaultValue,
+      "Attribute " + attributeToCheck + " is read only. Default value is " + defaultValue);
+}
+
+for (var idx in methods) {
+  test(function() {
+    assert_true(methods[idx] in request, "request has " + methods[idx] + " method");
+  }, "Request has " + methods[idx] + " method");
+}
+
+for (var idx in attributes) {
+  test(function() {
+    assert_true(attributes[idx] in request, "request has " + attributes[idx] + " attribute");
+    IsreadOnly(request, attributes[idx]);
+  }, "Check " + attributes[idx] + " attribute");
+}
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-structure.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-structure.any.serviceworker-expected.txt
new file mode 100644
index 0000000..fcdfb85
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-structure.any.serviceworker-expected.txt
@@ -0,0 +1,23 @@
+This is a testharness.js-based test.
+PASS Request has clone method
+PASS Request has arrayBuffer method
+PASS Request has blob method
+PASS Request has formData method
+PASS Request has json method
+PASS Request has text method
+PASS Check method attribute
+PASS Check url attribute
+PASS Check headers attribute
+PASS Check destination attribute
+PASS Check referrer attribute
+PASS Check referrerPolicy attribute
+PASS Check mode attribute
+PASS Check credentials attribute
+PASS Check cache attribute
+PASS Check redirect attribute
+PASS Check integrity attribute
+FAIL Check isReloadNavigation attribute assert_true: request has isReloadNavigation attribute expected true got false
+PASS Check isHistoryNavigation attribute
+PASS Check bodyUsed attribute
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-structure.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-structure.any.sharedworker-expected.txt
new file mode 100644
index 0000000..fcdfb85
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-structure.any.sharedworker-expected.txt
@@ -0,0 +1,23 @@
+This is a testharness.js-based test.
+PASS Request has clone method
+PASS Request has arrayBuffer method
+PASS Request has blob method
+PASS Request has formData method
+PASS Request has json method
+PASS Request has text method
+PASS Check method attribute
+PASS Check url attribute
+PASS Check headers attribute
+PASS Check destination attribute
+PASS Check referrer attribute
+PASS Check referrerPolicy attribute
+PASS Check mode attribute
+PASS Check credentials attribute
+PASS Check cache attribute
+PASS Check redirect attribute
+PASS Check integrity attribute
+FAIL Check isReloadNavigation attribute assert_true: request has isReloadNavigation attribute expected true got false
+PASS Check isHistoryNavigation attribute
+PASS Check bodyUsed attribute
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-structure.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-structure.any.worker-expected.txt
new file mode 100644
index 0000000..fcdfb85
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-structure.any.worker-expected.txt
@@ -0,0 +1,23 @@
+This is a testharness.js-based test.
+PASS Request has clone method
+PASS Request has arrayBuffer method
+PASS Request has blob method
+PASS Request has formData method
+PASS Request has json method
+PASS Request has text method
+PASS Check method attribute
+PASS Check url attribute
+PASS Check headers attribute
+PASS Check destination attribute
+PASS Check referrer attribute
+PASS Check referrerPolicy attribute
+PASS Check mode attribute
+PASS Check credentials attribute
+PASS Check cache attribute
+PASS Check redirect attribute
+PASS Check integrity attribute
+FAIL Check isReloadNavigation attribute assert_true: request has isReloadNavigation attribute expected true got false
+PASS Check isHistoryNavigation attribute
+PASS Check bodyUsed attribute
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-structure.html b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-structure.html
deleted file mode 100644
index e137a7e..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-structure.html
+++ /dev/null
@@ -1,140 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Request structure</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#request">
-    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-  </head>
-  <body>
-    <script>
-      var request = new Request("");
-      var methods = ["clone",
-                     //Request implements Body
-                     "arrayBuffer",
-                     "blob",
-                     "formData",
-                     "json",
-                     "text"
-                    ];
-      var attributes = ["method",
-                        "url",
-                        "headers",
-                        "destination",
-                        "referrer",
-                        "referrerPolicy",
-                        "mode",
-                        "credentials",
-                        "cache",
-                        "redirect",
-                        "integrity",
-                        "isReloadNavigation",
-                        "isHistoryNavigation",
-                        //Request implements Body
-                        "bodyUsed"
-                       ];
-
-      function IsreadOnly(request, attributeToCheck) {
-        var defaultValue = undefined;
-        var newValue = undefined;
-        switch (attributeToCheck) {
-          case "method":
-            defaultValue = "GET";
-            newValue = "POST";
-            break;
-
-          case "url":
-            //default value is base url
-            //i.e http://example.com/fetch/api/request-structure.html
-            newValue = "http://url.test";
-            break;
-
-          case "headers":
-            request.headers = new Headers ({"name":"value"});
-            assert_false(request.headers.has("name"), "Headers attribute is read only");
-            return;
-            break;
-
-          case "destination":
-            defaultValue = "";
-            newValue = "worker";
-            break;
-
-          case "referrer":
-            defaultValue = "about:client";
-            newValue = "http://url.test";
-            break;
-
-          case "referrerPolicy":
-            defaultValue = "";
-            newValue = "unsafe-url";
-            break;
-
-          case "mode":
-            defaultValue = "cors";
-            newValue = "navigate";
-            break;
-
-          case "credentials":
-            defaultValue = "same-origin";
-            newValue = "cors";
-            break;
-
-          case "cache":
-            defaultValue = "default";
-            newValue = "reload";
-            break;
-
-          case "redirect":
-            defaultValue = "follow";
-            newValue = "manual";
-            break;
-
-          case "integrity":
-            newValue = "CannotWriteIntegrity";
-            break;
-
-          case "bodyUsed":
-            defaultValue = false;
-            newValue = true;
-            break;
-
-          case "isReloadNavigation":
-            defaultValue = false;
-            newValue = true;
-            break;
-
-          case "isHistoryNavigation":
-            defaultValue = false;
-            newValue = true;
-            break;
-
-          default:
-            return;
-        }
-
-        request[attributeToCheck] = newValue;
-        if (defaultValue === undefined)
-          assert_not_equals(request[attributeToCheck], newValue, "Attribute " + attributeToCheck + " is read only");
-        else
-          assert_equals(request[attributeToCheck], defaultValue,
-           "Attribute " + attributeToCheck + " is read only. Default value is " + defaultValue);
-      }
-
-      for (var idx in methods) {
-        test(function() {
-          assert_true(methods[idx] in request, "request has " + methods[idx] + " method");
-        }, "Request has " + methods[idx] + " method");
-      }
-
-      for (var idx in attributes) {
-        test(function() {
-          assert_true(attributes[idx] in request, "request has " + attributes[idx] + " attribute");
-          IsreadOnly(request, attributes[idx]);
-        }, "Check " + attributes[idx] + " attribute");
-      }
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-cancel-stream.html b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-cancel-stream.any.js
similarity index 75%
rename from third_party/blink/web_tests/external/wpt/fetch/api/response/response-cancel-stream.html
rename to third_party/blink/web_tests/external/wpt/fetch/api/response/response-cancel-stream.any.js
index fcaed04..baa46de 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-cancel-stream.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-cancel-stream.any.js
@@ -1,17 +1,7 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Response consume blob and http bodies</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#response">
-    <meta name="help" href="https://fetch.spec.whatwg.org/#body-mixin">
-    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-  </head>
-  <body>
-    <script src="../resources/utils.js"></script>
-    <script>
+// META: global=window,worker
+// META: title=Response consume blob and http bodies
+// META: script=../resources/utils.js
+
 promise_test(function(test) {
     return new Response(new Blob([], { "type" : "text/plain" })).body.cancel();
 }, "Cancelling a starting blob Response stream");
@@ -65,6 +55,3 @@
         return readAll(reader).then(() => reader.cancel());
     });
 }, "Cancelling a closed Response stream");
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-clone.any-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-clone.any-expected.txt
new file mode 100644
index 0000000..6ff0e71
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-clone.any-expected.txt
@@ -0,0 +1,21 @@
+This is a testharness.js-based test.
+PASS Check Response's clone with default values, without body
+PASS Check Response's clone has the expected attribute values
+PASS Check orginal response's body after cloning
+PASS Check cloned response's body
+PASS Cannot clone a disturbed response
+PASS Cloned responses should provide the same data
+PASS Cancelling stream should not affect cloned one
+FAIL Check response clone use structureClone for teed ReadableStreams (Int8Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (Int16Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (Int32Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0,0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (ArrayBufferchunk) assert_array_equals: Cloned buffer chunks have the same content value is object "[object ArrayBuffer]", expected array
+FAIL Check response clone use structureClone for teed ReadableStreams (Uint8Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (Uint8ClampedArraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (Uint16Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0,0,0,0,0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (Uint32Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0,0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (Float32Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0,0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (Float64Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (DataViewchunk) assert_array_equals: Cloned buffer chunks have the same content value is object "[object DataView]", expected array
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-clone.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-clone.any.js
new file mode 100644
index 0000000..7cc8f20
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-clone.any.js
@@ -0,0 +1,124 @@
+// META: global=window,worker
+// META: title=Response clone
+// META: script=../resources/utils.js
+
+var defaultValues = { "type" : "default",
+                      "url" : "",
+                      "ok" : true,
+                      "status" : 200,
+                      "statusText" : ""
+};
+
+var response = new Response();
+var clonedResponse = response.clone();
+test(function() {
+  for (var attributeName in defaultValues) {
+      var expectedValue = defaultValues[attributeName];
+      assert_equals(clonedResponse[attributeName], expectedValue,
+        "Expect default response." + attributeName + " is " + expectedValue);
+  }
+}, "Check Response's clone with default values, without body");
+
+var body = "This is response body";
+var headersInit = { "name" : "value" };
+var responseInit  = { "status" : 200,
+                      "statusText" : "GOOD",
+                      "headers" : headersInit
+};
+var response = new Response(body, responseInit);
+var clonedResponse = response.clone();
+test(function() {
+  assert_equals(clonedResponse.status, responseInit["status"],
+    "Expect response.status is " + responseInit["status"]);
+  assert_equals(clonedResponse.statusText, responseInit["statusText"],
+    "Expect response.statusText is " + responseInit["statusText"]);
+  assert_equals(clonedResponse.headers.get("name"), "value",
+    "Expect response.headers has name:value header");
+}, "Check Response's clone has the expected attribute values");
+
+promise_test(function(test) {
+  return validateStreamFromString(response.body.getReader(), body);
+}, "Check orginal response's body after cloning");
+
+promise_test(function(test) {
+  return validateStreamFromString(clonedResponse.body.getReader(), body);
+}, "Check cloned response's body");
+
+promise_test(function(test) {
+  var disturbedResponse = new Response("data");
+  return disturbedResponse.text().then(function() {
+      assert_true(disturbedResponse.bodyUsed, "response is disturbed");
+      assert_throws_js(TypeError, function() { disturbedResponse.clone(); },
+        "Expect TypeError exception");
+  });
+}, "Cannot clone a disturbed response");
+
+promise_test(function(t) {
+    var clone;
+    var result;
+    var response;
+    return fetch('../resources/trickle.py?count=2&delay=100').then(function(res) {
+        clone = res.clone();
+        response = res;
+        return clone.text();
+    }).then(function(r) {
+        assert_equals(r.length, 26);
+        result = r;
+        return response.text();
+    }).then(function(r) {
+        assert_equals(r, result, "cloned responses should provide the same data");
+    });
+  }, 'Cloned responses should provide the same data');
+
+promise_test(function(t) {
+    var clone;
+    return fetch('../resources/trickle.py?count=2&delay=100').then(function(res) {
+        clone = res.clone();
+        res.body.cancel();
+        assert_true(res.bodyUsed);
+        assert_false(clone.bodyUsed);
+        return clone.arrayBuffer();
+    }).then(function(r) {
+        assert_equals(r.byteLength, 26);
+        assert_true(clone.bodyUsed);
+    });
+}, 'Cancelling stream should not affect cloned one');
+
+function testReadableStreamClone(initialBuffer, bufferType)
+{
+    promise_test(function(test) {
+        var response = new Response(new ReadableStream({start : function(controller) {
+            controller.enqueue(initialBuffer);
+            controller.close();
+        }}));
+
+        var clone = response.clone();
+        var stream1 = response.body;
+        var stream2 = clone.body;
+
+        var buffer;
+        return stream1.getReader().read().then(function(data) {
+            assert_false(data.done);
+            assert_equals(data.value, initialBuffer, "Buffer of being-cloned response stream is the same as the original buffer");
+            return stream2.getReader().read();
+        }).then(function(data) {
+            assert_false(data.done);
+            assert_array_equals(data.value, initialBuffer, "Cloned buffer chunks have the same content");
+            assert_equals(Object.getPrototypeOf(data.value), Object.getPrototypeOf(initialBuffer), "Cloned buffers have the same type");
+            assert_not_equals(data.value, initialBuffer, "Buffer of cloned response stream is a clone of the original buffer");
+        });
+    }, "Check response clone use structureClone for teed ReadableStreams (" + bufferType  + "chunk)");
+}
+
+var arrayBuffer = new ArrayBuffer(16);
+testReadableStreamClone(new Int8Array(arrayBuffer, 1), "Int8Array");
+testReadableStreamClone(new Int16Array(arrayBuffer, 2, 2), "Int16Array");
+testReadableStreamClone(new Int32Array(arrayBuffer), "Int32Array");
+testReadableStreamClone(arrayBuffer, "ArrayBuffer");
+testReadableStreamClone(new Uint8Array(arrayBuffer), "Uint8Array");
+testReadableStreamClone(new Uint8ClampedArray(arrayBuffer), "Uint8ClampedArray");
+testReadableStreamClone(new Uint16Array(arrayBuffer, 2), "Uint16Array");
+testReadableStreamClone(new Uint32Array(arrayBuffer), "Uint32Array");
+testReadableStreamClone(new Float32Array(arrayBuffer), "Float32Array");
+testReadableStreamClone(new Float64Array(arrayBuffer), "Float64Array");
+testReadableStreamClone(new DataView(arrayBuffer, 2, 8), "DataView");
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-clone.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-clone.any.serviceworker-expected.txt
new file mode 100644
index 0000000..6ff0e71
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-clone.any.serviceworker-expected.txt
@@ -0,0 +1,21 @@
+This is a testharness.js-based test.
+PASS Check Response's clone with default values, without body
+PASS Check Response's clone has the expected attribute values
+PASS Check orginal response's body after cloning
+PASS Check cloned response's body
+PASS Cannot clone a disturbed response
+PASS Cloned responses should provide the same data
+PASS Cancelling stream should not affect cloned one
+FAIL Check response clone use structureClone for teed ReadableStreams (Int8Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (Int16Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (Int32Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0,0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (ArrayBufferchunk) assert_array_equals: Cloned buffer chunks have the same content value is object "[object ArrayBuffer]", expected array
+FAIL Check response clone use structureClone for teed ReadableStreams (Uint8Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (Uint8ClampedArraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (Uint16Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0,0,0,0,0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (Uint32Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0,0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (Float32Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0,0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (Float64Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (DataViewchunk) assert_array_equals: Cloned buffer chunks have the same content value is object "[object DataView]", expected array
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-clone.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-clone.any.sharedworker-expected.txt
new file mode 100644
index 0000000..6ff0e71
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-clone.any.sharedworker-expected.txt
@@ -0,0 +1,21 @@
+This is a testharness.js-based test.
+PASS Check Response's clone with default values, without body
+PASS Check Response's clone has the expected attribute values
+PASS Check orginal response's body after cloning
+PASS Check cloned response's body
+PASS Cannot clone a disturbed response
+PASS Cloned responses should provide the same data
+PASS Cancelling stream should not affect cloned one
+FAIL Check response clone use structureClone for teed ReadableStreams (Int8Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (Int16Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (Int32Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0,0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (ArrayBufferchunk) assert_array_equals: Cloned buffer chunks have the same content value is object "[object ArrayBuffer]", expected array
+FAIL Check response clone use structureClone for teed ReadableStreams (Uint8Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (Uint8ClampedArraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (Uint16Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0,0,0,0,0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (Uint32Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0,0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (Float32Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0,0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (Float64Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (DataViewchunk) assert_array_equals: Cloned buffer chunks have the same content value is object "[object DataView]", expected array
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-clone.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-clone.any.worker-expected.txt
new file mode 100644
index 0000000..6ff0e71
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-clone.any.worker-expected.txt
@@ -0,0 +1,21 @@
+This is a testharness.js-based test.
+PASS Check Response's clone with default values, without body
+PASS Check Response's clone has the expected attribute values
+PASS Check orginal response's body after cloning
+PASS Check cloned response's body
+PASS Cannot clone a disturbed response
+PASS Cloned responses should provide the same data
+PASS Cancelling stream should not affect cloned one
+FAIL Check response clone use structureClone for teed ReadableStreams (Int8Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (Int16Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (Int32Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0,0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (ArrayBufferchunk) assert_array_equals: Cloned buffer chunks have the same content value is object "[object ArrayBuffer]", expected array
+FAIL Check response clone use structureClone for teed ReadableStreams (Uint8Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (Uint8ClampedArraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (Uint16Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0,0,0,0,0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (Uint32Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0,0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (Float32Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0,0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (Float64Arraychunk) assert_not_equals: Buffer of cloned response stream is a clone of the original buffer got disallowed value object "0,0"
+FAIL Check response clone use structureClone for teed ReadableStreams (DataViewchunk) assert_array_equals: Cloned buffer chunks have the same content value is object "[object DataView]", expected array
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-clone.html b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-clone.html
deleted file mode 100644
index 5529d49..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-clone.html
+++ /dev/null
@@ -1,137 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Response clone</title>
-    <meta name="timeout" content="long">
-    <meta name="help" href="https://fetch.spec.whatwg.org/#response">
-    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-  </head>
-  <body>
-    <script src="../resources/utils.js"></script>
-    <script>
-      var defaultValues = { "type" : "default",
-                            "url" : "",
-                            "ok" : true,
-                            "status" : 200,
-                            "statusText" : ""
-      };
-
-      var response = new Response();
-      var clonedResponse = response.clone();
-      test(function() {
-        for (var attributeName in defaultValues) {
-            var expectedValue = defaultValues[attributeName];
-            assert_equals(clonedResponse[attributeName], expectedValue,
-              "Expect default response." + attributeName + " is " + expectedValue);
-        }
-      }, "Check Response's clone with default values, without body");
-
-      var body = "This is response body";
-      var headersInit = { "name" : "value" };
-      var responseInit  = { "status" : 200,
-                            "statusText" : "GOOD",
-                            "headers" : headersInit
-      };
-      var response = new Response(body, responseInit);
-      var clonedResponse = response.clone();
-      test(function() {
-        assert_equals(clonedResponse.status, responseInit["status"],
-          "Expect response.status is " + responseInit["status"]);
-        assert_equals(clonedResponse.statusText, responseInit["statusText"],
-          "Expect response.statusText is " + responseInit["statusText"]);
-        assert_equals(clonedResponse.headers.get("name"), "value",
-          "Expect response.headers has name:value header");
-      }, "Check Response's clone has the expected attribute values");
-
-      promise_test(function(test) {
-        return validateStreamFromString(response.body.getReader(), body);
-      }, "Check orginal response's body after cloning");
-
-      promise_test(function(test) {
-        return validateStreamFromString(clonedResponse.body.getReader(), body);
-      }, "Check cloned response's body");
-
-      promise_test(function(test) {
-        var disturbedResponse = new Response("data");
-        return disturbedResponse.text().then(function() {
-            assert_true(disturbedResponse.bodyUsed, "response is disturbed");
-            assert_throws_js(TypeError, function() { disturbedResponse.clone(); },
-              "Expect TypeError exception");
-        });
-      }, "Cannot clone a disturbed response");
-
-    promise_test(function(t) {
-        var clone;
-        var result;
-        var response;
-        return fetch('../resources/trickle.py?count=2&delay=100').then(function(res) {
-            clone = res.clone();
-            response = res;
-            return clone.text();
-        }).then(function(r) {
-            assert_equals(r.length, 26);
-            result = r;
-            return response.text();
-        }).then(function(r) {
-            assert_equals(r, result, "cloned responses should provide the same data");
-        });
-     }, 'Cloned responses should provide the same data');
-
-    promise_test(function(t) {
-        var clone;
-        return fetch('../resources/trickle.py?count=2&delay=100').then(function(res) {
-            clone = res.clone();
-            res.body.cancel();
-            assert_true(res.bodyUsed);
-            assert_false(clone.bodyUsed);
-            return clone.arrayBuffer();
-        }).then(function(r) {
-            assert_equals(r.byteLength, 26);
-            assert_true(clone.bodyUsed);
-        });
-    }, 'Cancelling stream should not affect cloned one');
-
-function testReadableStreamClone(initialBuffer, bufferType)
-{
-    promise_test(function(test) {
-        var response = new Response(new ReadableStream({start : function(controller) {
-            controller.enqueue(initialBuffer);
-            controller.close();
-        }}));
-
-        var clone = response.clone();
-        var stream1 = response.body;
-        var stream2 = clone.body;
-
-        var buffer;
-        return stream1.getReader().read().then(function(data) {
-            assert_false(data.done);
-            assert_equals(data.value, initialBuffer, "Buffer of being-cloned response stream is the same as the original buffer");
-            return stream2.getReader().read();
-        }).then(function(data) {
-            assert_false(data.done);
-            assert_array_equals(data.value, initialBuffer, "Cloned buffer chunks have the same content");
-            assert_equals(Object.getPrototypeOf(data.value), Object.getPrototypeOf(initialBuffer), "Cloned buffers have the same type");
-            assert_not_equals(data.value, initialBuffer, "Buffer of cloned response stream is a clone of the original buffer");
-        });
-    }, "Check response clone use structureClone for teed ReadableStreams (" + bufferType  + "chunk)");
-}
-
-var arrayBuffer = new ArrayBuffer(16);
-testReadableStreamClone(new Int8Array(arrayBuffer, 1), "Int8Array");
-testReadableStreamClone(new Int16Array(arrayBuffer, 2, 2), "Int16Array");
-testReadableStreamClone(new Int32Array(arrayBuffer), "Int32Array");
-testReadableStreamClone(arrayBuffer, "ArrayBuffer");
-testReadableStreamClone(new Uint8Array(arrayBuffer), "Uint8Array");
-testReadableStreamClone(new Uint8ClampedArray(arrayBuffer), "Uint8ClampedArray");
-testReadableStreamClone(new Uint16Array(arrayBuffer, 2), "Uint16Array");
-testReadableStreamClone(new Uint32Array(arrayBuffer), "Uint32Array");
-testReadableStreamClone(new Float32Array(arrayBuffer), "Float32Array");
-testReadableStreamClone(new Float64Array(arrayBuffer), "Float64Array");
-testReadableStreamClone(new DataView(arrayBuffer, 2, 8), "DataView");
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-consume-empty.any-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-consume-empty.any-expected.txt
new file mode 100644
index 0000000..5b0426f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-consume-empty.any-expected.txt
@@ -0,0 +1,17 @@
+This is a testharness.js-based test.
+PASS Consume response's body as text
+PASS Consume response's body as blob
+PASS Consume response's body as arrayBuffer
+PASS Consume response's body as json (error case)
+PASS Consume response's body as formData with correct multipart type (error case)
+PASS Consume response's body as formData with correct urlencoded type
+PASS Consume response's body as formData without correct type (error case)
+PASS Consume empty blob response body as arrayBuffer
+PASS Consume empty text response body as arrayBuffer
+PASS Consume empty blob response body as text
+PASS Consume empty text response body as text
+PASS Consume empty URLSearchParams response body as text
+FAIL Consume empty FormData response body as text assert_equals: Resolved value should be empty expected 0 but got 44
+PASS Consume empty ArrayBuffer response body as text
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-consume-empty.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-consume-empty.any.js
new file mode 100644
index 0000000..0fa85ecb
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-consume-empty.any.js
@@ -0,0 +1,99 @@
+// META: global=window,worker
+// META: title=Response consume empty bodies
+
+function checkBodyText(test, response) {
+  return response.text().then(function(bodyAsText) {
+    assert_equals(bodyAsText, "", "Resolved value should be empty");
+    assert_false(response.bodyUsed);
+  });
+}
+
+function checkBodyBlob(test, response) {
+  return response.blob().then(function(bodyAsBlob) {
+    var promise = new Promise(function(resolve, reject) {
+      var reader = new FileReader();
+      reader.onload = function(evt) {
+        resolve(reader.result)
+      };
+      reader.onerror = function() {
+        reject("Blob's reader failed");
+      };
+      reader.readAsText(bodyAsBlob);
+    });
+    return promise.then(function(body) {
+      assert_equals(body, "", "Resolved value should be empty");
+      assert_false(response.bodyUsed);
+    });
+  });
+}
+
+function checkBodyArrayBuffer(test, response) {
+  return response.arrayBuffer().then(function(bodyAsArrayBuffer) {
+    assert_equals(bodyAsArrayBuffer.byteLength, 0, "Resolved value should be empty");
+    assert_false(response.bodyUsed);
+  });
+}
+
+function checkBodyJSON(test, response) {
+  return response.json().then(
+    function(bodyAsJSON) {
+      assert_unreached("JSON parsing should fail");
+    },
+    function() {
+      assert_false(response.bodyUsed);
+    });
+}
+
+function checkBodyFormData(test, response) {
+  return response.formData().then(function(bodyAsFormData) {
+    assert_true(bodyAsFormData instanceof FormData, "Should receive a FormData");
+    assert_false(response.bodyUsed);
+  });
+}
+
+function checkBodyFormDataError(test, response) {
+  return promise_rejects_js(test, TypeError, response.formData()).then(function() {
+    assert_false(response.bodyUsed);
+  });
+}
+
+function checkResponseWithNoBody(bodyType, checkFunction, headers = []) {
+  promise_test(function(test) {
+    var response = new Response(undefined, { "headers": headers });
+    assert_false(response.bodyUsed);
+    return checkFunction(test, response);
+  }, "Consume response's body as " + bodyType);
+}
+
+checkResponseWithNoBody("text", checkBodyText);
+checkResponseWithNoBody("blob", checkBodyBlob);
+checkResponseWithNoBody("arrayBuffer", checkBodyArrayBuffer);
+checkResponseWithNoBody("json (error case)", checkBodyJSON);
+checkResponseWithNoBody("formData with correct multipart type (error case)", checkBodyFormDataError, [["Content-Type", 'multipart/form-data; boundary="boundary"']]);
+checkResponseWithNoBody("formData with correct urlencoded type", checkBodyFormData, [["Content-Type", "application/x-www-form-urlencoded;charset=UTF-8"]]);
+checkResponseWithNoBody("formData without correct type (error case)", checkBodyFormDataError);
+
+function checkResponseWithEmptyBody(bodyType, body, asText) {
+  promise_test(function(test) {
+    var response = new Response(body);
+    assert_false(response.bodyUsed, "bodyUsed is false at init");
+    if (asText) {
+      return response.text().then(function(bodyAsString) {
+        assert_equals(bodyAsString.length, 0, "Resolved value should be empty");
+        assert_true(response.bodyUsed, "bodyUsed is true after being consumed");
+      });
+    }
+    return response.arrayBuffer().then(function(bodyAsArrayBuffer) {
+      assert_equals(bodyAsArrayBuffer.byteLength, 0, "Resolved value should be empty");
+      assert_true(response.bodyUsed, "bodyUsed is true after being consumed");
+    });
+  }, "Consume empty " + bodyType + " response body as " + (asText ? "text" : "arrayBuffer"));
+}
+
+checkResponseWithEmptyBody("blob", new Blob([], { "type" : "text/plain" }), false);
+checkResponseWithEmptyBody("text", "", false);
+checkResponseWithEmptyBody("blob", new Blob([], { "type" : "text/plain" }), true);
+checkResponseWithEmptyBody("text", "", true);
+checkResponseWithEmptyBody("URLSearchParams", new URLSearchParams(""), true);
+checkResponseWithEmptyBody("FormData", new FormData(), true);
+checkResponseWithEmptyBody("ArrayBuffer", new ArrayBuffer(), true);
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-consume-empty.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-consume-empty.any.serviceworker-expected.txt
new file mode 100644
index 0000000..5b0426f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-consume-empty.any.serviceworker-expected.txt
@@ -0,0 +1,17 @@
+This is a testharness.js-based test.
+PASS Consume response's body as text
+PASS Consume response's body as blob
+PASS Consume response's body as arrayBuffer
+PASS Consume response's body as json (error case)
+PASS Consume response's body as formData with correct multipart type (error case)
+PASS Consume response's body as formData with correct urlencoded type
+PASS Consume response's body as formData without correct type (error case)
+PASS Consume empty blob response body as arrayBuffer
+PASS Consume empty text response body as arrayBuffer
+PASS Consume empty blob response body as text
+PASS Consume empty text response body as text
+PASS Consume empty URLSearchParams response body as text
+FAIL Consume empty FormData response body as text assert_equals: Resolved value should be empty expected 0 but got 44
+PASS Consume empty ArrayBuffer response body as text
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-consume-empty.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-consume-empty.any.sharedworker-expected.txt
new file mode 100644
index 0000000..5b0426f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-consume-empty.any.sharedworker-expected.txt
@@ -0,0 +1,17 @@
+This is a testharness.js-based test.
+PASS Consume response's body as text
+PASS Consume response's body as blob
+PASS Consume response's body as arrayBuffer
+PASS Consume response's body as json (error case)
+PASS Consume response's body as formData with correct multipart type (error case)
+PASS Consume response's body as formData with correct urlencoded type
+PASS Consume response's body as formData without correct type (error case)
+PASS Consume empty blob response body as arrayBuffer
+PASS Consume empty text response body as arrayBuffer
+PASS Consume empty blob response body as text
+PASS Consume empty text response body as text
+PASS Consume empty URLSearchParams response body as text
+FAIL Consume empty FormData response body as text assert_equals: Resolved value should be empty expected 0 but got 44
+PASS Consume empty ArrayBuffer response body as text
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-consume-empty.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-consume-empty.any.worker-expected.txt
new file mode 100644
index 0000000..5b0426f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-consume-empty.any.worker-expected.txt
@@ -0,0 +1,17 @@
+This is a testharness.js-based test.
+PASS Consume response's body as text
+PASS Consume response's body as blob
+PASS Consume response's body as arrayBuffer
+PASS Consume response's body as json (error case)
+PASS Consume response's body as formData with correct multipart type (error case)
+PASS Consume response's body as formData with correct urlencoded type
+PASS Consume response's body as formData without correct type (error case)
+PASS Consume empty blob response body as arrayBuffer
+PASS Consume empty text response body as arrayBuffer
+PASS Consume empty blob response body as text
+PASS Consume empty text response body as text
+PASS Consume empty URLSearchParams response body as text
+FAIL Consume empty FormData response body as text assert_equals: Resolved value should be empty expected 0 but got 44
+PASS Consume empty ArrayBuffer response body as text
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-consume-empty.html b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-consume-empty.html
deleted file mode 100644
index f587e63..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-consume-empty.html
+++ /dev/null
@@ -1,112 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Response consume empty bodies</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#response">
-    <meta name="help" href="https://fetch.spec.whatwg.org/#body-mixin">
-    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-  </head>
-  <body>
-    <script>
-    function checkBodyText(test, response) {
-      return response.text().then(function(bodyAsText) {
-        assert_equals(bodyAsText, "", "Resolved value should be empty");
-        assert_false(response.bodyUsed);
-      });
-    }
-
-    function checkBodyBlob(test, response) {
-      return response.blob().then(function(bodyAsBlob) {
-        var promise = new Promise(function(resolve, reject) {
-          var reader = new FileReader();
-          reader.onload = function(evt) {
-            resolve(reader.result)
-          };
-          reader.onerror = function() {
-            reject("Blob's reader failed");
-          };
-          reader.readAsText(bodyAsBlob);
-        });
-        return promise.then(function(body) {
-          assert_equals(body, "", "Resolved value should be empty");
-          assert_false(response.bodyUsed);
-        });
-      });
-    }
-
-    function checkBodyArrayBuffer(test, response) {
-      return response.arrayBuffer().then(function(bodyAsArrayBuffer) {
-        assert_equals(bodyAsArrayBuffer.byteLength, 0, "Resolved value should be empty");
-        assert_false(response.bodyUsed);
-      });
-    }
-
-    function checkBodyJSON(test, response) {
-      return response.json().then(
-        function(bodyAsJSON) {
-          assert_unreached("JSON parsing should fail");
-        },
-        function() {
-          assert_false(response.bodyUsed);
-        });
-    }
-
-    function checkBodyFormData(test, response) {
-      return response.formData().then(function(bodyAsFormData) {
-        assert_true(bodyAsFormData instanceof FormData, "Should receive a FormData");
-        assert_false(response.bodyUsed);
-     });
-    }
-
-    function checkBodyFormDataError(test, response) {
-      return promise_rejects_js(test, TypeError, response.formData()).then(function() {
-        assert_false(response.bodyUsed);
-      });
-    }
-
-    function checkResponseWithNoBody(bodyType, checkFunction, headers = []) {
-      promise_test(function(test) {
-        var response = new Response(undefined, { "headers": headers });
-        assert_false(response.bodyUsed);
-        return checkFunction(test, response);
-      }, "Consume response's body as " + bodyType);
-    }
-
-    checkResponseWithNoBody("text", checkBodyText);
-    checkResponseWithNoBody("blob", checkBodyBlob);
-    checkResponseWithNoBody("arrayBuffer", checkBodyArrayBuffer);
-    checkResponseWithNoBody("json (error case)", checkBodyJSON);
-    checkResponseWithNoBody("formData with correct multipart type (error case)", checkBodyFormDataError, [["Content-Type", 'multipart/form-data; boundary="boundary"']]);
-    checkResponseWithNoBody("formData with correct urlencoded type", checkBodyFormData, [["Content-Type", "application/x-www-form-urlencoded;charset=UTF-8"]]);
-    checkResponseWithNoBody("formData without correct type (error case)", checkBodyFormDataError);
-
-    function checkResponseWithEmptyBody(bodyType, body, asText) {
-      promise_test(function(test) {
-        var response = new Response(body);
-        assert_false(response.bodyUsed, "bodyUsed is false at init");
-        if (asText) {
-          return response.text().then(function(bodyAsString) {
-            assert_equals(bodyAsString.length, 0, "Resolved value should be empty");
-            assert_true(response.bodyUsed, "bodyUsed is true after being consumed");
-          });
-        }
-        return response.arrayBuffer().then(function(bodyAsArrayBuffer) {
-          assert_equals(bodyAsArrayBuffer.byteLength, 0, "Resolved value should be empty");
-          assert_true(response.bodyUsed, "bodyUsed is true after being consumed");
-        });
-      }, "Consume empty " + bodyType + " response body as " + (asText ? "text" : "arrayBuffer"));
-    }
-
-    checkResponseWithEmptyBody("blob", new Blob([], { "type" : "text/plain" }), false);
-    checkResponseWithEmptyBody("text", "", false);
-    checkResponseWithEmptyBody("blob", new Blob([], { "type" : "text/plain" }), true);
-    checkResponseWithEmptyBody("text", "", true);
-    checkResponseWithEmptyBody("URLSearchParams", new URLSearchParams(""), true);
-    checkResponseWithEmptyBody("FormData", new FormData(), true);
-    checkResponseWithEmptyBody("ArrayBuffer", new ArrayBuffer(), true);
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-consume-stream.html b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-consume-stream.any.js
similarity index 79%
rename from third_party/blink/web_tests/external/wpt/fetch/api/response/response-consume-stream.html
rename to third_party/blink/web_tests/external/wpt/fetch/api/response/response-consume-stream.any.js
index 8a97fa0..d5b0c38 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-consume-stream.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-consume-stream.any.js
@@ -1,17 +1,6 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Response consume</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#response">
-    <meta name="help" href="https://fetch.spec.whatwg.org/#body-mixin">
-    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <script src="../resources/utils.js"></script>
-  </head>
-  <body>
-    <script>
+// META: global=window,worker
+// META: title=Response consume
+// META: script=../resources/utils.js
 
 promise_test(function(test) {
     var body = "";
@@ -68,7 +57,3 @@
 test(function() {
     assert_equals(Response.redirect("/").body, null);
 }, "Getting a redirect Response stream");
-
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-error-from-stream.any-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-error-from-stream.any-expected.txt
new file mode 100644
index 0000000..fd1e6908
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-error-from-stream.any-expected.txt
@@ -0,0 +1,15 @@
+This is a testharness.js-based test.
+PASS ReadableStreamDefaultReader Promise receives ReadableStream start() Error
+PASS ReadableStreamDefaultReader Promise receives ReadableStream pull() Error
+FAIL ReadableStream start() Error propagates to Response.arrayBuffer() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Start error"
+FAIL ReadableStream start() Error propagates to Response.blob() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Start error"
+FAIL ReadableStream start() Error propagates to Response.formData() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Start error"
+FAIL ReadableStream start() Error propagates to Response.json() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Start error"
+FAIL ReadableStream start() Error propagates to Response.text() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Start error"
+FAIL ReadableStream pull() Error propagates to Response.arrayBuffer() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Pull error"
+FAIL ReadableStream pull() Error propagates to Response.blob() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Pull error"
+FAIL ReadableStream pull() Error propagates to Response.formData() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Pull error"
+FAIL ReadableStream pull() Error propagates to Response.json() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Pull error"
+FAIL ReadableStream pull() Error propagates to Response.text() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Pull error"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-error-from-stream.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-error-from-stream.any.js
new file mode 100644
index 0000000..118eb7d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-error-from-stream.any.js
@@ -0,0 +1,59 @@
+// META: global=window,worker
+// META: title=Response Receives Propagated Error from ReadableStream
+
+function newStreamWithStartError() {
+  var err = new Error("Start error");
+  return [new ReadableStream({
+            start(controller) {
+                controller.error(err);
+            }
+          }),
+          err]
+}
+
+function newStreamWithPullError() {
+  var err = new Error("Pull error");
+  return [new ReadableStream({
+            pull(controller) {
+                controller.error(err);
+            }
+          }),
+          err]
+}
+
+function runRequestPromiseTest([stream, err], responseReaderMethod, testDescription) {
+  promise_test(test => {
+    return promise_rejects_exactly(
+      test,
+      err,
+      new Response(stream)[responseReaderMethod](),
+      'CustomTestError should propagate'
+    )
+  }, testDescription)
+}
+
+
+promise_test(test => {
+  var [stream, err] = newStreamWithStartError();
+  return promise_rejects_exactly(test, err, stream.getReader().read(), 'CustomTestError should propagate')
+}, "ReadableStreamDefaultReader Promise receives ReadableStream start() Error")
+
+promise_test(test => {
+  var [stream, err] = newStreamWithPullError();
+  return promise_rejects_exactly(test, err, stream.getReader().read(), 'CustomTestError should propagate')
+}, "ReadableStreamDefaultReader Promise receives ReadableStream pull() Error")
+
+
+// test start() errors for all Body reader methods
+runRequestPromiseTest(newStreamWithStartError(), 'arrayBuffer', 'ReadableStream start() Error propagates to Response.arrayBuffer() Promise');
+runRequestPromiseTest(newStreamWithStartError(), 'blob',        'ReadableStream start() Error propagates to Response.blob() Promise');
+runRequestPromiseTest(newStreamWithStartError(), 'formData',    'ReadableStream start() Error propagates to Response.formData() Promise');
+runRequestPromiseTest(newStreamWithStartError(), 'json',        'ReadableStream start() Error propagates to Response.json() Promise');
+runRequestPromiseTest(newStreamWithStartError(), 'text',        'ReadableStream start() Error propagates to Response.text() Promise');
+
+// test pull() errors for all Body reader methods
+runRequestPromiseTest(newStreamWithPullError(), 'arrayBuffer', 'ReadableStream pull() Error propagates to Response.arrayBuffer() Promise');
+runRequestPromiseTest(newStreamWithPullError(), 'blob',        'ReadableStream pull() Error propagates to Response.blob() Promise');
+runRequestPromiseTest(newStreamWithPullError(), 'formData',    'ReadableStream pull() Error propagates to Response.formData() Promise');
+runRequestPromiseTest(newStreamWithPullError(), 'json',        'ReadableStream pull() Error propagates to Response.json() Promise');
+runRequestPromiseTest(newStreamWithPullError(), 'text',        'ReadableStream pull() Error propagates to Response.text() Promise');
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-error-from-stream.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-error-from-stream.any.serviceworker-expected.txt
new file mode 100644
index 0000000..fd1e6908
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-error-from-stream.any.serviceworker-expected.txt
@@ -0,0 +1,15 @@
+This is a testharness.js-based test.
+PASS ReadableStreamDefaultReader Promise receives ReadableStream start() Error
+PASS ReadableStreamDefaultReader Promise receives ReadableStream pull() Error
+FAIL ReadableStream start() Error propagates to Response.arrayBuffer() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Start error"
+FAIL ReadableStream start() Error propagates to Response.blob() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Start error"
+FAIL ReadableStream start() Error propagates to Response.formData() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Start error"
+FAIL ReadableStream start() Error propagates to Response.json() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Start error"
+FAIL ReadableStream start() Error propagates to Response.text() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Start error"
+FAIL ReadableStream pull() Error propagates to Response.arrayBuffer() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Pull error"
+FAIL ReadableStream pull() Error propagates to Response.blob() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Pull error"
+FAIL ReadableStream pull() Error propagates to Response.formData() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Pull error"
+FAIL ReadableStream pull() Error propagates to Response.json() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Pull error"
+FAIL ReadableStream pull() Error propagates to Response.text() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Pull error"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-error-from-stream.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-error-from-stream.any.sharedworker-expected.txt
new file mode 100644
index 0000000..fd1e6908
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-error-from-stream.any.sharedworker-expected.txt
@@ -0,0 +1,15 @@
+This is a testharness.js-based test.
+PASS ReadableStreamDefaultReader Promise receives ReadableStream start() Error
+PASS ReadableStreamDefaultReader Promise receives ReadableStream pull() Error
+FAIL ReadableStream start() Error propagates to Response.arrayBuffer() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Start error"
+FAIL ReadableStream start() Error propagates to Response.blob() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Start error"
+FAIL ReadableStream start() Error propagates to Response.formData() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Start error"
+FAIL ReadableStream start() Error propagates to Response.json() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Start error"
+FAIL ReadableStream start() Error propagates to Response.text() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Start error"
+FAIL ReadableStream pull() Error propagates to Response.arrayBuffer() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Pull error"
+FAIL ReadableStream pull() Error propagates to Response.blob() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Pull error"
+FAIL ReadableStream pull() Error propagates to Response.formData() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Pull error"
+FAIL ReadableStream pull() Error propagates to Response.json() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Pull error"
+FAIL ReadableStream pull() Error propagates to Response.text() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Pull error"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-error-from-stream.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-error-from-stream.any.worker-expected.txt
new file mode 100644
index 0000000..fd1e6908
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-error-from-stream.any.worker-expected.txt
@@ -0,0 +1,15 @@
+This is a testharness.js-based test.
+PASS ReadableStreamDefaultReader Promise receives ReadableStream start() Error
+PASS ReadableStreamDefaultReader Promise receives ReadableStream pull() Error
+FAIL ReadableStream start() Error propagates to Response.arrayBuffer() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Start error"
+FAIL ReadableStream start() Error propagates to Response.blob() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Start error"
+FAIL ReadableStream start() Error propagates to Response.formData() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Start error"
+FAIL ReadableStream start() Error propagates to Response.json() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Start error"
+FAIL ReadableStream start() Error propagates to Response.text() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Start error"
+FAIL ReadableStream pull() Error propagates to Response.arrayBuffer() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Pull error"
+FAIL ReadableStream pull() Error propagates to Response.blob() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Pull error"
+FAIL ReadableStream pull() Error propagates to Response.formData() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Pull error"
+FAIL ReadableStream pull() Error propagates to Response.json() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Pull error"
+FAIL ReadableStream pull() Error propagates to Response.text() Promise promise_rejects_exactly: CustomTestError should propagate function "function() { throw e }" threw object "TypeError: Failed to fetch" but we expected it to throw object "Error: Pull error"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-error-from-stream.html b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-error-from-stream.html
deleted file mode 100644
index 370f6ba..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-error-from-stream.html
+++ /dev/null
@@ -1,69 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Response Receives Propagated Error from ReadableStream</title>
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-  </head>
-  <body>
-    <script>
-      function newStreamWithStartError() {
-        var err = new Error("Start error");
-        return [new ReadableStream({
-                  start(controller) {
-                      controller.error(err);
-                  }
-                }),
-                err]
-      }
-
-      function newStreamWithPullError() {
-        var err = new Error("Pull error");
-        return [new ReadableStream({
-                  pull(controller) {
-                      controller.error(err);
-                  }
-                }),
-                err]
-      }
-
-      function runRequestPromiseTest([stream, err], responseReaderMethod, testDescription) {
-        promise_test(test => {
-          return promise_rejects_exactly(
-            test,
-            err,
-            new Response(stream)[responseReaderMethod](),
-            'CustomTestError should propagate'
-          )
-        }, testDescription)
-      }
-
-
-      promise_test(test => {
-        var [stream, err] = newStreamWithStartError();
-        return promise_rejects_exactly(test, err, stream.getReader().read(), 'CustomTestError should propagate')
-      }, "ReadableStreamDefaultReader Promise receives ReadableStream start() Error")
-
-      promise_test(test => {
-        var [stream, err] = newStreamWithPullError();
-        return promise_rejects_exactly(test, err, stream.getReader().read(), 'CustomTestError should propagate')
-      }, "ReadableStreamDefaultReader Promise receives ReadableStream pull() Error")
-
-
-      // test start() errors for all Body reader methods
-      runRequestPromiseTest(newStreamWithStartError(), 'arrayBuffer', 'ReadableStream start() Error propagates to Response.arrayBuffer() Promise');
-      runRequestPromiseTest(newStreamWithStartError(), 'blob',        'ReadableStream start() Error propagates to Response.blob() Promise');
-      runRequestPromiseTest(newStreamWithStartError(), 'formData',    'ReadableStream start() Error propagates to Response.formData() Promise');
-      runRequestPromiseTest(newStreamWithStartError(), 'json',        'ReadableStream start() Error propagates to Response.json() Promise');
-      runRequestPromiseTest(newStreamWithStartError(), 'text',        'ReadableStream start() Error propagates to Response.text() Promise');
-
-      // test pull() errors for all Body reader methods
-      runRequestPromiseTest(newStreamWithPullError(), 'arrayBuffer', 'ReadableStream pull() Error propagates to Response.arrayBuffer() Promise');
-      runRequestPromiseTest(newStreamWithPullError(), 'blob',        'ReadableStream pull() Error propagates to Response.blob() Promise');
-      runRequestPromiseTest(newStreamWithPullError(), 'formData',    'ReadableStream pull() Error propagates to Response.formData() Promise');
-      runRequestPromiseTest(newStreamWithPullError(), 'json',        'ReadableStream pull() Error propagates to Response.json() Promise');
-      runRequestPromiseTest(newStreamWithPullError(), 'text',        'ReadableStream pull() Error propagates to Response.text() Promise');
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-error.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-error.any.js
new file mode 100644
index 0000000..a76bc43
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-error.any.js
@@ -0,0 +1,27 @@
+// META: global=window,worker
+// META: title=Response error
+
+var invalidStatus = [0, 100, 199, 600, 1000];
+invalidStatus.forEach(function(status) {
+  test(function() {
+    assert_throws_js(RangeError, function() { new Response("", { "status" : status }); },
+      "Expect RangeError exception when status is " + status);
+  },"Throws RangeError when responseInit's status is " + status);
+});
+
+var invalidStatusText = ["\n", "Ä€"];
+invalidStatusText.forEach(function(statusText) {
+  test(function() {
+    assert_throws_js(TypeError, function() { new Response("", { "statusText" : statusText }); },
+      "Expect TypeError exception " + statusText);
+  },"Throws TypeError when responseInit's statusText is " + statusText);
+});
+
+var nullBodyStatus = [204, 205, 304];
+nullBodyStatus.forEach(function(status) {
+  test(function() {
+    assert_throws_js(TypeError,
+      function() { new Response("body", {"status" : status }); },
+      "Expect TypeError exception ");
+  },"Throws TypeError when building a response with body and a body status of " + status);
+});
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-error.html b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-error.html
deleted file mode 100644
index 7cbb138..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-error.html
+++ /dev/null
@@ -1,39 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Response error</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#response">
-    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-  </head>
-  <body>
-    <script>
-      var invalidStatus = [0, 100, 199, 600, 1000];
-      invalidStatus.forEach(function(status) {
-        test(function() {
-          assert_throws_js(RangeError, function() { new Response("", { "status" : status }); },
-            "Expect RangeError exception when status is " + status);
-        },"Throws RangeError when responseInit's status is " + status);
-      });
-
-      var invalidStatusText = ["\n", "Ä€"];
-      invalidStatusText.forEach(function(statusText) {
-        test(function() {
-          assert_throws_js(TypeError, function() { new Response("", { "statusText" : statusText }); },
-            "Expect TypeError exception " + statusText);
-        },"Throws TypeError when responseInit's statusText is " + statusText);
-      });
-
-      var nullBodyStatus = [204, 205, 304];
-      nullBodyStatus.forEach(function(status) {
-        test(function() {
-          assert_throws_js(TypeError,
-            function() { new Response("body", {"status" : status }); },
-            "Expect TypeError exception ");
-        },"Throws TypeError when building a response with body and a body status of " + status);
-      });
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-init-001.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-init-001.any.js
new file mode 100644
index 0000000..559e49a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-init-001.any.js
@@ -0,0 +1,64 @@
+// META: global=window,worker
+// META: title=Response init: simple cases
+
+var defaultValues = { "type" : "default",
+                      "url" : "",
+                      "ok" : true,
+                      "status" : 200,
+                      "statusText" : "",
+                      "body" : null
+};
+
+var statusCodes = { "givenValues" : [200, 300, 400, 500, 599],
+                    "expectedValues" : [200, 300, 400, 500, 599]
+};
+var statusTexts = { "givenValues" : ["", "OK", "with space", String.fromCharCode(0x80)],
+                    "expectedValues" : ["", "OK", "with space", String.fromCharCode(0x80)]
+};
+var initValuesDict = { "status" : statusCodes,
+                        "statusText" : statusTexts
+};
+
+function isOkStatus(status) {
+  return 200 <= status &&  299 >= status;
+}
+
+var response = new Response();
+for (var attributeName in defaultValues) {
+  test(function() {
+    var expectedValue = defaultValues[attributeName];
+    assert_equals(response[attributeName], expectedValue,
+      "Expect default response." + attributeName + " is " + expectedValue);
+  }, "Check default value for " + attributeName + " attribute");
+}
+
+for (var attributeName in initValuesDict) {
+  test(function() {
+    var valuesToTest = initValuesDict[attributeName];
+    for (var valueIdx in valuesToTest["givenValues"]) {
+      var givenValue = valuesToTest["givenValues"][valueIdx];
+      var expectedValue = valuesToTest["expectedValues"][valueIdx];
+      var responseInit = {};
+      responseInit[attributeName] = givenValue;
+      var response = new Response("", responseInit);
+      assert_equals(response[attributeName], expectedValue,
+        "Expect response." + attributeName + " is " + expectedValue +
+        " when initialized with " + givenValue);
+      assert_equals(response.ok, isOkStatus(response.status),
+        "Expect response.ok is " + isOkStatus(response.status));
+    }
+  }, "Check " + attributeName + " init values and associated getter");
+}
+
+test(function() {
+  const response1 = new Response("");
+  assert_equals(response1.headers, response1.headers);
+
+  const response2 = new Response("", {"headers": {"X-Foo": "bar"}});
+  assert_equals(response2.headers, response2.headers);
+  const headers = response2.headers;
+  response2.headers.set("X-Foo", "quux");
+  assert_equals(headers, response2.headers);
+  headers.set("X-Other-Header", "baz");
+  assert_equals(headers, response2.headers);
+}, "Test that Response.headers has the [SameObject] extended attribute");
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-init-001.html b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-init-001.html
deleted file mode 100644
index 7af23d3..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-init-001.html
+++ /dev/null
@@ -1,77 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Response init: simple cases</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#response">
-    <meta name="help" href="https://fetch.spec.whatwg.org/#concept-response">
-    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-  </head>
-  <body>
-    <script>
-      var defaultValues = { "type" : "default",
-                            "url" : "",
-                            "ok" : true,
-                            "status" : 200,
-                            "statusText" : "",
-                            "body" : null
-      };
-
-      var statusCodes = { "givenValues" : [200, 300, 400, 500, 599],
-                          "expectedValues" : [200, 300, 400, 500, 599]
-      };
-      var statusTexts = { "givenValues" : ["", "OK", "with space", String.fromCharCode(0x80)],
-                          "expectedValues" : ["", "OK", "with space", String.fromCharCode(0x80)]
-      };
-      var initValuesDict = { "status" : statusCodes,
-                             "statusText" : statusTexts
-      };
-
-      function isOkStatus(status) {
-        return 200 <= status &&  299 >= status;
-      }
-
-      var response = new Response();
-      for (var attributeName in defaultValues) {
-        test(function() {
-          var expectedValue = defaultValues[attributeName];
-          assert_equals(response[attributeName], expectedValue,
-            "Expect default response." + attributeName + " is " + expectedValue);
-        }, "Check default value for " + attributeName + " attribute");
-      }
-
-      for (var attributeName in initValuesDict) {
-        test(function() {
-          var valuesToTest = initValuesDict[attributeName];
-          for (var valueIdx in valuesToTest["givenValues"]) {
-            var givenValue = valuesToTest["givenValues"][valueIdx];
-            var expectedValue = valuesToTest["expectedValues"][valueIdx];
-            var responseInit = {};
-            responseInit[attributeName] = givenValue;
-            var response = new Response("", responseInit);
-            assert_equals(response[attributeName], expectedValue,
-              "Expect response." + attributeName + " is " + expectedValue +
-              " when initialized with " + givenValue);
-            assert_equals(response.ok, isOkStatus(response.status),
-              "Expect response.ok is " + isOkStatus(response.status));
-          }
-        }, "Check " + attributeName + " init values and associated getter");
-      }
-
-      test(function() {
-        const response1 = new Response("");
-        assert_equals(response1.headers, response1.headers);
-
-        const response2 = new Response("", {"headers": {"X-Foo": "bar"}});
-        assert_equals(response2.headers, response2.headers);
-        const headers = response2.headers;
-        response2.headers.set("X-Foo", "quux");
-        assert_equals(headers, response2.headers);
-        headers.set("X-Other-Header", "baz");
-        assert_equals(headers, response2.headers);
-      }, "Test that Response.headers has the [SameObject] extended attribute");
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-init-002.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-init-002.any.js
new file mode 100644
index 0000000..6c0a46e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-init-002.any.js
@@ -0,0 +1,61 @@
+// META: global=window,worker
+// META: title=Response init: body and headers
+// META: script=../resources/utils.js
+
+test(function() {
+  var headerDict = {"name1": "value1",
+                    "name2": "value2",
+                    "name3": "value3"
+  };
+  var headers = new Headers(headerDict);
+  var response = new Response("", { "headers" : headers })
+  for (var name in headerDict) {
+    assert_equals(response.headers.get(name), headerDict[name],
+      "response's headers has " + name + " : " + headerDict[name]);
+  }
+}, "Initialize Response with headers values");
+
+function checkResponseInit(body, bodyType, expectedTextBody) {
+  promise_test(function(test) {
+    var response = new Response(body);
+    var resHeaders = response.headers;
+    var mime = resHeaders.get("Content-Type");
+    assert_true(mime && mime.search(bodyType) > -1, "Content-Type header should be \"" + bodyType + "\" ");
+    return response.text().then(function(bodyAsText) {
+      //not equals: cannot guess formData exact value
+      assert_true(bodyAsText.search(expectedTextBody) > -1, "Retrieve and verify response body");
+    });
+  }, "Initialize Response's body with " + bodyType);
+}
+
+var blob = new Blob(["This is a blob"], {type: "application/octet-binary"});
+var formaData = new FormData();
+formaData.append("name", "value");
+var urlSearchParams = "URLSearchParams are not supported";
+//avoid test timeout if not implemented
+if (self.URLSearchParams)
+  urlSearchParams = new URLSearchParams("name=value");
+var usvString = "This is a USVString"
+
+checkResponseInit(blob, "application/octet-binary", "This is a blob");
+checkResponseInit(formaData, "multipart/form-data", "name=\"name\"\r\n\r\nvalue");
+checkResponseInit(urlSearchParams, "application/x-www-form-urlencoded;charset=UTF-8", "name=value");
+checkResponseInit(usvString, "text/plain;charset=UTF-8", "This is a USVString");
+
+promise_test(function(test) {
+  var body = "This is response body";
+  var response = new Response(body);
+  return validateStreamFromString(response.body.getReader(), body);
+}, "Read Response's body as readableStream");
+
+promise_test(function(test) {
+  var response = new Response("This is my fork", {"headers" : [["Content-Type", ""]]});
+  return response.blob().then(function(blob) {
+    assert_equals(blob.type, "", "Blob type should be the empty string");
+  });
+}, "Testing empty Response Content-Type header");
+
+test(function() {
+  var response = new Response(null, {status: 204});
+  assert_equals(response.body, null);
+}, "Testing null Response body");
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-init-002.html b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-init-002.html
deleted file mode 100644
index a48af83..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-init-002.html
+++ /dev/null
@@ -1,75 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Response init: body and headers</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#response">
-    <meta name="help" href="https://fetch.spec.whatwg.org/#concept-response">
-    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-  </head>
-  <body>
-    <script src="../resources/utils.js"></script>
-    <script>
-      test(function() {
-        var headerDict = {"name1": "value1",
-                          "name2": "value2",
-                          "name3": "value3"
-        };
-        var headers = new Headers(headerDict);
-        var response = new Response("", { "headers" : headers })
-        for (var name in headerDict) {
-          assert_equals(response.headers.get(name), headerDict[name],
-           "response's headers has " + name + " : " + headerDict[name]);
-        }
-      }, "Initialize Response with headers values");
-
-      function checkResponseInit(body, bodyType, expectedTextBody) {
-        promise_test(function(test) {
-          var response = new Response(body);
-          var resHeaders = response.headers;
-          var mime = resHeaders.get("Content-Type");
-          assert_true(mime && mime.search(bodyType) > -1, "Content-Type header should be \"" + bodyType + "\" ");
-          return response.text().then(function(bodyAsText) {
-            //not equals: cannot guess formData exact value
-            assert_true(bodyAsText.search(expectedTextBody) > -1, "Retrieve and verify response body");
-          });
-        }, "Initialize Response's body with " + bodyType);
-      }
-
-      var blob = new Blob(["This is a blob"], {type: "application/octet-binary"});
-      var formaData = new FormData();
-      formaData.append("name", "value");
-      var urlSearchParams = "URLSearchParams are not supported";
-      //avoid test timeout if not implemented
-      if (window.URLSearchParams)
-        urlSearchParams = new URLSearchParams("name=value");
-      var usvString = "This is a USVString"
-
-      checkResponseInit(blob, "application/octet-binary", "This is a blob");
-      checkResponseInit(formaData, "multipart/form-data", "name=\"name\"\r\n\r\nvalue");
-      checkResponseInit(urlSearchParams, "application/x-www-form-urlencoded;charset=UTF-8", "name=value");
-      checkResponseInit(usvString, "text/plain;charset=UTF-8", "This is a USVString");
-
-      promise_test(function(test) {
-        var body = "This is response body";
-        var response = new Response(body);
-        return validateStreamFromString(response.body.getReader(), body);
-      }, "Read Response's body as readableStream");
-
-      promise_test(function(test) {
-        var response = new Response("This is my fork", {"headers" : [["Content-Type", ""]]});
-        return response.blob().then(function(blob) {
-          assert_equals(blob.type, "", "Blob type should be the empty string");
-        });
-      }, "Testing empty Response Content-Type header");
-
-      test(function() {
-        var response = new Response(null, {status: 204});
-        assert_equals(response.body, null);
-      }, "Testing null Response body");
-
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-static-error.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-static-error.any.js
new file mode 100644
index 0000000..4097eab
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-static-error.any.js
@@ -0,0 +1,22 @@
+// META: global=window,worker
+// META: title=Response: error static method
+
+test(function() {
+  var responseError = Response.error();
+  assert_equals(responseError.type, "error", "Network error response's type is error");
+  assert_equals(responseError.status, 0, "Network error response's status is 0");
+  assert_equals(responseError.statusText, "", "Network error response's statusText is empty");
+  assert_equals(responseError.body, null, "Network error response's body is null");
+
+  assert_true(responseError.headers.entries().next().done, "Headers should be empty");
+}, "Check response returned by static method error()");
+
+test(function() {
+  const headers = Response.error().headers;
+
+  // Avoid false positives if expected API is not available
+  assert_true(!!headers);
+  assert_equals(typeof headers.append, 'function');
+
+  assert_throws_js(TypeError, function () { headers.append('name', 'value'); });
+}, "the 'guard' of the Headers instance should be immutable");
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-static-error.html b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-static-error.html
deleted file mode 100644
index b2d6e82..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-static-error.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Response: error static method</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#response">
-    <meta name="help" href="https://fetch.spec.whatwg.org/#concept-network-error">
-    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-  </head>
-  <body>
-    <script>
-      test(function() {
-        var responseError = Response.error();
-        assert_equals(responseError.type, "error", "Network error response's type is error");
-        assert_equals(responseError.status, 0, "Network error response's status is 0");
-        assert_equals(responseError.statusText, "", "Network error response's statusText is empty");
-        assert_equals(responseError.body, null, "Network error response's body is null");
-
-        assert_true(responseError.headers.entries().next().done, "Headers should be empty");
-      }, "Check response returned by static method error()");
-
-      test(function() {
-        const headers = Response.error().headers;
-
-        // Avoid false positives if expected API is not available
-        assert_true(!!headers);
-        assert_equals(typeof headers.append, 'function');
-
-        assert_throws_js(TypeError, function () { headers.append('name', 'value'); });
-      }, "the 'guard' of the Headers instance should be immutable");
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-static-redirect.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-static-redirect.any.js
new file mode 100644
index 0000000..971baec
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-static-redirect.any.js
@@ -0,0 +1,40 @@
+// META: global=window,worker
+// META: title=Response: redirect static method
+
+var url = "http://test.url:1234/";
+test(function() {
+  redirectResponse = Response.redirect(url);
+  assert_equals(redirectResponse.type, "default");
+  assert_false(redirectResponse.redirected);
+  assert_false(redirectResponse.ok);
+  assert_equals(redirectResponse.status, 302, "Default redirect status is 302");
+  assert_equals(redirectResponse.headers.get("Location"), url,
+    "redirected response has Location header with the correct url");
+  assert_equals(redirectResponse.statusText, "");
+}, "Check default redirect response");
+
+[301, 302, 303, 307, 308].forEach(function(status) {
+  test(function() {
+    redirectResponse = Response.redirect(url, status);
+    assert_equals(redirectResponse.type, "default");
+    assert_false(redirectResponse.redirected);
+    assert_false(redirectResponse.ok);
+    assert_equals(redirectResponse.status, status, "Redirect status is " + status);
+    assert_equals(redirectResponse.headers.get("Location"), url);
+    assert_equals(redirectResponse.statusText, "");
+  }, "Check response returned by static method redirect(), status = " + status);
+});
+
+test(function() {
+  var invalidUrl = "http://:This is not an url";
+  assert_throws_js(TypeError, function() { Response.redirect(invalidUrl); },
+    "Expect TypeError exception");
+}, "Check error returned when giving invalid url to redirect()");
+
+var invalidRedirectStatus = [200, 309, 400, 500];
+invalidRedirectStatus.forEach(function(invalidStatus) {
+  test(function() {
+    assert_throws_js(RangeError, function() { Response.redirect(url, invalidStatus); },
+        "Expect RangeError exception");
+  }, "Check error returned when giving invalid status to redirect(), status = " + invalidStatus);
+});
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-static-redirect.html b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-static-redirect.html
deleted file mode 100644
index f647b6d..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-static-redirect.html
+++ /dev/null
@@ -1,53 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Response: redirect static method</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#response">
-    <meta name="help" href="https://fetch.spec.whatwg.org/#redirect-status">
-    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-  </head>
-  <body>
-    <script>
-      var url = "http://test.url:1234/";
-      test(function() {
-        redirectResponse = Response.redirect(url);
-        assert_equals(redirectResponse.type, "default");
-        assert_false(redirectResponse.redirected);
-        assert_false(redirectResponse.ok);
-        assert_equals(redirectResponse.status, 302, "Default redirect status is 302");
-        assert_equals(redirectResponse.headers.get("Location"), url,
-          "redirected response has Location header with the correct url");
-        assert_equals(redirectResponse.statusText, "");
-      }, "Check default redirect response");
-
-      [301, 302, 303, 307, 308].forEach(function(status) {
-        test(function() {
-          redirectResponse = Response.redirect(url, status);
-          assert_equals(redirectResponse.type, "default");
-          assert_false(redirectResponse.redirected);
-          assert_false(redirectResponse.ok);
-          assert_equals(redirectResponse.status, status, "Redirect status is " + status);
-          assert_equals(redirectResponse.headers.get("Location"), url);
-          assert_equals(redirectResponse.statusText, "");
-        }, "Check response returned by static method redirect(), status = " + status);
-      });
-
-      test(function() {
-        var invalidUrl = "http://:This is not an url";
-        assert_throws_js(TypeError, function() { Response.redirect(invalidUrl); },
-          "Expect TypeError exception");
-      }, "Check error returned when giving invalid url to redirect()");
-
-      var invalidRedirectStatus = [200, 309, 400, 500];
-      invalidRedirectStatus.forEach(function(invalidStatus) {
-        test(function() {
-          assert_throws_js(RangeError, function() { Response.redirect(url, invalidStatus); },
-              "Expect RangeError exception");
-        }, "Check error returned when giving invalid status to redirect(), status = " + invalidStatus);
-      });
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-1.html b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-1.any.js
similarity index 72%
rename from third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-1.html
rename to third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-1.any.js
index c856a6d4e..d80049a 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-1.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-1.any.js
@@ -1,16 +1,5 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Consuming Response body after getting a ReadableStream</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#response">
-    <meta name="help" href="https://fetch.spec.whatwg.org/#body-mixin">
-    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-  </head>
-  <body>
-    <script>
+// META: global=window,worker
+// META: title=Consuming Response body after getting a ReadableStream
 
 function createResponseWithReadableStream(callback) {
     return fetch("../resources/data.json").then(function(response) {
@@ -51,7 +40,3 @@
         });
     });
 }, "Getting arrayBuffer after getting the Response body - not disturbed, not locked");
-
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-2.html b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-2.any.js
similarity index 68%
rename from third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-2.html
rename to third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-2.any.js
index 75cc4a59..ccff5475 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-2.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-2.any.js
@@ -1,16 +1,5 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Consuming Response body after getting a ReadableStream</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#response">
-    <meta name="help" href="https://fetch.spec.whatwg.org/#body-mixin">
-    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-  </head>
-  <body>
-    <script>
+// META: global=window,worker
+// META: title=Consuming Response body after getting a ReadableStream
 
 function createResponseWithLockedReadableStream(callback) {
     return fetch("../resources/data.json").then(function(response) {
@@ -42,7 +31,3 @@
         return promise_rejects_js(test, TypeError, response.arrayBuffer());
     });
 }, "Getting arrayBuffer after getting a locked Response body");
-
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-3.html b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-3.any.js
similarity index 68%
rename from third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-3.html
rename to third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-3.any.js
index 795357e6..32c1162 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-3.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-3.any.js
@@ -1,16 +1,5 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Consuming Response body after getting a ReadableStream</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#response">
-    <meta name="help" href="https://fetch.spec.whatwg.org/#body-mixin">
-    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-  </head>
-  <body>
-    <script>
+// META: global=window,worker
+// META: title=Consuming Response body after getting a ReadableStream
 
 function createResponseWithDisturbedReadableStream(callback) {
     return fetch("../resources/data.json").then(function(response) {
@@ -43,7 +32,3 @@
         return promise_rejects_js(test, TypeError, response.arrayBuffer());
     });
 }, "Getting arrayBuffer after reading the Response body");
-
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-4.html b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-4.any.js
similarity index 68%
rename from third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-4.html
rename to third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-4.any.js
index 9c387699..58331ae 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-4.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-4.any.js
@@ -1,16 +1,5 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Consuming Response body after getting a ReadableStream</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#response">
-    <meta name="help" href="https://fetch.spec.whatwg.org/#body-mixin">
-    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-  </head>
-  <body>
-    <script>
+// META: global=window,worker
+// META: title=Consuming Response body after getting a ReadableStream
 
 function createResponseWithCancelledReadableStream(callback) {
     return fetch("../resources/data.json").then(function(response) {
@@ -42,7 +31,3 @@
         return promise_rejects_js(test, TypeError, response.arrayBuffer());
     });
 }, "Getting arrayBuffer after cancelling the Response body");
-
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-5.html b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-5.any.js
similarity index 69%
rename from third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-5.html
rename to third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-5.any.js
index 830a41bc..9be0c93f 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-5.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-5.any.js
@@ -1,16 +1,5 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Consuming Response body after getting a ReadableStream</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#response">
-    <meta name="help" href="https://fetch.spec.whatwg.org/#body-mixin">
-    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-  </head>
-  <body>
-    <script>
+// META: global=window,worker
+// META: title=Consuming Response body after getting a ReadableStream
 
 promise_test(function() {
     return fetch("../resources/data.json").then(function(response) {
@@ -43,7 +32,3 @@
         assert_throws_js(TypeError, function() { response.body.getReader(); });
     });
 }, "Getting a body reader after consuming as arrayBuffer");
-
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-6.html b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-6.any.js
similarity index 79%
rename from third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-6.html
rename to third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-6.any.js
index 30492d4..61d8544 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-6.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-6.any.js
@@ -1,16 +1,6 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>ReadableStream disturbed tests, via Response's bodyUsed property</title>
-<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
-<link rel="author" title="Takeshi Yoshino" href="mailto:tyoshino@chromium.org">
+// META: global=window,worker
+// META: title=ReadableStream disturbed tests, via Response's bodyUsed property
 
-<link rel="help" href="https://streams.spec.whatwg.org/#is-readable-stream-disturbed">
-<link rel="help" href="https://fetch.spec.whatwg.org/#dom-body-bodyused">
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<script>
 "use strict";
 
 test(() => {
@@ -84,5 +74,3 @@
   reader.cancel().then(() => { }, () => { });
   assert_true(response.bodyUsed, "After calling stream.cancel()");
 }, "An errored stream on which cancel() has been called");
-
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-by-pipe.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-by-pipe.any.js
index f0066c2..5341b752 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-by-pipe.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-by-pipe.any.js
@@ -1,3 +1,5 @@
+// META: global=window,worker
+
 test(() => {
   const r = new Response(new ReadableStream());
   // highWaterMark: 0 means that nothing will actually be read from the body.
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-by-pipe.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-by-pipe.any.serviceworker-expected.txt
new file mode 100644
index 0000000..7ee0f33a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-by-pipe.any.serviceworker-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL using pipeTo on Response body should disturb it synchronously assert_true: bodyUsed should be true expected true got false
+FAIL using pipeThrough on Response body should disturb it synchronously assert_true: bodyUsed should be true expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-by-pipe.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-by-pipe.any.sharedworker-expected.txt
new file mode 100644
index 0000000..7ee0f33a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-disturbed-by-pipe.any.sharedworker-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL using pipeTo on Response body should disturb it synchronously assert_true: bodyUsed should be true expected true got false
+FAIL using pipeThrough on Response body should disturb it synchronously assert_true: bodyUsed should be true expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-with-broken-then.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-with-broken-then.any.js
index b83365d7..8fef66c8 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-with-broken-then.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-with-broken-then.any.js
@@ -1,3 +1,4 @@
+// META: global=window,worker
 // META: script=../resources/utils.js
 
 promise_test(async () => {
diff --git a/third_party/blink/web_tests/external/wpt/fetch/content-encoding/bad-gzip-body.any.js b/third_party/blink/web_tests/external/wpt/fetch/content-encoding/bad-gzip-body.any.js
index f8203226..17bc126 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/content-encoding/bad-gzip-body.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/content-encoding/bad-gzip-body.any.js
@@ -1,3 +1,5 @@
+// META: global=window,worker
+
 promise_test((test) => {
     return fetch("resources/bad-gzip-body.py").then(res => {
       assert_equals(res.status, 200);
diff --git a/third_party/blink/web_tests/external/wpt/fetch/data-urls/base64.any.js b/third_party/blink/web_tests/external/wpt/fetch/data-urls/base64.any.js
index c4080536..83f34db 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/data-urls/base64.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/data-urls/base64.any.js
@@ -1,3 +1,5 @@
+// META: global=window,worker
+
 promise_test(() => fetch("resources/base64.json").then(res => res.json()).then(runBase64Tests), "Setup.");
 function runBase64Tests(tests) {
   for(let i = 0; i < tests.length; i++) {
diff --git a/third_party/blink/web_tests/external/wpt/fetch/data-urls/processing.any.js b/third_party/blink/web_tests/external/wpt/fetch/data-urls/processing.any.js
index 940e5cea..cec97bd 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/data-urls/processing.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/data-urls/processing.any.js
@@ -1,3 +1,5 @@
+// META: global=window,worker
+
 promise_test(() => fetch("resources/data-urls.json").then(res => res.json()).then(runDataURLTests), "Setup.");
 function runDataURLTests(tests) {
   for(let i = 0; i < tests.length; i++) {
diff --git a/third_party/blink/web_tests/external/wpt/fetch/data-urls/processing.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/data-urls/processing.any.serviceworker-expected.txt
new file mode 100644
index 0000000..cfab79c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/data-urls/processing.any.serviceworker-expected.txt
@@ -0,0 +1,75 @@
+This is a testharness.js-based test.
+Found 71 tests; 49 PASS, 22 FAIL, 0 TIMEOUT, 0 NOTRUN.
+PASS Setup.
+PASS "data://test/,X"
+FAIL "data://test:test/,X" assert_unreached: Should have rejected: undefined Reached unreachable code
+PASS "data:,X"
+PASS "data:"
+PASS "data:text/html"
+PASS "data:text/html    ;charset=x   "
+PASS "data:,"
+PASS "data:,X#X"
+PASS "data:,%FF"
+PASS "data:text/plain,X"
+PASS "data:text/plain ,X"
+PASS "data:text/plain%20,X"
+PASS "data:text/plain\f,X"
+PASS "data:text/plain%0C,X"
+PASS "data:text/plain;,X"
+FAIL "data:;x=x;charset=x,X" assert_equals: expected "text/plain;x=x;charset=x" but got "text/plain;charset=x"
+FAIL "data:;x=x,X" assert_equals: expected "text/plain;x=x" but got "text/plain;charset=US-ASCII"
+PASS "data:text/plain;charset=windows-1252,%C2%B1"
+PASS "data:text/plain;Charset=UTF-8,%C2%B1"
+PASS "data:image/gif,%C2%B1"
+PASS "data:IMAGE/gif,%C2%B1"
+FAIL "data:IMAGE/gif;hi=x,%C2%B1" assert_equals: expected "image/gif;hi=x" but got "image/gif"
+PASS "data:IMAGE/gif;CHARSET=x,%C2%B1"
+PASS "data: ,%FF"
+PASS "data:%20,%FF"
+PASS "data:\f,%FF"
+PASS "data:%1F,%FF"
+PASS "data:\0,%FF"
+PASS "data:%00,%FF"
+PASS "data:text/html  ,X"
+PASS "data:text / html,X"
+PASS "data:†,X"
+PASS "data:†/†,X"
+PASS "data:X,X"
+FAIL "data:image/png,X X" assert_array_equals: lengths differ, expected array [88, 32, 88] length 3, got object "88,88" length 2
+FAIL "data:application/javascript,X X" assert_array_equals: lengths differ, expected array [88, 32, 88] length 3, got object "88,88" length 2
+PASS "data:application/xml,X X"
+PASS "data:text/javascript,X X"
+PASS "data:text/plain,X X"
+FAIL "data:unknown/unknown,X X" assert_array_equals: lengths differ, expected array [88, 32, 88] length 3, got object "88,88" length 2
+FAIL "data:text/plain;a=\",\",X" assert_equals: expected "text/plain;a=\"\"" but got "text/plain"
+FAIL "data:text/plain;a=%2C,X" assert_equals: expected "text/plain;a=%2C" but got "text/plain"
+FAIL "data:;base64;base64,WA" assert_equals: expected "text/plain" but got "text/plain;charset=US-ASCII"
+PASS "data:x/x;base64;base64,WA"
+FAIL "data:x/x;base64;charset=x,WA" assert_array_equals: lengths differ, expected array [87, 65] length 2, got object "88" length 1
+PASS "data:x/x;base64;charset=x;base64,WA"
+FAIL "data:x/x;base64;base64x,WA" assert_array_equals: lengths differ, expected array [87, 65] length 2, got object "88" length 1
+PASS "data:;base64,W%20A"
+PASS "data:;base64,W%0CA"
+PASS "data:x;base64x,WA"
+FAIL "data:x;base64;x,WA" assert_array_equals: lengths differ, expected array [87, 65] length 2, got object "88" length 1
+PASS "data:x;base64=x,WA"
+PASS "data:; base64,WA"
+PASS "data:;  base64,WA"
+PASS "data:  ;charset=x   ;  base64,WA"
+FAIL "data:;base64;,WA" assert_array_equals: lengths differ, expected array [87, 65] length 2, got object "88" length 1
+PASS "data:;base64 ,WA"
+PASS "data:;base64   ,WA"
+FAIL "data:;base 64,WA" assert_equals: expected "text/plain" but got "text/plain;charset=US-ASCII"
+PASS "data:;BASe64,WA"
+FAIL "data:;%62ase64,WA" assert_equals: expected "text/plain" but got "text/plain;charset=US-ASCII"
+PASS "data:%3Bbase64,WA"
+PASS "data:;charset=x,X"
+PASS "data:; charset=x,X"
+FAIL "data:;charset =x,X" assert_equals: expected "text/plain" but got "text/plain;charset=US-ASCII"
+FAIL "data:;charset= x,X" promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch"
+FAIL "data:;charset=,X" promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch"
+FAIL "data:;charset,X" assert_equals: expected "text/plain" but got "text/plain;charset=US-ASCII"
+FAIL "data:;charset=\"x\",X" promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch"
+FAIL "data:;CHARSET=\"X\",X" promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/data-urls/processing.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/data-urls/processing.any.sharedworker-expected.txt
new file mode 100644
index 0000000..cfab79c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/data-urls/processing.any.sharedworker-expected.txt
@@ -0,0 +1,75 @@
+This is a testharness.js-based test.
+Found 71 tests; 49 PASS, 22 FAIL, 0 TIMEOUT, 0 NOTRUN.
+PASS Setup.
+PASS "data://test/,X"
+FAIL "data://test:test/,X" assert_unreached: Should have rejected: undefined Reached unreachable code
+PASS "data:,X"
+PASS "data:"
+PASS "data:text/html"
+PASS "data:text/html    ;charset=x   "
+PASS "data:,"
+PASS "data:,X#X"
+PASS "data:,%FF"
+PASS "data:text/plain,X"
+PASS "data:text/plain ,X"
+PASS "data:text/plain%20,X"
+PASS "data:text/plain\f,X"
+PASS "data:text/plain%0C,X"
+PASS "data:text/plain;,X"
+FAIL "data:;x=x;charset=x,X" assert_equals: expected "text/plain;x=x;charset=x" but got "text/plain;charset=x"
+FAIL "data:;x=x,X" assert_equals: expected "text/plain;x=x" but got "text/plain;charset=US-ASCII"
+PASS "data:text/plain;charset=windows-1252,%C2%B1"
+PASS "data:text/plain;Charset=UTF-8,%C2%B1"
+PASS "data:image/gif,%C2%B1"
+PASS "data:IMAGE/gif,%C2%B1"
+FAIL "data:IMAGE/gif;hi=x,%C2%B1" assert_equals: expected "image/gif;hi=x" but got "image/gif"
+PASS "data:IMAGE/gif;CHARSET=x,%C2%B1"
+PASS "data: ,%FF"
+PASS "data:%20,%FF"
+PASS "data:\f,%FF"
+PASS "data:%1F,%FF"
+PASS "data:\0,%FF"
+PASS "data:%00,%FF"
+PASS "data:text/html  ,X"
+PASS "data:text / html,X"
+PASS "data:†,X"
+PASS "data:†/†,X"
+PASS "data:X,X"
+FAIL "data:image/png,X X" assert_array_equals: lengths differ, expected array [88, 32, 88] length 3, got object "88,88" length 2
+FAIL "data:application/javascript,X X" assert_array_equals: lengths differ, expected array [88, 32, 88] length 3, got object "88,88" length 2
+PASS "data:application/xml,X X"
+PASS "data:text/javascript,X X"
+PASS "data:text/plain,X X"
+FAIL "data:unknown/unknown,X X" assert_array_equals: lengths differ, expected array [88, 32, 88] length 3, got object "88,88" length 2
+FAIL "data:text/plain;a=\",\",X" assert_equals: expected "text/plain;a=\"\"" but got "text/plain"
+FAIL "data:text/plain;a=%2C,X" assert_equals: expected "text/plain;a=%2C" but got "text/plain"
+FAIL "data:;base64;base64,WA" assert_equals: expected "text/plain" but got "text/plain;charset=US-ASCII"
+PASS "data:x/x;base64;base64,WA"
+FAIL "data:x/x;base64;charset=x,WA" assert_array_equals: lengths differ, expected array [87, 65] length 2, got object "88" length 1
+PASS "data:x/x;base64;charset=x;base64,WA"
+FAIL "data:x/x;base64;base64x,WA" assert_array_equals: lengths differ, expected array [87, 65] length 2, got object "88" length 1
+PASS "data:;base64,W%20A"
+PASS "data:;base64,W%0CA"
+PASS "data:x;base64x,WA"
+FAIL "data:x;base64;x,WA" assert_array_equals: lengths differ, expected array [87, 65] length 2, got object "88" length 1
+PASS "data:x;base64=x,WA"
+PASS "data:; base64,WA"
+PASS "data:;  base64,WA"
+PASS "data:  ;charset=x   ;  base64,WA"
+FAIL "data:;base64;,WA" assert_array_equals: lengths differ, expected array [87, 65] length 2, got object "88" length 1
+PASS "data:;base64 ,WA"
+PASS "data:;base64   ,WA"
+FAIL "data:;base 64,WA" assert_equals: expected "text/plain" but got "text/plain;charset=US-ASCII"
+PASS "data:;BASe64,WA"
+FAIL "data:;%62ase64,WA" assert_equals: expected "text/plain" but got "text/plain;charset=US-ASCII"
+PASS "data:%3Bbase64,WA"
+PASS "data:;charset=x,X"
+PASS "data:; charset=x,X"
+FAIL "data:;charset =x,X" assert_equals: expected "text/plain" but got "text/plain;charset=US-ASCII"
+FAIL "data:;charset= x,X" promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch"
+FAIL "data:;charset=,X" promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch"
+FAIL "data:;charset,X" assert_equals: expected "text/plain" but got "text/plain;charset=US-ASCII"
+FAIL "data:;charset=\"x\",X" promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch"
+FAIL "data:;CHARSET=\"X\",X" promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/304-update.any.js b/third_party/blink/web_tests/external/wpt/fetch/http-cache/304-update.any.js
new file mode 100644
index 0000000..15484f01
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/304-update.any.js
@@ -0,0 +1,146 @@
+// META: global=window,worker
+// META: title=HTTP Cache - 304 Updates
+// META: timeout=long
+// META: script=/common/utils.js
+// META: script=/common/get-host-info.sub.js
+// META: script=http-cache.js
+
+var tests = [
+  {
+    name: "HTTP cache updates returned headers from a Last-Modified 304",
+    requests: [
+      {
+        response_headers: [
+          ["Expires", -5000],
+          ["Last-Modified", -3000],
+          ["Test-Header", "A"]
+        ]
+      },
+      {
+        response_headers: [
+          ["Expires", -3000],
+          ["Last-Modified", -3000],
+          ["Test-Header", "B"]
+        ],
+        expected_type: "lm_validated",
+        expected_response_headers: [
+          ["Test-Header", "B"]
+        ]
+      }
+    ]
+  },
+  {
+    name: "HTTP cache updates stored headers from a Last-Modified 304",
+    requests: [
+      {
+        response_headers: [
+          ["Expires", -5000],
+          ["Last-Modified", -3000],
+          ["Test-Header", "A"]
+        ]
+      },
+      {
+        response_headers: [
+          ["Expires", 3000],
+          ["Last-Modified", -3000],
+          ["Test-Header", "B"]
+        ],
+        expected_type: "lm_validated",
+        expected_response_headers: [
+          ["Test-Header", "B"]
+        ],
+        pause_after: true
+      },
+      {
+        expected_type: "cached",
+        expected_response_headers: [
+          ["Test-Header", "B"]
+        ]
+      }
+    ]
+  },
+  {
+    name: "HTTP cache updates returned headers from a ETag 304",
+    requests: [
+      {
+        response_headers: [
+          ["Expires", -5000],
+          ["ETag", "ABC"],
+          ["Test-Header", "A"]
+        ]
+      },
+      {
+        response_headers: [
+          ["Expires", -3000],
+          ["ETag", "ABC"],
+          ["Test-Header", "B"]
+        ],
+        expected_type: "etag_validated",
+        expected_response_headers: [
+          ["Test-Header", "B"]
+        ]
+      }
+    ]
+  },
+  {
+    name: "HTTP cache updates stored headers from a ETag 304",
+    requests: [
+      {
+        response_headers: [
+          ["Expires", -5000],
+          ["ETag", "DEF"],
+          ["Test-Header", "A"]
+        ]
+      },
+      {
+        response_headers: [
+          ["Expires", 3000],
+          ["ETag", "DEF"],
+          ["Test-Header", "B"]
+        ],
+        expected_type: "etag_validated",
+        expected_response_headers: [
+          ["Test-Header", "B"]
+        ],
+        pause_after: true
+      },
+      {
+        expected_type: "cached",
+        expected_response_headers: [
+          ["Test-Header", "B"]
+        ]
+      }
+    ]
+  },
+  {
+    name: "Content-* header",
+    requests: [
+      {
+        response_headers: [
+          ["Expires", -5000],
+          ["ETag", "GHI"],
+          ["Content-Test-Header", "A"]
+        ]
+      },
+      {
+        response_headers: [
+          ["Expires", 3000],
+          ["ETag", "GHI"],
+          ["Content-Test-Header", "B"]
+        ],
+        expected_type: "etag_validated",
+        expected_response_headers: [
+          ["Content-Test-Header", "B"]
+        ],
+        pause_after: true
+      },
+      {
+        expected_type: "cached",
+        expected_response_headers: [
+          ["Content-Test-Header", "B"]
+        ]
+      }
+    ]
+  },
+];
+run_tests(tests);
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/304-update.html b/third_party/blink/web_tests/external/wpt/fetch/http-cache/304-update.html
deleted file mode 100644
index d6d8481..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/http-cache/304-update.html
+++ /dev/null
@@ -1,157 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>HTTP Cache - 304 Updates</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#request">
-    <meta name="timeout" content="long">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <script src="/common/utils.js"></script>
-    <script src="/common/get-host-info.sub.js"></script>
-    <script src="http-cache.js"></script>
-  </head>
-  <body>
-    <script>
-    var tests = [
-      {
-        name: "HTTP cache updates returned headers from a Last-Modified 304",
-        requests: [
-          {
-            response_headers: [
-              ["Expires", -5000],
-              ["Last-Modified", -3000],
-              ["Test-Header", "A"]
-            ]
-          },
-          {
-            response_headers: [
-              ["Expires", -3000],
-              ["Last-Modified", -3000],
-              ["Test-Header", "B"]
-            ],
-            expected_type: "lm_validated",
-            expected_response_headers: [
-              ["Test-Header", "B"]
-            ]
-          }
-        ]
-      },
-      {
-        name: "HTTP cache updates stored headers from a Last-Modified 304",
-        requests: [
-          {
-            response_headers: [
-              ["Expires", -5000],
-              ["Last-Modified", -3000],
-              ["Test-Header", "A"]
-            ]
-          },
-          {
-            response_headers: [
-              ["Expires", 3000],
-              ["Last-Modified", -3000],
-              ["Test-Header", "B"]
-            ],
-            expected_type: "lm_validated",
-            expected_response_headers: [
-              ["Test-Header", "B"]
-            ],
-            pause_after: true
-          },
-          {
-            expected_type: "cached",
-            expected_response_headers: [
-              ["Test-Header", "B"]
-            ]
-          }
-        ]
-      },
-      {
-        name: "HTTP cache updates returned headers from a ETag 304",
-        requests: [
-          {
-            response_headers: [
-              ["Expires", -5000],
-              ["ETag", "ABC"],
-              ["Test-Header", "A"]
-            ]
-          },
-          {
-            response_headers: [
-              ["Expires", -3000],
-              ["ETag", "ABC"],
-              ["Test-Header", "B"]
-            ],
-            expected_type: "etag_validated",
-            expected_response_headers: [
-              ["Test-Header", "B"]
-            ]
-          }
-        ]
-      },
-      {
-        name: "HTTP cache updates stored headers from a ETag 304",
-        requests: [
-          {
-            response_headers: [
-              ["Expires", -5000],
-              ["ETag", "DEF"],
-              ["Test-Header", "A"]
-            ]
-          },
-          {
-            response_headers: [
-              ["Expires", 3000],
-              ["ETag", "DEF"],
-              ["Test-Header", "B"]
-            ],
-            expected_type: "etag_validated",
-            expected_response_headers: [
-              ["Test-Header", "B"]
-            ],
-            pause_after: true
-          },
-          {
-            expected_type: "cached",
-            expected_response_headers: [
-              ["Test-Header", "B"]
-            ]
-          }
-        ]
-      },
-      {
-        name: "Content-* header",
-        requests: [
-          {
-            response_headers: [
-              ["Expires", -5000],
-              ["ETag", "GHI"],
-              ["Content-Test-Header", "A"]
-            ]
-          },
-          {
-            response_headers: [
-              ["Expires", 3000],
-              ["ETag", "GHI"],
-              ["Content-Test-Header", "B"]
-            ],
-            expected_type: "etag_validated",
-            expected_response_headers: [
-              ["Content-Test-Header", "B"]
-            ],
-            pause_after: true
-          },
-          {
-            expected_type: "cached",
-            expected_response_headers: [
-              ["Content-Test-Header", "B"]
-            ]
-          }
-        ]
-      },
-    ];
-    run_tests(tests);
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/cache-mode.any-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/http-cache/cache-mode.any-expected.txt
new file mode 100644
index 0000000..bee27041
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/cache-mode.any-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+PASS Fetch sends Cache-Control: max-age=0 when cache mode is no-cache
+PASS Fetch doesn't touch Cache-Control when cache mode is no-cache and Cache-Control is already present
+FAIL Fetch sends Cache-Control: no-cache and Pragma: no-cache when cache mode is no-store assert_equals: request 1 header cache-control value is "undefined", not "no-cache" expected (string) "no-cache" but got (undefined) undefined
+PASS Fetch doesn't touch Cache-Control when cache mode is no-store and Cache-Control is already present
+PASS Fetch doesn't touch Pragma when cache mode is no-store and Pragma is already present
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/cache-mode.any.js b/third_party/blink/web_tests/external/wpt/fetch/http-cache/cache-mode.any.js
new file mode 100644
index 0000000..8f406d5a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/cache-mode.any.js
@@ -0,0 +1,61 @@
+// META: global=window,worker
+// META: title=Fetch - Cache Mode
+// META: timeout=long
+// META: script=/common/utils.js
+// META: script=/common/get-host-info.sub.js
+// META: script=http-cache.js
+
+var tests = [
+  {
+    name: "Fetch sends Cache-Control: max-age=0 when cache mode is no-cache",
+    requests: [
+      {
+        cache: "no-cache",
+        expected_request_headers: [['cache-control', 'max-age=0']]
+      }
+    ]
+  },
+  {
+    name: "Fetch doesn't touch Cache-Control when cache mode is no-cache and Cache-Control is already present",
+    requests: [
+      {
+        cache: "no-cache",
+        request_headers: [['cache-control', 'foo']],
+        expected_request_headers: [['cache-control', 'foo']]
+      }
+    ]
+  },
+  {
+    name: "Fetch sends Cache-Control: no-cache and Pragma: no-cache when cache mode is no-store",
+    requests: [
+      {
+        cache: "no-store",
+        expected_request_headers: [
+          ['cache-control', 'no-cache'],
+          ['pragma', 'no-cache']
+        ]
+      }
+    ]
+  },
+  {
+    name: "Fetch doesn't touch Cache-Control when cache mode is no-store and Cache-Control is already present",
+    requests: [
+      {
+        cache: "no-store",
+        request_headers: [['cache-control', 'foo']],
+        expected_request_headers: [['cache-control', 'foo']]
+      }
+    ]
+  },
+  {
+    name: "Fetch doesn't touch Pragma when cache mode is no-store and Pragma is already present",
+    requests: [
+      {
+        cache: "no-store",
+        request_headers: [['pragma', 'foo']],
+        expected_request_headers: [['pragma', 'foo']]
+      }
+    ]
+  }
+];
+run_tests(tests);
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/cache-mode.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/http-cache/cache-mode.any.serviceworker-expected.txt
new file mode 100644
index 0000000..bee27041
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/cache-mode.any.serviceworker-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+PASS Fetch sends Cache-Control: max-age=0 when cache mode is no-cache
+PASS Fetch doesn't touch Cache-Control when cache mode is no-cache and Cache-Control is already present
+FAIL Fetch sends Cache-Control: no-cache and Pragma: no-cache when cache mode is no-store assert_equals: request 1 header cache-control value is "undefined", not "no-cache" expected (string) "no-cache" but got (undefined) undefined
+PASS Fetch doesn't touch Cache-Control when cache mode is no-store and Cache-Control is already present
+PASS Fetch doesn't touch Pragma when cache mode is no-store and Pragma is already present
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/cache-mode.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/http-cache/cache-mode.any.sharedworker-expected.txt
new file mode 100644
index 0000000..bee27041
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/cache-mode.any.sharedworker-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+PASS Fetch sends Cache-Control: max-age=0 when cache mode is no-cache
+PASS Fetch doesn't touch Cache-Control when cache mode is no-cache and Cache-Control is already present
+FAIL Fetch sends Cache-Control: no-cache and Pragma: no-cache when cache mode is no-store assert_equals: request 1 header cache-control value is "undefined", not "no-cache" expected (string) "no-cache" but got (undefined) undefined
+PASS Fetch doesn't touch Cache-Control when cache mode is no-store and Cache-Control is already present
+PASS Fetch doesn't touch Pragma when cache mode is no-store and Pragma is already present
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/cache-mode.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/http-cache/cache-mode.any.worker-expected.txt
new file mode 100644
index 0000000..bee27041
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/cache-mode.any.worker-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+PASS Fetch sends Cache-Control: max-age=0 when cache mode is no-cache
+PASS Fetch doesn't touch Cache-Control when cache mode is no-cache and Cache-Control is already present
+FAIL Fetch sends Cache-Control: no-cache and Pragma: no-cache when cache mode is no-store assert_equals: request 1 header cache-control value is "undefined", not "no-cache" expected (string) "no-cache" but got (undefined) undefined
+PASS Fetch doesn't touch Cache-Control when cache mode is no-store and Cache-Control is already present
+PASS Fetch doesn't touch Pragma when cache mode is no-store and Pragma is already present
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/cache-mode.html b/third_party/blink/web_tests/external/wpt/fetch/http-cache/cache-mode.html
deleted file mode 100644
index ea5bbad0..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/http-cache/cache-mode.html
+++ /dev/null
@@ -1,72 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Fetch - Cache Mode</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-or-cache-fetch">
-    <meta name="timeout" content="long">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <script src="/common/utils.js"></script>
-    <script src="/common/get-host-info.sub.js"></script>
-    <script src="http-cache.js"></script>
-  </head>
-  <body>
-    <script>
-    var tests = [
-      {
-        name: "Fetch sends Cache-Control: max-age=0 when cache mode is no-cache",
-        requests: [
-          {
-            cache: "no-cache",
-            expected_request_headers: [['cache-control', 'max-age=0']]
-          }
-        ]
-      },
-      {
-        name: "Fetch doesn't touch Cache-Control when cache mode is no-cache and Cache-Control is already present",
-        requests: [
-          {
-            cache: "no-cache",
-            request_headers: [['cache-control', 'foo']],
-            expected_request_headers: [['cache-control', 'foo']]
-          }
-        ]
-      },
-      {
-        name: "Fetch sends Cache-Control: no-cache and Pragma: no-cache when cache mode is no-store",
-        requests: [
-          {
-            cache: "no-store",
-            expected_request_headers: [
-              ['cache-control', 'no-cache'],
-              ['pragma', 'no-cache']
-            ]
-          }
-        ]
-      },
-      {
-        name: "Fetch doesn't touch Cache-Control when cache mode is no-store and Cache-Control is already present",
-        requests: [
-          {
-            cache: "no-store",
-            request_headers: [['cache-control', 'foo']],
-            expected_request_headers: [['cache-control', 'foo']]
-          }
-        ]
-      },
-      {
-        name: "Fetch doesn't touch Pragma when cache mode is no-store and Pragma is already present",
-        requests: [
-          {
-            cache: "no-store",
-            request_headers: [['pragma', 'foo']],
-            expected_request_headers: [['pragma', 'foo']]
-          }
-        ]
-      }
-    ];
-    run_tests(tests);
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/cc-request.any-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/http-cache/cc-request.any-expected.txt
new file mode 100644
index 0000000..10e574ea6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/cc-request.any-expected.txt
@@ -0,0 +1,15 @@
+This is a testharness.js-based test.
+PASS HTTP cache doesn't use aged but fresh response when request contains Cache-Control: max-age=0
+FAIL HTTP cache doesn't use aged but fresh response when request contains Cache-Control: max-age=1 assert_equals: Response 2 comes from cache expected 2 but got 1
+FAIL HTTP cache doesn't use fresh response with Age header when request contains Cache-Control: max-age that is greater than remaining freshness assert_equals: Response 2 comes from cache expected 2 but got 1
+FAIL HTTP cache does use aged stale response when request contains Cache-Control: max-stale that permits its use assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache does reuse stale response with Age header when request contains Cache-Control: max-stale that permits its use assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache doesn't reuse fresh response when request contains Cache-Control: min-fresh that wants it fresher assert_equals: Response 2 comes from cache expected 2 but got 1
+FAIL HTTP cache doesn't reuse fresh response with Age header when request contains Cache-Control: min-fresh that wants it fresher assert_equals: Response 2 comes from cache expected 2 but got 1
+PASS HTTP cache doesn't reuse fresh response when request contains Cache-Control: no-cache
+PASS HTTP cache validates fresh response with Last-Modified when request contains Cache-Control: no-cache
+PASS HTTP cache validates fresh response with ETag when request contains Cache-Control: no-cache
+FAIL HTTP cache doesn't reuse fresh response when request contains Cache-Control: no-store assert_equals: Response 2 comes from cache expected 2 but got 1
+FAIL HTTP cache generates 504 status code when nothing is in cache and request contains Cache-Control: only-if-cached assert_equals: Response 1 status is 200, not 504 expected 504 but got 200
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/cc-request.any.js b/third_party/blink/web_tests/external/wpt/fetch/http-cache/cc-request.any.js
new file mode 100644
index 0000000..d556566
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/cc-request.any.js
@@ -0,0 +1,202 @@
+// META: global=window,worker
+// META: title=HTTP Cache - Cache-Control Request Directives
+// META: timeout=long
+// META: script=/common/utils.js
+// META: script=/common/get-host-info.sub.js
+// META: script=http-cache.js
+
+var tests = [
+  {
+    name: "HTTP cache doesn't use aged but fresh response when request contains Cache-Control: max-age=0",
+    requests: [
+      {
+        template: "fresh",
+        pause_after: true
+      },
+      {
+        request_headers: [
+          ["Cache-Control", "max-age=0"]
+        ],
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache doesn't use aged but fresh response when request contains Cache-Control: max-age=1",
+    requests: [
+      {
+        template: "fresh",
+        pause_after: true
+      },
+      {
+        request_headers: [
+          ["Cache-Control", "max-age=1"]
+        ],
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache doesn't use fresh response with Age header when request contains Cache-Control: max-age that is greater than remaining freshness",
+    requests: [
+      {
+        response_headers: [
+          ["Cache-Control", "max-age=3600"],
+          ["Age", "1800"]
+        ]
+      },
+      {
+        request_headers: [
+          ["Cache-Control", "max-age=600"]
+        ],
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache does use aged stale response when request contains Cache-Control: max-stale that permits its use",
+    requests: [
+      {
+        response_headers: [
+          ["Cache-Control", "max-age=1"]
+        ],
+        pause_after: true
+      },
+      {
+        request_headers: [
+          ["Cache-Control", "max-stale=1000"]
+        ],
+        expected_type: "cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache does reuse stale response with Age header when request contains Cache-Control: max-stale that permits its use",
+    requests: [
+      {
+        response_headers: [
+          ["Cache-Control", "max-age=1500"],
+          ["Age", "2000"]
+        ]
+      },
+      {
+        request_headers: [
+          ["Cache-Control", "max-stale=1000"]
+        ],
+        expected_type: "cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache doesn't reuse fresh response when request contains Cache-Control: min-fresh that wants it fresher",
+    requests: [
+      {
+        response_headers: [
+          ["Cache-Control", "max-age=1500"]
+        ]
+      },
+      {
+        request_headers: [
+          ["Cache-Control", "min-fresh=2000"]
+        ],
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache doesn't reuse fresh response with Age header when request contains Cache-Control: min-fresh that wants it fresher",
+    requests: [
+      {
+        response_headers: [
+          ["Cache-Control", "max-age=1500"],
+          ["Age", "1000"]
+        ]
+      },
+      {
+        request_headers: [
+          ["Cache-Control", "min-fresh=1000"]
+        ],
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache doesn't reuse fresh response when request contains Cache-Control: no-cache",
+    requests: [
+      {
+        response_headers: [
+          ["Cache-Control", "max-age=3600"]
+        ]
+      },
+      {
+        request_headers: [
+          ["Cache-Control", "no-cache"]
+        ],
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache validates fresh response with Last-Modified when request contains Cache-Control: no-cache",
+    requests: [
+      {
+        response_headers: [
+          ["Cache-Control", "max-age=3600"],
+          ["Last-Modified", -10000]
+        ]
+      },
+      {
+        request_headers: [
+          ["Cache-Control", "no-cache"]
+        ],
+        expected_type: "lm_validate"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache validates fresh response with ETag when request contains Cache-Control: no-cache",
+    requests: [
+      {
+        response_headers: [
+          ["Cache-Control", "max-age=3600"],
+          ["ETag", http_content("abc")]
+        ]
+      },
+      {
+        request_headers: [
+          ["Cache-Control", "no-cache"]
+        ],
+        expected_type: "etag_validate"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache doesn't reuse fresh response when request contains Cache-Control: no-store",
+    requests: [
+      {
+        response_headers: [
+          ["Cache-Control", "max-age=3600"]
+        ]
+      },
+      {
+        request_headers: [
+          ["Cache-Control", "no-store"]
+        ],
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache generates 504 status code when nothing is in cache and request contains Cache-Control: only-if-cached",
+    requests: [
+      {
+        request_headers: [
+          ["Cache-Control", "only-if-cached"]
+        ],
+        expected_status: 504,
+        expected_response_text: null
+      }
+    ]
+  }
+];
+run_tests(tests);
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/cc-request.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/http-cache/cc-request.any.serviceworker-expected.txt
new file mode 100644
index 0000000..10e574ea6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/cc-request.any.serviceworker-expected.txt
@@ -0,0 +1,15 @@
+This is a testharness.js-based test.
+PASS HTTP cache doesn't use aged but fresh response when request contains Cache-Control: max-age=0
+FAIL HTTP cache doesn't use aged but fresh response when request contains Cache-Control: max-age=1 assert_equals: Response 2 comes from cache expected 2 but got 1
+FAIL HTTP cache doesn't use fresh response with Age header when request contains Cache-Control: max-age that is greater than remaining freshness assert_equals: Response 2 comes from cache expected 2 but got 1
+FAIL HTTP cache does use aged stale response when request contains Cache-Control: max-stale that permits its use assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache does reuse stale response with Age header when request contains Cache-Control: max-stale that permits its use assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache doesn't reuse fresh response when request contains Cache-Control: min-fresh that wants it fresher assert_equals: Response 2 comes from cache expected 2 but got 1
+FAIL HTTP cache doesn't reuse fresh response with Age header when request contains Cache-Control: min-fresh that wants it fresher assert_equals: Response 2 comes from cache expected 2 but got 1
+PASS HTTP cache doesn't reuse fresh response when request contains Cache-Control: no-cache
+PASS HTTP cache validates fresh response with Last-Modified when request contains Cache-Control: no-cache
+PASS HTTP cache validates fresh response with ETag when request contains Cache-Control: no-cache
+FAIL HTTP cache doesn't reuse fresh response when request contains Cache-Control: no-store assert_equals: Response 2 comes from cache expected 2 but got 1
+FAIL HTTP cache generates 504 status code when nothing is in cache and request contains Cache-Control: only-if-cached assert_equals: Response 1 status is 200, not 504 expected 504 but got 200
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/cc-request.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/http-cache/cc-request.any.sharedworker-expected.txt
new file mode 100644
index 0000000..10e574ea6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/cc-request.any.sharedworker-expected.txt
@@ -0,0 +1,15 @@
+This is a testharness.js-based test.
+PASS HTTP cache doesn't use aged but fresh response when request contains Cache-Control: max-age=0
+FAIL HTTP cache doesn't use aged but fresh response when request contains Cache-Control: max-age=1 assert_equals: Response 2 comes from cache expected 2 but got 1
+FAIL HTTP cache doesn't use fresh response with Age header when request contains Cache-Control: max-age that is greater than remaining freshness assert_equals: Response 2 comes from cache expected 2 but got 1
+FAIL HTTP cache does use aged stale response when request contains Cache-Control: max-stale that permits its use assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache does reuse stale response with Age header when request contains Cache-Control: max-stale that permits its use assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache doesn't reuse fresh response when request contains Cache-Control: min-fresh that wants it fresher assert_equals: Response 2 comes from cache expected 2 but got 1
+FAIL HTTP cache doesn't reuse fresh response with Age header when request contains Cache-Control: min-fresh that wants it fresher assert_equals: Response 2 comes from cache expected 2 but got 1
+PASS HTTP cache doesn't reuse fresh response when request contains Cache-Control: no-cache
+PASS HTTP cache validates fresh response with Last-Modified when request contains Cache-Control: no-cache
+PASS HTTP cache validates fresh response with ETag when request contains Cache-Control: no-cache
+FAIL HTTP cache doesn't reuse fresh response when request contains Cache-Control: no-store assert_equals: Response 2 comes from cache expected 2 but got 1
+FAIL HTTP cache generates 504 status code when nothing is in cache and request contains Cache-Control: only-if-cached assert_equals: Response 1 status is 200, not 504 expected 504 but got 200
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/cc-request.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/http-cache/cc-request.any.worker-expected.txt
new file mode 100644
index 0000000..10e574ea6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/cc-request.any.worker-expected.txt
@@ -0,0 +1,15 @@
+This is a testharness.js-based test.
+PASS HTTP cache doesn't use aged but fresh response when request contains Cache-Control: max-age=0
+FAIL HTTP cache doesn't use aged but fresh response when request contains Cache-Control: max-age=1 assert_equals: Response 2 comes from cache expected 2 but got 1
+FAIL HTTP cache doesn't use fresh response with Age header when request contains Cache-Control: max-age that is greater than remaining freshness assert_equals: Response 2 comes from cache expected 2 but got 1
+FAIL HTTP cache does use aged stale response when request contains Cache-Control: max-stale that permits its use assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache does reuse stale response with Age header when request contains Cache-Control: max-stale that permits its use assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache doesn't reuse fresh response when request contains Cache-Control: min-fresh that wants it fresher assert_equals: Response 2 comes from cache expected 2 but got 1
+FAIL HTTP cache doesn't reuse fresh response with Age header when request contains Cache-Control: min-fresh that wants it fresher assert_equals: Response 2 comes from cache expected 2 but got 1
+PASS HTTP cache doesn't reuse fresh response when request contains Cache-Control: no-cache
+PASS HTTP cache validates fresh response with Last-Modified when request contains Cache-Control: no-cache
+PASS HTTP cache validates fresh response with ETag when request contains Cache-Control: no-cache
+FAIL HTTP cache doesn't reuse fresh response when request contains Cache-Control: no-store assert_equals: Response 2 comes from cache expected 2 but got 1
+FAIL HTTP cache generates 504 status code when nothing is in cache and request contains Cache-Control: only-if-cached assert_equals: Response 1 status is 200, not 504 expected 504 but got 200
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/cc-request.html b/third_party/blink/web_tests/external/wpt/fetch/http-cache/cc-request.html
deleted file mode 100644
index e732683..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/http-cache/cc-request.html
+++ /dev/null
@@ -1,213 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>HTTP Cache - Cache-Control Request Directives</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#request">
-    <meta name="timeout" content="long">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <script src="/common/utils.js"></script>
-    <script src="/common/get-host-info.sub.js"></script>
-    <script src="http-cache.js"></script>
-  </head>
-  <body>
-    <script>
-    var tests = [
-      {
-        name: "HTTP cache doesn't use aged but fresh response when request contains Cache-Control: max-age=0",
-        requests: [
-          {
-            template: "fresh",
-            pause_after: true
-          },
-          {
-            request_headers: [
-              ["Cache-Control", "max-age=0"]
-            ],
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache doesn't use aged but fresh response when request contains Cache-Control: max-age=1",
-        requests: [
-          {
-            template: "fresh",
-            pause_after: true
-          },
-          {
-            request_headers: [
-              ["Cache-Control", "max-age=1"]
-            ],
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache doesn't use fresh response with Age header when request contains Cache-Control: max-age that is greater than remaining freshness",
-        requests: [
-          {
-            response_headers: [
-              ["Cache-Control", "max-age=3600"],
-              ["Age", "1800"]
-            ]
-          },
-          {
-            request_headers: [
-              ["Cache-Control", "max-age=600"]
-            ],
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache does use aged stale response when request contains Cache-Control: max-stale that permits its use",
-        requests: [
-          {
-            response_headers: [
-              ["Cache-Control", "max-age=1"]
-            ],
-            pause_after: true
-          },
-          {
-            request_headers: [
-              ["Cache-Control", "max-stale=1000"]
-            ],
-            expected_type: "cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache does reuse stale response with Age header when request contains Cache-Control: max-stale that permits its use",
-        requests: [
-          {
-            response_headers: [
-              ["Cache-Control", "max-age=1500"],
-              ["Age", "2000"]
-            ]
-          },
-          {
-            request_headers: [
-              ["Cache-Control", "max-stale=1000"]
-            ],
-            expected_type: "cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache doesn't reuse fresh response when request contains Cache-Control: min-fresh that wants it fresher",
-        requests: [
-          {
-            response_headers: [
-              ["Cache-Control", "max-age=1500"]
-            ]
-          },
-          {
-            request_headers: [
-              ["Cache-Control", "min-fresh=2000"]
-            ],
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache doesn't reuse fresh response with Age header when request contains Cache-Control: min-fresh that wants it fresher",
-        requests: [
-          {
-            response_headers: [
-              ["Cache-Control", "max-age=1500"],
-              ["Age", "1000"]
-            ]
-          },
-          {
-            request_headers: [
-              ["Cache-Control", "min-fresh=1000"]
-            ],
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache doesn't reuse fresh response when request contains Cache-Control: no-cache",
-        requests: [
-          {
-            response_headers: [
-              ["Cache-Control", "max-age=3600"]
-            ]
-          },
-          {
-            request_headers: [
-              ["Cache-Control", "no-cache"]
-            ],
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache validates fresh response with Last-Modified when request contains Cache-Control: no-cache",
-        requests: [
-          {
-            response_headers: [
-              ["Cache-Control", "max-age=3600"],
-              ["Last-Modified", -10000]
-            ]
-          },
-          {
-            request_headers: [
-              ["Cache-Control", "no-cache"]
-            ],
-            expected_type: "lm_validate"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache validates fresh response with ETag when request contains Cache-Control: no-cache",
-        requests: [
-          {
-            response_headers: [
-              ["Cache-Control", "max-age=3600"],
-              ["ETag", http_content("abc")]
-            ]
-          },
-          {
-            request_headers: [
-              ["Cache-Control", "no-cache"]
-            ],
-            expected_type: "etag_validate"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache doesn't reuse fresh response when request contains Cache-Control: no-store",
-        requests: [
-          {
-            response_headers: [
-              ["Cache-Control", "max-age=3600"]
-            ]
-          },
-          {
-            request_headers: [
-              ["Cache-Control", "no-store"]
-            ],
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache generates 504 status code when nothing is in cache and request contains Cache-Control: only-if-cached",
-        requests: [
-          {
-            request_headers: [
-              ["Cache-Control", "only-if-cached"]
-            ],
-            expected_status: 504,
-            expected_response_text: null
-          }
-        ]
-      }
-    ];
-    run_tests(tests);
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/freshness.any.js b/third_party/blink/web_tests/external/wpt/fetch/http-cache/freshness.any.js
new file mode 100644
index 0000000..6b97c824
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/freshness.any.js
@@ -0,0 +1,215 @@
+// META: global=window,worker
+// META: title=HTTP Cache - Freshness
+// META: timeout=long
+// META: script=/common/utils.js
+// META: script=/common/get-host-info.sub.js
+// META: script=http-cache.js
+
+var tests = [
+  // response directives
+  {
+    name: "HTTP cache reuses a response with a future Expires",
+    requests: [
+      {
+        response_headers: [
+          ["Expires", (30 * 24 * 60 * 60)]
+        ]
+      },
+      {
+        expected_type: "cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache does not reuse a response with a past Expires",
+    requests: [
+      {
+        response_headers: [
+          ["Expires", (-30 * 24 * 60 * 60)]
+        ]
+      },
+      {
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache does not reuse a response with a present Expires",
+    requests: [
+      {
+        response_headers: [
+          ["Expires", 0]
+        ]
+      },
+      {
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache does not reuse a response with an invalid Expires",
+    requests: [
+      {
+        response_headers: [
+          ["Expires", "0"]
+        ]
+      },
+      {
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache reuses a response with positive Cache-Control: max-age",
+    requests: [
+      {
+        response_headers: [
+          ["Cache-Control", "max-age=3600"]
+        ]
+      },
+      {
+        expected_type: "cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache does not reuse a response with Cache-Control: max-age=0",
+    requests: [
+      {
+        response_headers: [
+          ["Cache-Control", "max-age=0"]
+        ]
+      },
+      {
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache reuses a response with positive Cache-Control: max-age and a past Expires",
+    requests: [
+      {
+        response_headers: [
+          ["Cache-Control", "max-age=3600"],
+          ["Expires", -10000]
+        ]
+      },
+      {
+        expected_type: "cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache reuses a response with positive Cache-Control: max-age and an invalid Expires",
+    requests: [
+      {
+        response_headers: [
+          ["Cache-Control", "max-age=3600"],
+          ["Expires", "0"]
+        ]
+      },
+      {
+        expected_type: "cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache does not reuse a response with Cache-Control: max-age=0 and a future Expires",
+    requests: [
+      {
+        response_headers: [
+          ["Cache-Control", "max-age=0"],
+          ["Expires", 10000]
+        ]
+      },
+      {
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache does not prefer Cache-Control: s-maxage over Cache-Control: max-age",
+    requests: [
+      {
+        response_headers: [
+          ["Cache-Control", "max-age=1, s-maxage=3600"]
+        ],
+        pause_after: true,
+      },
+      {
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache does not reuse a response when the Age header is greater than its freshness lifetime",
+    requests: [
+      {
+        response_headers: [
+          ["Cache-Control", "max-age=3600"],
+          ["Age", "12000"]
+        ],
+      },
+      {
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache does not store a response with Cache-Control: no-store",
+    requests: [
+      {
+        response_headers: [
+          ["Cache-Control", "no-store"]
+        ]
+      },
+      {
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache does not store a response with Cache-Control: no-store, even with max-age and Expires",
+    requests: [
+      {
+        response_headers: [
+          ["Cache-Control", "max-age=10000, no-store"],
+          ["Expires", 10000]
+        ]
+      },
+      {
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache stores a response with Cache-Control: no-cache, but revalidates upon use",
+    requests: [
+      {
+        response_headers: [
+          ["Cache-Control", "no-cache"],
+          ["ETag", "abcd"]
+        ]
+      },
+      {
+        expected_type: "etag_validated"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache stores a response with Cache-Control: no-cache, but revalidates upon use, even with max-age and Expires",
+    requests: [
+      {
+        response_headers: [
+          ["Cache-Control", "max-age=10000, no-cache"],
+          ["Expires", 10000],
+          ["ETag", "abcd"]
+        ]
+      },
+      {
+        expected_type: "etag_validated"
+      }
+    ]
+  },
+];
+run_tests(tests);
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/freshness.html b/third_party/blink/web_tests/external/wpt/fetch/http-cache/freshness.html
deleted file mode 100644
index 38a457c..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/http-cache/freshness.html
+++ /dev/null
@@ -1,226 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>HTTP Cache - Freshness</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#request">
-    <meta name="timeout" content="long">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <script src="/common/utils.js"></script>
-    <script src="/common/get-host-info.sub.js"></script>
-    <script src="http-cache.js"></script>
-  </head>
-  <body>
-    <script>
-    var tests = [
-      // response directives
-      {
-        name: "HTTP cache reuses a response with a future Expires",
-        requests: [
-          {
-            response_headers: [
-              ["Expires", (30 * 24 * 60 * 60)]
-            ]
-          },
-          {
-            expected_type: "cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache does not reuse a response with a past Expires",
-        requests: [
-          {
-            response_headers: [
-              ["Expires", (-30 * 24 * 60 * 60)]
-            ]
-          },
-          {
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache does not reuse a response with a present Expires",
-        requests: [
-          {
-            response_headers: [
-              ["Expires", 0]
-            ]
-          },
-          {
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache does not reuse a response with an invalid Expires",
-        requests: [
-          {
-            response_headers: [
-              ["Expires", "0"]
-            ]
-          },
-          {
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache reuses a response with positive Cache-Control: max-age",
-        requests: [
-          {
-            response_headers: [
-              ["Cache-Control", "max-age=3600"]
-            ]
-          },
-          {
-            expected_type: "cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache does not reuse a response with Cache-Control: max-age=0",
-        requests: [
-          {
-            response_headers: [
-              ["Cache-Control", "max-age=0"]
-            ]
-          },
-          {
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache reuses a response with positive Cache-Control: max-age and a past Expires",
-        requests: [
-          {
-            response_headers: [
-              ["Cache-Control", "max-age=3600"],
-              ["Expires", -10000]
-            ]
-          },
-          {
-            expected_type: "cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache reuses a response with positive Cache-Control: max-age and an invalid Expires",
-        requests: [
-          {
-            response_headers: [
-              ["Cache-Control", "max-age=3600"],
-              ["Expires", "0"]
-            ]
-          },
-          {
-            expected_type: "cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache does not reuse a response with Cache-Control: max-age=0 and a future Expires",
-        requests: [
-          {
-            response_headers: [
-              ["Cache-Control", "max-age=0"],
-              ["Expires", 10000]
-            ]
-          },
-          {
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache does not prefer Cache-Control: s-maxage over Cache-Control: max-age",
-        requests: [
-          {
-            response_headers: [
-              ["Cache-Control", "max-age=1, s-maxage=3600"]
-            ],
-            pause_after: true,
-          },
-          {
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache does not reuse a response when the Age header is greater than its freshness lifetime",
-        requests: [
-          {
-            response_headers: [
-              ["Cache-Control", "max-age=3600"],
-              ["Age", "12000"]
-            ],
-          },
-          {
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache does not store a response with Cache-Control: no-store",
-        requests: [
-          {
-            response_headers: [
-              ["Cache-Control", "no-store"]
-            ]
-          },
-          {
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache does not store a response with Cache-Control: no-store, even with max-age and Expires",
-        requests: [
-          {
-            response_headers: [
-              ["Cache-Control", "max-age=10000, no-store"],
-              ["Expires", 10000]
-            ]
-          },
-          {
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache stores a response with Cache-Control: no-cache, but revalidates upon use",
-        requests: [
-          {
-            response_headers: [
-              ["Cache-Control", "no-cache"],
-              ["ETag", "abcd"]
-            ]
-          },
-          {
-            expected_type: "etag_validated"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache stores a response with Cache-Control: no-cache, but revalidates upon use, even with max-age and Expires",
-        requests: [
-          {
-            response_headers: [
-              ["Cache-Control", "max-age=10000, no-cache"],
-              ["Expires", 10000],
-              ["ETag", "abcd"]
-            ]
-          },
-          {
-            expected_type: "etag_validated"
-          }
-        ]
-      },
-    ];
-    run_tests(tests);
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/heuristic.any-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/http-cache/heuristic.any-expected.txt
new file mode 100644
index 0000000..e319502
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/heuristic.any-expected.txt
@@ -0,0 +1,19 @@
+This is a testharness.js-based test.
+FAIL HTTP cache reuses an unknown response with Last-Modified based upon heuristic freshness when Cache-Control: public is present assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+PASS HTTP cache does not reuse an unknown response with Last-Modified based upon heuristic freshness when Cache-Control: public is not present
+PASS HTTP cache reuses a 200 OK response with Last-Modified based upon heuristic freshness
+PASS HTTP cache reuses a 203 Non-Authoritative Information response with Last-Modified based upon heuristic freshness
+FAIL HTTP cache reuses a 204 No Content response with Last-Modified based upon heuristic freshness assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache reuses a 404 Not Found response with Last-Modified based upon heuristic freshness assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache reuses a 405 Method Not Allowed response with Last-Modified based upon heuristic freshness assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+PASS HTTP cache reuses a 410 Gone response with Last-Modified based upon heuristic freshness
+FAIL HTTP cache reuses a 414 URI Too Long response with Last-Modified based upon heuristic freshness assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache reuses a 501 Not Implemented response with Last-Modified based upon heuristic freshness assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+PASS HTTP cache does not use a 201 Created response with Last-Modified based upon heuristic freshness
+PASS HTTP cache does not use a 202 Accepted response with Last-Modified based upon heuristic freshness
+PASS HTTP cache does not use a 403 Forbidden response with Last-Modified based upon heuristic freshness
+PASS HTTP cache does not use a 502 Bad Gateway response with Last-Modified based upon heuristic freshness
+PASS HTTP cache does not use a 503 Service Unavailable response with Last-Modified based upon heuristic freshness
+PASS HTTP cache does not use a 504 Gateway Timeout response with Last-Modified based upon heuristic freshness
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/heuristic.any.js b/third_party/blink/web_tests/external/wpt/fetch/http-cache/heuristic.any.js
new file mode 100644
index 0000000..d846131
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/heuristic.any.js
@@ -0,0 +1,93 @@
+// META: global=window,worker
+// META: title=HTTP Cache - Heuristic Freshness
+// META: timeout=long
+// META: script=/common/utils.js
+// META: script=/common/get-host-info.sub.js
+// META: script=http-cache.js
+
+var tests = [
+  {
+    name: "HTTP cache reuses an unknown response with Last-Modified based upon heuristic freshness when Cache-Control: public is present",
+    requests: [
+      {
+        response_status: [299, "Whatever"],
+        response_headers: [
+          ["Last-Modified", (-3 * 100)],
+          ["Cache-Control", "public"]
+        ],
+      },
+      {
+        expected_type: "cached",
+        response_status: [299, "Whatever"]
+      }
+    ]
+  },
+  {
+    name: "HTTP cache does not reuse an unknown response with Last-Modified based upon heuristic freshness when Cache-Control: public is not present",
+    requests: [
+      {
+        response_status: [299, "Whatever"],
+        response_headers: [
+          ["Last-Modified", (-3 * 100)]
+        ],
+      },
+      {
+        expected_type: "not_cached"
+      }
+    ]
+  }
+];
+
+function check_status(status) {
+  var succeed = status[0];
+  var code = status[1];
+  var phrase = status[2];
+  var body = status[3];
+  if (body === undefined) {
+    body = http_content(code);
+  }
+  var expected_type = "not_cached";
+  var desired = "does not use"
+  if (succeed === true) {
+    expected_type = "cached";
+    desired = "reuses";
+  }
+  tests.push(
+    {
+      name: "HTTP cache " + desired + " a " + code + " " + phrase + " response with Last-Modified based upon heuristic freshness",
+      requests: [
+        {
+          response_status: [code, phrase],
+          response_headers: [
+            ["Last-Modified", (-3 * 100)]
+          ],
+          response_body: body
+        },
+        {
+          expected_type: expected_type,
+          response_status: [code, phrase],
+          response_body: body
+        }
+      ]
+    }
+  )
+}
+[
+  [true, 200, "OK"],
+  [true, 203, "Non-Authoritative Information"],
+  [true, 204, "No Content", ""],
+  [true, 404, "Not Found"],
+  [true, 405, "Method Not Allowed"],
+  [true, 410, "Gone"],
+  [true, 414, "URI Too Long"],
+  [true, 501, "Not Implemented"]
+].forEach(check_status);
+[
+  [false, 201, "Created"],
+  [false, 202, "Accepted"],
+  [false, 403, "Forbidden"],
+  [false, 502, "Bad Gateway"],
+  [false, 503, "Service Unavailable"],
+  [false, 504, "Gateway Timeout"],
+].forEach(check_status);
+run_tests(tests);
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/heuristic.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/http-cache/heuristic.any.serviceworker-expected.txt
new file mode 100644
index 0000000..e319502
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/heuristic.any.serviceworker-expected.txt
@@ -0,0 +1,19 @@
+This is a testharness.js-based test.
+FAIL HTTP cache reuses an unknown response with Last-Modified based upon heuristic freshness when Cache-Control: public is present assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+PASS HTTP cache does not reuse an unknown response with Last-Modified based upon heuristic freshness when Cache-Control: public is not present
+PASS HTTP cache reuses a 200 OK response with Last-Modified based upon heuristic freshness
+PASS HTTP cache reuses a 203 Non-Authoritative Information response with Last-Modified based upon heuristic freshness
+FAIL HTTP cache reuses a 204 No Content response with Last-Modified based upon heuristic freshness assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache reuses a 404 Not Found response with Last-Modified based upon heuristic freshness assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache reuses a 405 Method Not Allowed response with Last-Modified based upon heuristic freshness assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+PASS HTTP cache reuses a 410 Gone response with Last-Modified based upon heuristic freshness
+FAIL HTTP cache reuses a 414 URI Too Long response with Last-Modified based upon heuristic freshness assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache reuses a 501 Not Implemented response with Last-Modified based upon heuristic freshness assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+PASS HTTP cache does not use a 201 Created response with Last-Modified based upon heuristic freshness
+PASS HTTP cache does not use a 202 Accepted response with Last-Modified based upon heuristic freshness
+PASS HTTP cache does not use a 403 Forbidden response with Last-Modified based upon heuristic freshness
+PASS HTTP cache does not use a 502 Bad Gateway response with Last-Modified based upon heuristic freshness
+PASS HTTP cache does not use a 503 Service Unavailable response with Last-Modified based upon heuristic freshness
+PASS HTTP cache does not use a 504 Gateway Timeout response with Last-Modified based upon heuristic freshness
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/heuristic.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/http-cache/heuristic.any.sharedworker-expected.txt
new file mode 100644
index 0000000..e319502
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/heuristic.any.sharedworker-expected.txt
@@ -0,0 +1,19 @@
+This is a testharness.js-based test.
+FAIL HTTP cache reuses an unknown response with Last-Modified based upon heuristic freshness when Cache-Control: public is present assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+PASS HTTP cache does not reuse an unknown response with Last-Modified based upon heuristic freshness when Cache-Control: public is not present
+PASS HTTP cache reuses a 200 OK response with Last-Modified based upon heuristic freshness
+PASS HTTP cache reuses a 203 Non-Authoritative Information response with Last-Modified based upon heuristic freshness
+FAIL HTTP cache reuses a 204 No Content response with Last-Modified based upon heuristic freshness assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache reuses a 404 Not Found response with Last-Modified based upon heuristic freshness assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache reuses a 405 Method Not Allowed response with Last-Modified based upon heuristic freshness assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+PASS HTTP cache reuses a 410 Gone response with Last-Modified based upon heuristic freshness
+FAIL HTTP cache reuses a 414 URI Too Long response with Last-Modified based upon heuristic freshness assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache reuses a 501 Not Implemented response with Last-Modified based upon heuristic freshness assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+PASS HTTP cache does not use a 201 Created response with Last-Modified based upon heuristic freshness
+PASS HTTP cache does not use a 202 Accepted response with Last-Modified based upon heuristic freshness
+PASS HTTP cache does not use a 403 Forbidden response with Last-Modified based upon heuristic freshness
+PASS HTTP cache does not use a 502 Bad Gateway response with Last-Modified based upon heuristic freshness
+PASS HTTP cache does not use a 503 Service Unavailable response with Last-Modified based upon heuristic freshness
+PASS HTTP cache does not use a 504 Gateway Timeout response with Last-Modified based upon heuristic freshness
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/heuristic.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/http-cache/heuristic.any.worker-expected.txt
new file mode 100644
index 0000000..e319502
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/heuristic.any.worker-expected.txt
@@ -0,0 +1,19 @@
+This is a testharness.js-based test.
+FAIL HTTP cache reuses an unknown response with Last-Modified based upon heuristic freshness when Cache-Control: public is present assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+PASS HTTP cache does not reuse an unknown response with Last-Modified based upon heuristic freshness when Cache-Control: public is not present
+PASS HTTP cache reuses a 200 OK response with Last-Modified based upon heuristic freshness
+PASS HTTP cache reuses a 203 Non-Authoritative Information response with Last-Modified based upon heuristic freshness
+FAIL HTTP cache reuses a 204 No Content response with Last-Modified based upon heuristic freshness assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache reuses a 404 Not Found response with Last-Modified based upon heuristic freshness assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache reuses a 405 Method Not Allowed response with Last-Modified based upon heuristic freshness assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+PASS HTTP cache reuses a 410 Gone response with Last-Modified based upon heuristic freshness
+FAIL HTTP cache reuses a 414 URI Too Long response with Last-Modified based upon heuristic freshness assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache reuses a 501 Not Implemented response with Last-Modified based upon heuristic freshness assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+PASS HTTP cache does not use a 201 Created response with Last-Modified based upon heuristic freshness
+PASS HTTP cache does not use a 202 Accepted response with Last-Modified based upon heuristic freshness
+PASS HTTP cache does not use a 403 Forbidden response with Last-Modified based upon heuristic freshness
+PASS HTTP cache does not use a 502 Bad Gateway response with Last-Modified based upon heuristic freshness
+PASS HTTP cache does not use a 503 Service Unavailable response with Last-Modified based upon heuristic freshness
+PASS HTTP cache does not use a 504 Gateway Timeout response with Last-Modified based upon heuristic freshness
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/heuristic.html b/third_party/blink/web_tests/external/wpt/fetch/http-cache/heuristic.html
deleted file mode 100644
index c2333cd..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/http-cache/heuristic.html
+++ /dev/null
@@ -1,104 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>HTTP Cache - Heuristic Freshness</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#request">
-    <meta name="timeout" content="long">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <script src="/common/utils.js"></script>
-    <script src="/common/get-host-info.sub.js"></script>
-    <script src="http-cache.js"></script>
-  </head>
-  <body>
-    <script>
-    var tests = [
-      {
-        name: "HTTP cache reuses an unknown response with Last-Modified based upon heuristic freshness when Cache-Control: public is present",
-        requests: [
-          {
-            response_status: [299, "Whatever"],
-            response_headers: [
-              ["Last-Modified", (-3 * 100)],
-              ["Cache-Control", "public"]
-            ],
-          },
-          {
-            expected_type: "cached",
-            response_status: [299, "Whatever"]
-          }
-        ]
-      },
-      {
-        name: "HTTP cache does not reuse an unknown response with Last-Modified based upon heuristic freshness when Cache-Control: public is not present",
-        requests: [
-          {
-            response_status: [299, "Whatever"],
-            response_headers: [
-              ["Last-Modified", (-3 * 100)]
-            ],
-          },
-          {
-            expected_type: "not_cached"
-          }
-        ]
-      }
-    ];
-
-    function check_status(status) {
-      var succeed = status[0];
-      var code = status[1];
-      var phrase = status[2];
-      var body = status[3];
-      if (body === undefined) {
-        body = http_content(code);
-      }
-      var expected_type = "not_cached";
-      var desired = "does not use"
-      if (succeed === true) {
-        expected_type = "cached";
-        desired = "reuses";
-      }
-      tests.push(
-        {
-          name: "HTTP cache " + desired + " a " + code + " " + phrase + " response with Last-Modified based upon heuristic freshness",
-          requests: [
-            {
-              response_status: [code, phrase],
-              response_headers: [
-                ["Last-Modified", (-3 * 100)]
-              ],
-              response_body: body
-            },
-            {
-              expected_type: expected_type,
-              response_status: [code, phrase],
-              response_body: body
-            }
-          ]
-        }
-      )
-    }
-    [
-      [true, 200, "OK"],
-      [true, 203, "Non-Authoritative Information"],
-      [true, 204, "No Content", ""],
-      [true, 404, "Not Found"],
-      [true, 405, "Method Not Allowed"],
-      [true, 410, "Gone"],
-      [true, 414, "URI Too Long"],
-      [true, 501, "Not Implemented"]
-    ].forEach(check_status);
-    [
-      [false, 201, "Created"],
-      [false, 202, "Accepted"],
-      [false, 403, "Forbidden"],
-      [false, 502, "Bad Gateway"],
-      [false, 503, "Service Unavailable"],
-      [false, 504, "Gateway Timeout"],
-    ].forEach(check_status);
-    run_tests(tests);
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/invalidate.any-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/http-cache/invalidate.any-expected.txt
new file mode 100644
index 0000000..9f29bc5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/invalidate.any-expected.txt
@@ -0,0 +1,18 @@
+This is a testharness.js-based test.
+PASS HTTP cache invalidates after a successful response from a POST
+PASS HTTP cache does not invalidate after a failed response from an unsafe request
+PASS HTTP cache invalidates after a successful response from a PUT
+PASS HTTP cache invalidates after a successful response from a DELETE
+FAIL HTTP cache invalidates after a successful response from an unknown method assert_equals: Response 3 comes from cache expected 3 but got 1
+FAIL HTTP cache invalidates Location URL after a successful response from a POST assert_equals: Response 3 comes from cache expected 3 but got 1
+PASS HTTP cache does not invalidate Location URL after a failed response from an unsafe request
+FAIL HTTP cache invalidates Location URL after a successful response from a PUT assert_equals: Response 3 comes from cache expected 3 but got 1
+FAIL HTTP cache invalidates Location URL after a successful response from a DELETE assert_equals: Response 3 comes from cache expected 3 but got 1
+FAIL HTTP cache invalidates Location URL after a successful response from an unknown method assert_equals: Response 3 comes from cache expected 3 but got 1
+FAIL HTTP cache invalidates Content-Location URL after a successful response from a POST assert_equals: Response 3 comes from cache expected 3 but got 1
+PASS HTTP cache does not invalidate Content-Location URL after a failed response from an unsafe request
+FAIL HTTP cache invalidates Content-Location URL after a successful response from a PUT assert_equals: Response 3 comes from cache expected 3 but got 1
+FAIL HTTP cache invalidates Content-Location URL after a successful response from a DELETE assert_equals: Response 3 comes from cache expected 3 but got 1
+FAIL HTTP cache invalidates Content-Location URL after a successful response from an unknown method assert_equals: Response 3 comes from cache expected 3 but got 1
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/invalidate.any.js b/third_party/blink/web_tests/external/wpt/fetch/http-cache/invalidate.any.js
new file mode 100644
index 0000000..9f8090a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/invalidate.any.js
@@ -0,0 +1,235 @@
+// META: global=window,worker
+// META: title=HTTP Cache - Invalidation
+// META: timeout=long
+// META: script=/common/utils.js
+// META: script=/common/get-host-info.sub.js
+// META: script=http-cache.js
+
+var tests = [
+  {
+    name: 'HTTP cache invalidates after a successful response from a POST',
+    requests: [
+      {
+        template: "fresh"
+      }, {
+        request_method: "POST",
+        request_body: "abc"
+      }, {
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: 'HTTP cache does not invalidate after a failed response from an unsafe request',
+    requests: [
+      {
+        template: "fresh"
+      }, {
+        request_method: "POST",
+        request_body: "abc",
+        response_status: [500, "Internal Server Error"]
+      }, {
+        expected_type: "cached"
+      }
+    ]
+  },
+  {
+    name: 'HTTP cache invalidates after a successful response from a PUT',
+    requests: [
+      {
+        template: "fresh"
+      }, {
+        template: "fresh",
+        request_method: "PUT",
+        request_body: "abc"
+      }, {
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: 'HTTP cache invalidates after a successful response from a DELETE',
+    requests: [
+      {
+        template: "fresh"
+      }, {
+        request_method: "DELETE",
+        request_body: "abc"
+      }, {
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: 'HTTP cache invalidates after a successful response from an unknown method',
+    requests: [
+      {
+        template: "fresh"
+      }, {
+        request_method: "FOO",
+        request_body: "abc"
+      }, {
+        expected_type: "not_cached"
+      }
+    ]
+  },
+
+
+  {
+    name: 'HTTP cache invalidates Location URL after a successful response from a POST',
+    requests: [
+      {
+        template: "location"
+      }, {
+        request_method: "POST",
+        request_body: "abc",
+        template: "lcl_response"
+      }, {
+        template: "location",
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: 'HTTP cache does not invalidate Location URL after a failed response from an unsafe request',
+    requests: [
+      {
+        template: "location"
+      }, {
+        template: "lcl_response",
+        request_method: "POST",
+        request_body: "abc",
+        response_status: [500, "Internal Server Error"]
+      }, {
+        template: "location",
+        expected_type: "cached"
+      }
+    ]
+  },
+  {
+    name: 'HTTP cache invalidates Location URL after a successful response from a PUT',
+    requests: [
+      {
+        template: "location"
+      }, {
+        template: "lcl_response",
+        request_method: "PUT",
+        request_body: "abc"
+      }, {
+        template: "location",
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: 'HTTP cache invalidates Location URL after a successful response from a DELETE',
+    requests: [
+      {
+        template: "location"
+      }, {
+        template: "lcl_response",
+        request_method: "DELETE",
+        request_body: "abc"
+      }, {
+        template: "location",
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: 'HTTP cache invalidates Location URL after a successful response from an unknown method',
+    requests: [
+      {
+        template: "location"
+      }, {
+        template: "lcl_response",
+        request_method: "FOO",
+        request_body: "abc"
+      }, {
+        template: "location",
+        expected_type: "not_cached"
+      }
+    ]
+  },
+
+
+
+  {
+    name: 'HTTP cache invalidates Content-Location URL after a successful response from a POST',
+    requests: [
+      {
+        template: "content_location"
+      }, {
+        request_method: "POST",
+        request_body: "abc",
+        template: "lcl_response"
+      }, {
+        template: "content_location",
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: 'HTTP cache does not invalidate Content-Location URL after a failed response from an unsafe request',
+    requests: [
+      {
+        template: "content_location"
+      }, {
+        template: "lcl_response",
+        request_method: "POST",
+        request_body: "abc",
+        response_status: [500, "Internal Server Error"]
+      }, {
+        template: "content_location",
+        expected_type: "cached"
+      }
+    ]
+  },
+  {
+    name: 'HTTP cache invalidates Content-Location URL after a successful response from a PUT',
+    requests: [
+      {
+        template: "content_location"
+      }, {
+        template: "lcl_response",
+        request_method: "PUT",
+        request_body: "abc"
+      }, {
+        template: "content_location",
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: 'HTTP cache invalidates Content-Location URL after a successful response from a DELETE',
+    requests: [
+      {
+        template: "content_location"
+      }, {
+        template: "lcl_response",
+        request_method: "DELETE",
+        request_body: "abc"
+      }, {
+        template: "content_location",
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: 'HTTP cache invalidates Content-Location URL after a successful response from an unknown method',
+    requests: [
+      {
+        template: "content_location"
+      }, {
+        template: "lcl_response",
+        request_method: "FOO",
+        request_body: "abc"
+      }, {
+        template: "content_location",
+        expected_type: "not_cached"
+      }
+    ]
+  }
+
+];
+run_tests(tests);
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/invalidate.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/http-cache/invalidate.any.serviceworker-expected.txt
new file mode 100644
index 0000000..9f29bc5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/invalidate.any.serviceworker-expected.txt
@@ -0,0 +1,18 @@
+This is a testharness.js-based test.
+PASS HTTP cache invalidates after a successful response from a POST
+PASS HTTP cache does not invalidate after a failed response from an unsafe request
+PASS HTTP cache invalidates after a successful response from a PUT
+PASS HTTP cache invalidates after a successful response from a DELETE
+FAIL HTTP cache invalidates after a successful response from an unknown method assert_equals: Response 3 comes from cache expected 3 but got 1
+FAIL HTTP cache invalidates Location URL after a successful response from a POST assert_equals: Response 3 comes from cache expected 3 but got 1
+PASS HTTP cache does not invalidate Location URL after a failed response from an unsafe request
+FAIL HTTP cache invalidates Location URL after a successful response from a PUT assert_equals: Response 3 comes from cache expected 3 but got 1
+FAIL HTTP cache invalidates Location URL after a successful response from a DELETE assert_equals: Response 3 comes from cache expected 3 but got 1
+FAIL HTTP cache invalidates Location URL after a successful response from an unknown method assert_equals: Response 3 comes from cache expected 3 but got 1
+FAIL HTTP cache invalidates Content-Location URL after a successful response from a POST assert_equals: Response 3 comes from cache expected 3 but got 1
+PASS HTTP cache does not invalidate Content-Location URL after a failed response from an unsafe request
+FAIL HTTP cache invalidates Content-Location URL after a successful response from a PUT assert_equals: Response 3 comes from cache expected 3 but got 1
+FAIL HTTP cache invalidates Content-Location URL after a successful response from a DELETE assert_equals: Response 3 comes from cache expected 3 but got 1
+FAIL HTTP cache invalidates Content-Location URL after a successful response from an unknown method assert_equals: Response 3 comes from cache expected 3 but got 1
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/invalidate.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/http-cache/invalidate.any.sharedworker-expected.txt
new file mode 100644
index 0000000..9f29bc5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/invalidate.any.sharedworker-expected.txt
@@ -0,0 +1,18 @@
+This is a testharness.js-based test.
+PASS HTTP cache invalidates after a successful response from a POST
+PASS HTTP cache does not invalidate after a failed response from an unsafe request
+PASS HTTP cache invalidates after a successful response from a PUT
+PASS HTTP cache invalidates after a successful response from a DELETE
+FAIL HTTP cache invalidates after a successful response from an unknown method assert_equals: Response 3 comes from cache expected 3 but got 1
+FAIL HTTP cache invalidates Location URL after a successful response from a POST assert_equals: Response 3 comes from cache expected 3 but got 1
+PASS HTTP cache does not invalidate Location URL after a failed response from an unsafe request
+FAIL HTTP cache invalidates Location URL after a successful response from a PUT assert_equals: Response 3 comes from cache expected 3 but got 1
+FAIL HTTP cache invalidates Location URL after a successful response from a DELETE assert_equals: Response 3 comes from cache expected 3 but got 1
+FAIL HTTP cache invalidates Location URL after a successful response from an unknown method assert_equals: Response 3 comes from cache expected 3 but got 1
+FAIL HTTP cache invalidates Content-Location URL after a successful response from a POST assert_equals: Response 3 comes from cache expected 3 but got 1
+PASS HTTP cache does not invalidate Content-Location URL after a failed response from an unsafe request
+FAIL HTTP cache invalidates Content-Location URL after a successful response from a PUT assert_equals: Response 3 comes from cache expected 3 but got 1
+FAIL HTTP cache invalidates Content-Location URL after a successful response from a DELETE assert_equals: Response 3 comes from cache expected 3 but got 1
+FAIL HTTP cache invalidates Content-Location URL after a successful response from an unknown method assert_equals: Response 3 comes from cache expected 3 but got 1
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/invalidate.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/http-cache/invalidate.any.worker-expected.txt
new file mode 100644
index 0000000..9f29bc5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/invalidate.any.worker-expected.txt
@@ -0,0 +1,18 @@
+This is a testharness.js-based test.
+PASS HTTP cache invalidates after a successful response from a POST
+PASS HTTP cache does not invalidate after a failed response from an unsafe request
+PASS HTTP cache invalidates after a successful response from a PUT
+PASS HTTP cache invalidates after a successful response from a DELETE
+FAIL HTTP cache invalidates after a successful response from an unknown method assert_equals: Response 3 comes from cache expected 3 but got 1
+FAIL HTTP cache invalidates Location URL after a successful response from a POST assert_equals: Response 3 comes from cache expected 3 but got 1
+PASS HTTP cache does not invalidate Location URL after a failed response from an unsafe request
+FAIL HTTP cache invalidates Location URL after a successful response from a PUT assert_equals: Response 3 comes from cache expected 3 but got 1
+FAIL HTTP cache invalidates Location URL after a successful response from a DELETE assert_equals: Response 3 comes from cache expected 3 but got 1
+FAIL HTTP cache invalidates Location URL after a successful response from an unknown method assert_equals: Response 3 comes from cache expected 3 but got 1
+FAIL HTTP cache invalidates Content-Location URL after a successful response from a POST assert_equals: Response 3 comes from cache expected 3 but got 1
+PASS HTTP cache does not invalidate Content-Location URL after a failed response from an unsafe request
+FAIL HTTP cache invalidates Content-Location URL after a successful response from a PUT assert_equals: Response 3 comes from cache expected 3 but got 1
+FAIL HTTP cache invalidates Content-Location URL after a successful response from a DELETE assert_equals: Response 3 comes from cache expected 3 but got 1
+FAIL HTTP cache invalidates Content-Location URL after a successful response from an unknown method assert_equals: Response 3 comes from cache expected 3 but got 1
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/invalidate.html b/third_party/blink/web_tests/external/wpt/fetch/http-cache/invalidate.html
deleted file mode 100644
index dbf727c..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/http-cache/invalidate.html
+++ /dev/null
@@ -1,246 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>HTTP Cache - Invalidation</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#request">
-    <meta name="timeout" content="long">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <script src="/common/utils.js"></script>
-    <script src="/common/get-host-info.sub.js"></script>
-    <script src="http-cache.js"></script>
-  </head>
-  <body>
-    <script>
-    var tests = [
-      {
-        name: 'HTTP cache invalidates after a successful response from a POST',
-        requests: [
-          {
-            template: "fresh"
-          }, {
-            request_method: "POST",
-            request_body: "abc"
-          }, {
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: 'HTTP cache does not invalidate after a failed response from an unsafe request',
-        requests: [
-          {
-            template: "fresh"
-          }, {
-            request_method: "POST",
-            request_body: "abc",
-            response_status: [500, "Internal Server Error"]
-          }, {
-            expected_type: "cached"
-          }
-        ]
-      },
-      {
-        name: 'HTTP cache invalidates after a successful response from a PUT',
-        requests: [
-          {
-            template: "fresh"
-          }, {
-            template: "fresh",
-            request_method: "PUT",
-            request_body: "abc"
-          }, {
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: 'HTTP cache invalidates after a successful response from a DELETE',
-        requests: [
-          {
-            template: "fresh"
-          }, {
-            request_method: "DELETE",
-            request_body: "abc"
-          }, {
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: 'HTTP cache invalidates after a successful response from an unknown method',
-        requests: [
-          {
-            template: "fresh"
-          }, {
-            request_method: "FOO",
-            request_body: "abc"
-          }, {
-            expected_type: "not_cached"
-          }
-        ]
-      },
-
-
-      {
-        name: 'HTTP cache invalidates Location URL after a successful response from a POST',
-        requests: [
-          {
-            template: "location"
-          }, {
-            request_method: "POST",
-            request_body: "abc",
-            template: "lcl_response"
-          }, {
-            template: "location",
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: 'HTTP cache does not invalidate Location URL after a failed response from an unsafe request',
-        requests: [
-          {
-            template: "location"
-          }, {
-            template: "lcl_response",
-            request_method: "POST",
-            request_body: "abc",
-            response_status: [500, "Internal Server Error"]
-          }, {
-            template: "location",
-            expected_type: "cached"
-          }
-        ]
-      },
-      {
-        name: 'HTTP cache invalidates Location URL after a successful response from a PUT',
-        requests: [
-          {
-            template: "location"
-          }, {
-            template: "lcl_response",
-            request_method: "PUT",
-            request_body: "abc"
-          }, {
-            template: "location",
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: 'HTTP cache invalidates Location URL after a successful response from a DELETE',
-        requests: [
-          {
-            template: "location"
-          }, {
-            template: "lcl_response",
-            request_method: "DELETE",
-            request_body: "abc"
-          }, {
-            template: "location",
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: 'HTTP cache invalidates Location URL after a successful response from an unknown method',
-        requests: [
-          {
-            template: "location"
-          }, {
-            template: "lcl_response",
-            request_method: "FOO",
-            request_body: "abc"
-          }, {
-            template: "location",
-            expected_type: "not_cached"
-          }
-        ]
-      },
-
-
-
-      {
-        name: 'HTTP cache invalidates Content-Location URL after a successful response from a POST',
-        requests: [
-          {
-            template: "content_location"
-          }, {
-            request_method: "POST",
-            request_body: "abc",
-            template: "lcl_response"
-          }, {
-            template: "content_location",
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: 'HTTP cache does not invalidate Content-Location URL after a failed response from an unsafe request',
-        requests: [
-          {
-            template: "content_location"
-          }, {
-            template: "lcl_response",
-            request_method: "POST",
-            request_body: "abc",
-            response_status: [500, "Internal Server Error"]
-          }, {
-            template: "content_location",
-            expected_type: "cached"
-          }
-        ]
-      },
-      {
-        name: 'HTTP cache invalidates Content-Location URL after a successful response from a PUT',
-        requests: [
-          {
-            template: "content_location"
-          }, {
-            template: "lcl_response",
-            request_method: "PUT",
-            request_body: "abc"
-          }, {
-            template: "content_location",
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: 'HTTP cache invalidates Content-Location URL after a successful response from a DELETE',
-        requests: [
-          {
-            template: "content_location"
-          }, {
-            template: "lcl_response",
-            request_method: "DELETE",
-            request_body: "abc"
-          }, {
-            template: "content_location",
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: 'HTTP cache invalidates Content-Location URL after a successful response from an unknown method',
-        requests: [
-          {
-            template: "content_location"
-          }, {
-            template: "lcl_response",
-            request_method: "FOO",
-            request_body: "abc"
-          }, {
-            template: "content_location",
-            expected_type: "not_cached"
-          }
-        ]
-      }
-
-    ];
-    run_tests(tests);
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/partial.any-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/http-cache/partial.any-expected.txt
new file mode 100644
index 0000000..759cb5d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/partial.any-expected.txt
@@ -0,0 +1,11 @@
+This is a testharness.js-based test.
+FAIL HTTP cache stores partial content and reuses it assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+PASS HTTP cache stores complete response and serves smaller ranges from it (byte-range-spec)
+PASS HTTP cache stores complete response and serves smaller ranges from it (absent last-byte-pos)
+PASS HTTP cache stores complete response and serves smaller ranges from it (suffix-byte-range-spec)
+FAIL HTTP cache stores partial response and serves smaller ranges from it (byte-range-spec) assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache stores partial response and serves smaller ranges from it (absent last-byte-pos) assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache stores partial response and serves smaller ranges from it (suffix-byte-range-spec) assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache stores partial content and completes it assert_equals: request 2 header range value is "undefined", not "bytes=5-" expected (string) "bytes=5-" but got (undefined) undefined
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/partial.any.js b/third_party/blink/web_tests/external/wpt/fetch/http-cache/partial.any.js
new file mode 100644
index 0000000..a75b811
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/partial.any.js
@@ -0,0 +1,187 @@
+// META: global=window,worker
+// META: title=HTTP Cache - Partial Content
+// META: timeout=long
+// META: script=/common/utils.js
+// META: script=/common/get-host-info.sub.js
+// META: script=http-cache.js
+
+var tests = [
+  {
+    name: "HTTP cache stores partial content and reuses it",
+    requests: [
+      {
+        request_headers: [
+          ['Range', "bytes=-5"]
+        ],
+        response_status: [206, "Partial Content"],
+        response_headers: [
+          ["Cache-Control", "max-age=3600"],
+          ["Content-Range", "bytes 4-9/10"]
+        ],
+        response_body: "01234",
+        expected_request_headers: [
+          ["Range", "bytes=-5"]
+        ]
+      },
+      {
+        request_headers: [
+          ["Range", "bytes=-5"]
+        ],
+        expected_type: "cached",
+        expected_status: 206,
+        expected_response_text: "01234"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache stores complete response and serves smaller ranges from it (byte-range-spec)",
+    requests: [
+      {
+        response_headers: [
+          ["Cache-Control", "max-age=3600"]
+        ],
+        response_body: "01234567890"
+      },
+      {
+        request_headers: [
+          ['Range', "bytes=0-1"]
+        ],
+        expected_type: "cached",
+        expected_status: 206,
+        expected_response_text: "01"
+      },
+    ]
+  },
+  {
+    name: "HTTP cache stores complete response and serves smaller ranges from it (absent last-byte-pos)",
+    requests: [
+      {
+        response_headers: [
+          ["Cache-Control", "max-age=3600"],
+        ],
+        response_body: "01234567890"
+      },
+      {
+        request_headers: [
+          ['Range', "bytes=1-"]
+        ],
+        expected_type: "cached",
+        expected_status: 206,
+        expected_response_text: "1234567890"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache stores complete response and serves smaller ranges from it (suffix-byte-range-spec)",
+    requests: [
+      {
+        response_headers: [
+          ["Cache-Control", "max-age=3600"],
+        ],
+        response_body: "0123456789A"
+      },
+      {
+        request_headers: [
+          ['Range', "bytes=-1"]
+        ],
+        expected_type: "cached",
+        expected_status: 206,
+        expected_response_text: "A"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache stores partial response and serves smaller ranges from it (byte-range-spec)",
+    requests: [
+      {
+        request_headers: [
+          ['Range', "bytes=-5"]
+        ],
+        response_status: [206, "Partial Content"],
+        response_headers: [
+          ["Cache-Control", "max-age=3600"],
+          ["Content-Range", "bytes 4-9/10"]
+        ],
+        response_body: "01234"
+      },
+      {
+        request_headers: [
+          ['Range', "bytes=6-8"]
+        ],
+        expected_type: "cached",
+        expected_status: 206,
+        expected_response_text: "234"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache stores partial response and serves smaller ranges from it (absent last-byte-pos)",
+    requests: [
+      {
+        request_headers: [
+          ['Range', "bytes=-5"]
+        ],
+        response_status: [206, "Partial Content"],
+        response_headers: [
+          ["Cache-Control", "max-age=3600"],
+          ["Content-Range", "bytes 4-9/10"]
+        ],
+        response_body: "01234"
+      },
+      {
+        request_headers: [
+          ["Range", "bytes=6-"]
+        ],
+        expected_type: "cached",
+        expected_status: 206,
+        expected_response_text: "234"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache stores partial response and serves smaller ranges from it (suffix-byte-range-spec)",
+    requests: [
+      {
+        request_headers: [
+          ['Range', "bytes=-5"]
+        ],
+        response_status: [206, "Partial Content"],
+        response_headers: [
+          ["Cache-Control", "max-age=3600"],
+          ["Content-Range", "bytes 4-9/10"]
+        ],
+        response_body: "01234"
+      },
+      {
+        request_headers: [
+          ['Range', "bytes=-1"]
+        ],
+        expected_type: "cached",
+        expected_status: 206,
+        expected_response_text: "4"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache stores partial content and completes it",
+    requests: [
+      {
+        request_headers: [
+          ['Range', "bytes=-5"]
+        ],
+        response_status: [206, "Partial Content"],
+        response_headers: [
+          ["Cache-Control", "max-age=3600"],
+          ["Content-Range", "bytes 0-4/10"]
+        ],
+        response_body: "01234"
+      },
+      {
+        expected_request_headers: [
+          ["range", "bytes=5-"]
+        ]
+      }
+    ]
+  },
+];
+run_tests(tests);
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/partial.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/http-cache/partial.any.serviceworker-expected.txt
new file mode 100644
index 0000000..759cb5d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/partial.any.serviceworker-expected.txt
@@ -0,0 +1,11 @@
+This is a testharness.js-based test.
+FAIL HTTP cache stores partial content and reuses it assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+PASS HTTP cache stores complete response and serves smaller ranges from it (byte-range-spec)
+PASS HTTP cache stores complete response and serves smaller ranges from it (absent last-byte-pos)
+PASS HTTP cache stores complete response and serves smaller ranges from it (suffix-byte-range-spec)
+FAIL HTTP cache stores partial response and serves smaller ranges from it (byte-range-spec) assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache stores partial response and serves smaller ranges from it (absent last-byte-pos) assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache stores partial response and serves smaller ranges from it (suffix-byte-range-spec) assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache stores partial content and completes it assert_equals: request 2 header range value is "undefined", not "bytes=5-" expected (string) "bytes=5-" but got (undefined) undefined
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/partial.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/http-cache/partial.any.sharedworker-expected.txt
new file mode 100644
index 0000000..759cb5d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/partial.any.sharedworker-expected.txt
@@ -0,0 +1,11 @@
+This is a testharness.js-based test.
+FAIL HTTP cache stores partial content and reuses it assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+PASS HTTP cache stores complete response and serves smaller ranges from it (byte-range-spec)
+PASS HTTP cache stores complete response and serves smaller ranges from it (absent last-byte-pos)
+PASS HTTP cache stores complete response and serves smaller ranges from it (suffix-byte-range-spec)
+FAIL HTTP cache stores partial response and serves smaller ranges from it (byte-range-spec) assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache stores partial response and serves smaller ranges from it (absent last-byte-pos) assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache stores partial response and serves smaller ranges from it (suffix-byte-range-spec) assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache stores partial content and completes it assert_equals: request 2 header range value is "undefined", not "bytes=5-" expected (string) "bytes=5-" but got (undefined) undefined
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/partial.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/http-cache/partial.any.worker-expected.txt
new file mode 100644
index 0000000..759cb5d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/partial.any.worker-expected.txt
@@ -0,0 +1,11 @@
+This is a testharness.js-based test.
+FAIL HTTP cache stores partial content and reuses it assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+PASS HTTP cache stores complete response and serves smaller ranges from it (byte-range-spec)
+PASS HTTP cache stores complete response and serves smaller ranges from it (absent last-byte-pos)
+PASS HTTP cache stores complete response and serves smaller ranges from it (suffix-byte-range-spec)
+FAIL HTTP cache stores partial response and serves smaller ranges from it (byte-range-spec) assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache stores partial response and serves smaller ranges from it (absent last-byte-pos) assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache stores partial response and serves smaller ranges from it (suffix-byte-range-spec) assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache stores partial content and completes it assert_equals: request 2 header range value is "undefined", not "bytes=5-" expected (string) "bytes=5-" but got (undefined) undefined
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/partial.html b/third_party/blink/web_tests/external/wpt/fetch/http-cache/partial.html
deleted file mode 100644
index 8f0b528..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/http-cache/partial.html
+++ /dev/null
@@ -1,198 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>HTTP Cache - Partial Content</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#request">
-    <meta name="timeout" content="long">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <script src="/common/utils.js"></script>
-    <script src="/common/get-host-info.sub.js"></script>
-    <script src="http-cache.js"></script>
-  </head>
-  <body>
-    <script>
-    var tests = [
-      {
-        name: "HTTP cache stores partial content and reuses it",
-        requests: [
-          {
-            request_headers: [
-              ['Range', "bytes=-5"]
-            ],
-            response_status: [206, "Partial Content"],
-            response_headers: [
-              ["Cache-Control", "max-age=3600"],
-              ["Content-Range", "bytes 4-9/10"]
-            ],
-            response_body: "01234",
-            expected_request_headers: [
-              ["Range", "bytes=-5"]
-            ]
-          },
-          {
-            request_headers: [
-              ["Range", "bytes=-5"]
-            ],
-            expected_type: "cached",
-            expected_status: 206,
-            expected_response_text: "01234"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache stores complete response and serves smaller ranges from it (byte-range-spec)",
-        requests: [
-          {
-            response_headers: [
-              ["Cache-Control", "max-age=3600"]
-            ],
-            response_body: "01234567890"
-          },
-          {
-            request_headers: [
-              ['Range', "bytes=0-1"]
-            ],
-            expected_type: "cached",
-            expected_status: 206,
-            expected_response_text: "01"
-          },
-        ]
-      },
-      {
-        name: "HTTP cache stores complete response and serves smaller ranges from it (absent last-byte-pos)",
-        requests: [
-          {
-            response_headers: [
-              ["Cache-Control", "max-age=3600"],
-            ],
-            response_body: "01234567890"
-          },
-          {
-            request_headers: [
-              ['Range', "bytes=1-"]
-            ],
-            expected_type: "cached",
-            expected_status: 206,
-            expected_response_text: "1234567890"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache stores complete response and serves smaller ranges from it (suffix-byte-range-spec)",
-        requests: [
-          {
-            response_headers: [
-              ["Cache-Control", "max-age=3600"],
-            ],
-            response_body: "0123456789A"
-          },
-          {
-            request_headers: [
-              ['Range', "bytes=-1"]
-            ],
-            expected_type: "cached",
-            expected_status: 206,
-            expected_response_text: "A"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache stores partial response and serves smaller ranges from it (byte-range-spec)",
-        requests: [
-          {
-            request_headers: [
-              ['Range', "bytes=-5"]
-            ],
-            response_status: [206, "Partial Content"],
-            response_headers: [
-              ["Cache-Control", "max-age=3600"],
-              ["Content-Range", "bytes 4-9/10"]
-            ],
-            response_body: "01234"
-          },
-          {
-            request_headers: [
-              ['Range', "bytes=6-8"]
-            ],
-            expected_type: "cached",
-            expected_status: 206,
-            expected_response_text: "234"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache stores partial response and serves smaller ranges from it (absent last-byte-pos)",
-        requests: [
-          {
-            request_headers: [
-              ['Range', "bytes=-5"]
-            ],
-            response_status: [206, "Partial Content"],
-            response_headers: [
-              ["Cache-Control", "max-age=3600"],
-              ["Content-Range", "bytes 4-9/10"]
-            ],
-            response_body: "01234"
-          },
-          {
-            request_headers: [
-              ["Range", "bytes=6-"]
-            ],
-            expected_type: "cached",
-            expected_status: 206,
-            expected_response_text: "234"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache stores partial response and serves smaller ranges from it (suffix-byte-range-spec)",
-        requests: [
-          {
-            request_headers: [
-              ['Range', "bytes=-5"]
-            ],
-            response_status: [206, "Partial Content"],
-            response_headers: [
-              ["Cache-Control", "max-age=3600"],
-              ["Content-Range", "bytes 4-9/10"]
-            ],
-            response_body: "01234"
-          },
-          {
-            request_headers: [
-              ['Range', "bytes=-1"]
-            ],
-            expected_type: "cached",
-            expected_status: 206,
-            expected_response_text: "4"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache stores partial content and completes it",
-        requests: [
-          {
-            request_headers: [
-              ['Range', "bytes=-5"]
-            ],
-            response_status: [206, "Partial Content"],
-            response_headers: [
-              ["Cache-Control", "max-age=3600"],
-              ["Content-Range", "bytes 0-4/10"]
-            ],
-            response_body: "01234"
-          },
-          {
-            expected_request_headers: [
-              ["range", "bytes=5-"]
-            ]
-          }
-        ]
-      },
-    ];
-    run_tests(tests);
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/post-patch.any-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/http-cache/post-patch.any-expected.txt
new file mode 100644
index 0000000..3a5cd589
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/post-patch.any-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL HTTP cache uses content after PATCH request with response containing Content-Location and cache-allowing header assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache uses content after POST request with response containing Content-Location and cache-allowing header assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/post-patch.any.js b/third_party/blink/web_tests/external/wpt/fetch/http-cache/post-patch.any.js
new file mode 100644
index 0000000..0a69baa
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/post-patch.any.js
@@ -0,0 +1,46 @@
+// META: global=window,worker
+// META: title=HTTP Cache - Caching POST and PATCH responses
+// META: timeout=long
+// META: script=/common/utils.js
+// META: script=/common/get-host-info.sub.js
+// META: script=http-cache.js
+
+var tests = [
+  {
+    name: "HTTP cache uses content after PATCH request with response containing Content-Location and cache-allowing header",
+    requests: [
+      {
+        request_method: "PATCH",
+        request_body: "abc",
+        response_status: [200, "OK"],
+        response_headers: [
+          ['Cache-Control', "private, max-age=1000"],
+          ['Content-Location', ""]
+        ],
+        response_body: "abc"
+      },
+      {
+        expected_type: "cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache uses content after POST request with response containing Content-Location and cache-allowing header",
+    requests: [
+      {
+        request_method: "POST",
+        request_body: "abc",
+        response_status: [200, "OK"],
+        response_headers: [
+          ['Cache-Control', "private, max-age=1000"],
+          ['Content-Location', ""]
+        ],
+        response_body: "abc"
+      },
+      {
+        expected_type: "cached"
+      }
+    ]
+  }
+];
+run_tests(tests);
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/post-patch.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/http-cache/post-patch.any.serviceworker-expected.txt
new file mode 100644
index 0000000..3a5cd589
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/post-patch.any.serviceworker-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL HTTP cache uses content after PATCH request with response containing Content-Location and cache-allowing header assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache uses content after POST request with response containing Content-Location and cache-allowing header assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/post-patch.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/http-cache/post-patch.any.sharedworker-expected.txt
new file mode 100644
index 0000000..3a5cd589
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/post-patch.any.sharedworker-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL HTTP cache uses content after PATCH request with response containing Content-Location and cache-allowing header assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache uses content after POST request with response containing Content-Location and cache-allowing header assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/post-patch.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/http-cache/post-patch.any.worker-expected.txt
new file mode 100644
index 0000000..3a5cd589
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/post-patch.any.worker-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL HTTP cache uses content after PATCH request with response containing Content-Location and cache-allowing header assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+FAIL HTTP cache uses content after POST request with response containing Content-Location and cache-allowing header assert_less_than: Response 2 does not come from cache expected a number less than 2 but got 2
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/post-patch.html b/third_party/blink/web_tests/external/wpt/fetch/http-cache/post-patch.html
deleted file mode 100644
index 9025a96..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/http-cache/post-patch.html
+++ /dev/null
@@ -1,57 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>HTTP Cache - Caching POST and PATCH responses</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#request">
-    <meta name="timeout" content="long">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <script src="/common/utils.js"></script>
-    <script src="/common/get-host-info.sub.js"></script>
-    <script src="http-cache.js"></script>
-  </head>
-  <body>
-    <script>
-    var tests = [
-      {
-        name: "HTTP cache uses content after PATCH request with response containing Content-Location and cache-allowing header",
-        requests: [
-          {
-            request_method: "PATCH",
-            request_body: "abc",
-            response_status: [200, "OK"],
-            response_headers: [
-              ['Cache-Control', "private, max-age=1000"],
-              ['Content-Location', ""]
-            ],
-            response_body: "abc"
-          },
-          {
-            expected_type: "cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache uses content after POST request with response containing Content-Location and cache-allowing header",
-        requests: [
-          {
-            request_method: "POST",
-            request_body: "abc",
-            response_status: [200, "OK"],
-            response_headers: [
-              ['Cache-Control', "private, max-age=1000"],
-              ['Content-Location', ""]
-            ],
-            response_body: "abc"
-          },
-          {
-            expected_type: "cached"
-          }
-        ]
-      }
-    ];
-    run_tests(tests);
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/status.any.js b/third_party/blink/web_tests/external/wpt/fetch/http-cache/status.any.js
new file mode 100644
index 0000000..10c83a25
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/status.any.js
@@ -0,0 +1,60 @@
+// META: global=window,worker
+// META: title=HTTP Cache - Status Codes
+// META: timeout=long
+// META: script=/common/utils.js
+// META: script=/common/get-host-info.sub.js
+// META: script=http-cache.js
+
+var tests = [];
+function check_status(status) {
+  var code = status[0];
+  var phrase = status[1];
+  var body = status[2];
+  if (body === undefined) {
+    body = http_content(code);
+  }
+  tests.push({
+    name: "HTTP cache goes to the network if it has a stale " + code + " response",
+    requests: [
+      {
+        template: "stale",
+        response_status: [code, phrase],
+        response_body: body
+      }, {
+        expected_type: "not_cached",
+        response_status: [code, phrase],
+        response_body: body
+      }
+    ]
+  })
+  tests.push({
+    name: "HTTP cache avoids going to the network if it has a fresh " + code + " response",
+    requests: [
+      {
+        template: "fresh",
+        response_status: [code, phrase],
+        response_body: body
+      }, {
+        expected_type: "cached",
+        response_status: [code, phrase],
+        response_body: body
+      }
+    ]
+  })
+}
+[
+  [200, "OK"],
+  [203, "Non-Authoritative Information"],
+  [204, "No Content", null],
+  [299, "Whatever"],
+  [400, "Bad Request"],
+  [404, "Not Found"],
+  [410, "Gone"],
+  [499, "Whatever"],
+  [500, "Internal Server Error"],
+  [502, "Bad Gateway"],
+  [503, "Service Unavailable"],
+  [504, "Gateway Timeout"],
+  [599, "Whatever"]
+].forEach(check_status);
+run_tests(tests);
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/status.html b/third_party/blink/web_tests/external/wpt/fetch/http-cache/status.html
deleted file mode 100644
index d55d9e3..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/http-cache/status.html
+++ /dev/null
@@ -1,71 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>HTTP Cache - Status Codes</title>
-    <meta name="timeout" content="long">
-    <meta name="help" href="https://fetch.spec.whatwg.org/#request">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <script src="/common/utils.js"></script>
-    <script src="/common/get-host-info.sub.js"></script>
-    <script src="http-cache.js"></script>
-  </head>
-  <body>
-    <script>
-    var tests = [];
-    function check_status(status) {
-      var code = status[0];
-      var phrase = status[1];
-      var body = status[2];
-      if (body === undefined) {
-        body = http_content(code);
-      }
-      tests.push({
-        name: "HTTP cache goes to the network if it has a stale " + code + " response",
-        requests: [
-          {
-            template: "stale",
-            response_status: [code, phrase],
-            response_body: body
-          }, {
-            expected_type: "not_cached",
-            response_status: [code, phrase],
-            response_body: body
-          }
-        ]
-      })
-      tests.push({
-        name: "HTTP cache avoids going to the network if it has a fresh " + code + " response",
-        requests: [
-          {
-            template: "fresh",
-            response_status: [code, phrase],
-            response_body: body
-          }, {
-            expected_type: "cached",
-            response_status: [code, phrase],
-            response_body: body
-          }
-        ]
-      })
-    }
-    [
-      [200, "OK"],
-      [203, "Non-Authoritative Information"],
-      [204, "No Content", null],
-      [299, "Whatever"],
-      [400, "Bad Request"],
-      [404, "Not Found"],
-      [410, "Gone"],
-      [499, "Whatever"],
-      [500, "Internal Server Error"],
-      [502, "Bad Gateway"],
-      [503, "Service Unavailable"],
-      [504, "Gateway Timeout"],
-      [599, "Whatever"]
-    ].forEach(check_status);
-    run_tests(tests);
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/vary.any-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/http-cache/vary.any-expected.txt
new file mode 100644
index 0000000..5cfb7f71
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/vary.any-expected.txt
@@ -0,0 +1,16 @@
+This is a testharness.js-based test.
+PASS HTTP cache reuses Vary response when request matches
+PASS HTTP cache doesn't use Vary response when request doesn't match
+PASS HTTP cache doesn't use Vary response when request omits variant header
+FAIL HTTP cache doesn't invalidate existing Vary response assert_less_than: Response 3 does not come from cache expected a number less than 3 but got 3
+PASS HTTP cache doesn't pay attention to headers not listed in Vary
+PASS HTTP cache reuses two-way Vary response when request matches
+PASS HTTP cache doesn't use two-way Vary response when request doesn't match
+PASS HTTP cache doesn't use two-way Vary response when request omits variant header
+PASS HTTP cache reuses three-way Vary response when request matches
+PASS HTTP cache doesn't use three-way Vary response when request doesn't match
+PASS HTTP cache doesn't use three-way Vary response when request doesn't match, regardless of header order
+PASS HTTP cache uses three-way Vary response when both request and the original request omited a variant header
+PASS HTTP cache doesn't use Vary response with a field value of '*'
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/vary.any.js b/third_party/blink/web_tests/external/wpt/fetch/http-cache/vary.any.js
new file mode 100644
index 0000000..2cfd226a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/vary.any.js
@@ -0,0 +1,313 @@
+// META: global=window,worker
+// META: title=HTTP Cache - Vary
+// META: timeout=long
+// META: script=/common/utils.js
+// META: script=/common/get-host-info.sub.js
+// META: script=http-cache.js
+
+var tests = [
+  {
+    name: "HTTP cache reuses Vary response when request matches",
+    requests: [
+      {
+        request_headers: [
+          ["Foo", "1"]
+        ],
+        response_headers: [
+          ["Expires", 5000],
+          ["Last-Modified", -3000],
+          ["Vary", "Foo"]
+        ]
+      },
+      {
+        request_headers: [
+          ["Foo", "1"]
+        ],
+        expected_type: "cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache doesn't use Vary response when request doesn't match",
+    requests: [
+      {
+        request_headers: [
+          ["Foo", "1"]
+        ],
+        response_headers: [
+          ["Expires", 5000],
+          ["Last-Modified", -3000],
+          ["Vary", "Foo"]
+        ]
+      },
+      {
+        request_headers: [
+          ["Foo", "2"]
+        ],
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache doesn't use Vary response when request omits variant header",
+    requests: [
+      {
+        request_headers: [
+          ["Foo", "1"]
+        ],
+        response_headers: [
+          ["Expires", 5000],
+          ["Last-Modified", -3000],
+          ["Vary", "Foo"]
+        ]
+      },
+      {
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache doesn't invalidate existing Vary response",
+    requests: [
+      {
+        request_headers: [
+          ["Foo", "1"]
+        ],
+        response_headers: [
+          ["Expires", 5000],
+          ["Last-Modified", -3000],
+          ["Vary", "Foo"]
+        ],
+        response_body: http_content('foo_1')
+      },
+      {
+        request_headers: [
+          ["Foo", "2"]
+        ],
+        response_headers: [
+          ["Expires", 5000],
+          ["Last-Modified", -3000],
+          ["Vary", "Foo"]
+        ],
+        expected_type: "not_cached",
+        response_body: http_content('foo_2'),
+      },
+      {
+        request_headers: [
+          ["Foo", "1"]
+        ],
+        response_body: http_content('foo_1'),
+        expected_type: "cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache doesn't pay attention to headers not listed in Vary",
+    requests: [
+      {
+        request_headers: [
+          ["Foo", "1"],
+          ["Other", "2"]
+        ],
+        response_headers: [
+          ["Expires", 5000],
+          ["Last-Modified", -3000],
+          ["Vary", "Foo"]
+        ],
+      },
+      {
+        request_headers: [
+          ["Foo", "1"],
+          ["Other", "3"]
+        ],
+        expected_type: "cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache reuses two-way Vary response when request matches",
+    requests: [
+      {
+        request_headers: [
+          ["Foo", "1"],
+          ["Bar", "abc"]
+        ],
+        response_headers: [
+          ["Expires", 5000],
+          ["Last-Modified", -3000],
+          ["Vary", "Foo, Bar"]
+        ]
+      },
+      {
+        request_headers: [
+          ["Foo", "1"],
+          ["Bar", "abc"]
+        ],
+        expected_type: "cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache doesn't use two-way Vary response when request doesn't match",
+    requests: [
+      {
+        request_headers: [
+          ["Foo", "1"],
+          ["Bar", "abc"]
+        ],
+        response_headers: [
+          ["Expires", 5000],
+          ["Last-Modified", -3000],
+          ["Vary", "Foo, Bar"]
+        ]
+      },
+      {
+        request_headers: [
+          ["Foo", "2"],
+          ["Bar", "abc"]
+        ],
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache doesn't use two-way Vary response when request omits variant header",
+    requests: [
+      {
+        request_headers: [
+          ["Foo", "1"]
+        ],
+        response_headers: [
+          ["Expires", 5000],
+          ["Last-Modified", -3000],
+          ["Vary", "Foo, Bar"]
+        ]
+      },
+      {
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache reuses three-way Vary response when request matches",
+    requests: [
+      {
+        request_headers: [
+          ["Foo", "1"],
+          ["Bar", "abc"],
+          ["Baz", "789"]
+        ],
+        response_headers: [
+          ["Expires", 5000],
+          ["Last-Modified", -3000],
+          ["Vary", "Foo, Bar, Baz"]
+        ]
+      },
+      {
+        request_headers: [
+          ["Foo", "1"],
+          ["Bar", "abc"],
+          ["Baz", "789"]
+        ],
+        expected_type: "cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache doesn't use three-way Vary response when request doesn't match",
+    requests: [
+      {
+        request_headers: [
+          ["Foo", "1"],
+          ["Bar", "abc"],
+          ["Baz", "789"]
+        ],
+        response_headers: [
+          ["Expires", 5000],
+          ["Last-Modified", -3000],
+          ["Vary", "Foo, Bar, Baz"]
+        ]
+      },
+      {
+        request_headers: [
+          ["Foo", "2"],
+          ["Bar", "abc"],
+          ["Baz", "789"]
+        ],
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache doesn't use three-way Vary response when request doesn't match, regardless of header order",
+    requests: [
+      {
+        request_headers: [
+          ["Foo", "1"],
+          ["Bar", "abc4"],
+          ["Baz", "789"]
+        ],
+        response_headers: [
+          ["Expires", 5000],
+          ["Last-Modified", -3000],
+          ["Vary", "Foo, Bar, Baz"]
+        ]
+      },
+      {
+        request_headers: [
+          ["Foo", "1"],
+          ["Bar", "abc"],
+          ["Baz", "789"]
+        ],
+        expected_type: "not_cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache uses three-way Vary response when both request and the original request omited a variant header",
+    requests: [
+      {
+        request_headers: [
+          ["Foo", "1"],
+          ["Baz", "789"]
+        ],
+        response_headers: [
+          ["Expires", 5000],
+          ["Last-Modified", -3000],
+          ["Vary", "Foo, Bar, Baz"]
+        ]
+      },
+      {
+        request_headers: [
+          ["Foo", "1"],
+          ["Baz", "789"]
+        ],
+        expected_type: "cached"
+      }
+    ]
+  },
+  {
+    name: "HTTP cache doesn't use Vary response with a field value of '*'",
+    requests: [
+      {
+        request_headers: [
+          ["Foo", "1"],
+          ["Baz", "789"]
+        ],
+        response_headers: [
+          ["Expires", 5000],
+          ["Last-Modified", -3000],
+          ["Vary", "*"]
+        ]
+      },
+      {
+        request_headers: [
+          ["*", "1"],
+          ["Baz", "789"]
+        ],
+        expected_type: "not_cached"
+      }
+    ]
+  }
+];
+run_tests(tests);
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/vary.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/http-cache/vary.any.serviceworker-expected.txt
new file mode 100644
index 0000000..5cfb7f71
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/vary.any.serviceworker-expected.txt
@@ -0,0 +1,16 @@
+This is a testharness.js-based test.
+PASS HTTP cache reuses Vary response when request matches
+PASS HTTP cache doesn't use Vary response when request doesn't match
+PASS HTTP cache doesn't use Vary response when request omits variant header
+FAIL HTTP cache doesn't invalidate existing Vary response assert_less_than: Response 3 does not come from cache expected a number less than 3 but got 3
+PASS HTTP cache doesn't pay attention to headers not listed in Vary
+PASS HTTP cache reuses two-way Vary response when request matches
+PASS HTTP cache doesn't use two-way Vary response when request doesn't match
+PASS HTTP cache doesn't use two-way Vary response when request omits variant header
+PASS HTTP cache reuses three-way Vary response when request matches
+PASS HTTP cache doesn't use three-way Vary response when request doesn't match
+PASS HTTP cache doesn't use three-way Vary response when request doesn't match, regardless of header order
+PASS HTTP cache uses three-way Vary response when both request and the original request omited a variant header
+PASS HTTP cache doesn't use Vary response with a field value of '*'
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/vary.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/http-cache/vary.any.sharedworker-expected.txt
new file mode 100644
index 0000000..5cfb7f71
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/vary.any.sharedworker-expected.txt
@@ -0,0 +1,16 @@
+This is a testharness.js-based test.
+PASS HTTP cache reuses Vary response when request matches
+PASS HTTP cache doesn't use Vary response when request doesn't match
+PASS HTTP cache doesn't use Vary response when request omits variant header
+FAIL HTTP cache doesn't invalidate existing Vary response assert_less_than: Response 3 does not come from cache expected a number less than 3 but got 3
+PASS HTTP cache doesn't pay attention to headers not listed in Vary
+PASS HTTP cache reuses two-way Vary response when request matches
+PASS HTTP cache doesn't use two-way Vary response when request doesn't match
+PASS HTTP cache doesn't use two-way Vary response when request omits variant header
+PASS HTTP cache reuses three-way Vary response when request matches
+PASS HTTP cache doesn't use three-way Vary response when request doesn't match
+PASS HTTP cache doesn't use three-way Vary response when request doesn't match, regardless of header order
+PASS HTTP cache uses three-way Vary response when both request and the original request omited a variant header
+PASS HTTP cache doesn't use Vary response with a field value of '*'
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/vary.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/http-cache/vary.any.worker-expected.txt
new file mode 100644
index 0000000..5cfb7f71
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/vary.any.worker-expected.txt
@@ -0,0 +1,16 @@
+This is a testharness.js-based test.
+PASS HTTP cache reuses Vary response when request matches
+PASS HTTP cache doesn't use Vary response when request doesn't match
+PASS HTTP cache doesn't use Vary response when request omits variant header
+FAIL HTTP cache doesn't invalidate existing Vary response assert_less_than: Response 3 does not come from cache expected a number less than 3 but got 3
+PASS HTTP cache doesn't pay attention to headers not listed in Vary
+PASS HTTP cache reuses two-way Vary response when request matches
+PASS HTTP cache doesn't use two-way Vary response when request doesn't match
+PASS HTTP cache doesn't use two-way Vary response when request omits variant header
+PASS HTTP cache reuses three-way Vary response when request matches
+PASS HTTP cache doesn't use three-way Vary response when request doesn't match
+PASS HTTP cache doesn't use three-way Vary response when request doesn't match, regardless of header order
+PASS HTTP cache uses three-way Vary response when both request and the original request omited a variant header
+PASS HTTP cache doesn't use Vary response with a field value of '*'
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/vary.html b/third_party/blink/web_tests/external/wpt/fetch/http-cache/vary.html
deleted file mode 100644
index 721d6e79..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/http-cache/vary.html
+++ /dev/null
@@ -1,323 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>HTTP Cache - Vary</title>
-    <meta name="help" href="https://fetch.spec.whatwg.org/#request">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <script src="/common/utils.js"></script>
-    <script src="/common/get-host-info.sub.js"></script>
-    <script src="http-cache.js"></script>
-  </head>
-  <body>
-    <script>
-    var tests = [
-      {
-        name: "HTTP cache reuses Vary response when request matches",
-        requests: [
-          {
-            request_headers: [
-              ["Foo", "1"]
-            ],
-            response_headers: [
-              ["Expires", 5000],
-              ["Last-Modified", -3000],
-              ["Vary", "Foo"]
-            ]
-          },
-          {
-            request_headers: [
-              ["Foo", "1"]
-            ],
-            expected_type: "cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache doesn't use Vary response when request doesn't match",
-        requests: [
-          {
-            request_headers: [
-              ["Foo", "1"]
-            ],
-            response_headers: [
-              ["Expires", 5000],
-              ["Last-Modified", -3000],
-              ["Vary", "Foo"]
-            ]
-          },
-          {
-            request_headers: [
-              ["Foo", "2"]
-            ],
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache doesn't use Vary response when request omits variant header",
-        requests: [
-          {
-            request_headers: [
-              ["Foo", "1"]
-            ],
-            response_headers: [
-              ["Expires", 5000],
-              ["Last-Modified", -3000],
-              ["Vary", "Foo"]
-            ]
-          },
-          {
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache doesn't invalidate existing Vary response",
-        requests: [
-          {
-            request_headers: [
-              ["Foo", "1"]
-            ],
-            response_headers: [
-              ["Expires", 5000],
-              ["Last-Modified", -3000],
-              ["Vary", "Foo"]
-            ],
-            response_body: http_content('foo_1')
-          },
-          {
-            request_headers: [
-              ["Foo", "2"]
-            ],
-            response_headers: [
-              ["Expires", 5000],
-              ["Last-Modified", -3000],
-              ["Vary", "Foo"]
-            ],
-            expected_type: "not_cached",
-            response_body: http_content('foo_2'),
-          },
-          {
-            request_headers: [
-              ["Foo", "1"]
-            ],
-            response_body: http_content('foo_1'),
-            expected_type: "cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache doesn't pay attention to headers not listed in Vary",
-        requests: [
-          {
-            request_headers: [
-              ["Foo", "1"],
-              ["Other", "2"]
-            ],
-            response_headers: [
-              ["Expires", 5000],
-              ["Last-Modified", -3000],
-              ["Vary", "Foo"]
-            ],
-          },
-          {
-            request_headers: [
-              ["Foo", "1"],
-              ["Other", "3"]
-            ],
-            expected_type: "cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache reuses two-way Vary response when request matches",
-        requests: [
-          {
-            request_headers: [
-              ["Foo", "1"],
-              ["Bar", "abc"]
-            ],
-            response_headers: [
-              ["Expires", 5000],
-              ["Last-Modified", -3000],
-              ["Vary", "Foo, Bar"]
-            ]
-          },
-          {
-            request_headers: [
-              ["Foo", "1"],
-              ["Bar", "abc"]
-            ],
-            expected_type: "cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache doesn't use two-way Vary response when request doesn't match",
-        requests: [
-          {
-            request_headers: [
-              ["Foo", "1"],
-              ["Bar", "abc"]
-            ],
-            response_headers: [
-              ["Expires", 5000],
-              ["Last-Modified", -3000],
-              ["Vary", "Foo, Bar"]
-            ]
-          },
-          {
-            request_headers: [
-              ["Foo", "2"],
-              ["Bar", "abc"]
-            ],
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache doesn't use two-way Vary response when request omits variant header",
-        requests: [
-          {
-            request_headers: [
-              ["Foo", "1"]
-            ],
-            response_headers: [
-              ["Expires", 5000],
-              ["Last-Modified", -3000],
-              ["Vary", "Foo, Bar"]
-            ]
-          },
-          {
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache reuses three-way Vary response when request matches",
-        requests: [
-          {
-            request_headers: [
-              ["Foo", "1"],
-              ["Bar", "abc"],
-              ["Baz", "789"]
-            ],
-            response_headers: [
-              ["Expires", 5000],
-              ["Last-Modified", -3000],
-              ["Vary", "Foo, Bar, Baz"]
-            ]
-          },
-          {
-            request_headers: [
-              ["Foo", "1"],
-              ["Bar", "abc"],
-              ["Baz", "789"]
-            ],
-            expected_type: "cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache doesn't use three-way Vary response when request doesn't match",
-        requests: [
-          {
-            request_headers: [
-              ["Foo", "1"],
-              ["Bar", "abc"],
-              ["Baz", "789"]
-            ],
-            response_headers: [
-              ["Expires", 5000],
-              ["Last-Modified", -3000],
-              ["Vary", "Foo, Bar, Baz"]
-            ]
-          },
-          {
-            request_headers: [
-              ["Foo", "2"],
-              ["Bar", "abc"],
-              ["Baz", "789"]
-            ],
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache doesn't use three-way Vary response when request doesn't match, regardless of header order",
-        requests: [
-          {
-            request_headers: [
-              ["Foo", "1"],
-              ["Bar", "abc4"],
-              ["Baz", "789"]
-            ],
-            response_headers: [
-              ["Expires", 5000],
-              ["Last-Modified", -3000],
-              ["Vary", "Foo, Bar, Baz"]
-            ]
-          },
-          {
-            request_headers: [
-              ["Foo", "1"],
-              ["Bar", "abc"],
-              ["Baz", "789"]
-            ],
-            expected_type: "not_cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache uses three-way Vary response when both request and the original request omited a variant header",
-        requests: [
-          {
-            request_headers: [
-              ["Foo", "1"],
-              ["Baz", "789"]
-            ],
-            response_headers: [
-              ["Expires", 5000],
-              ["Last-Modified", -3000],
-              ["Vary", "Foo, Bar, Baz"]
-            ]
-          },
-          {
-            request_headers: [
-              ["Foo", "1"],
-              ["Baz", "789"]
-            ],
-            expected_type: "cached"
-          }
-        ]
-      },
-      {
-        name: "HTTP cache doesn't use Vary response with a field value of '*'",
-        requests: [
-          {
-            request_headers: [
-              ["Foo", "1"],
-              ["Baz", "789"]
-            ],
-            response_headers: [
-              ["Expires", 5000],
-              ["Last-Modified", -3000],
-              ["Vary", "*"]
-            ]
-          },
-          {
-            request_headers: [
-              ["*", "1"],
-              ["Baz", "789"]
-            ],
-            expected_type: "not_cached"
-          }
-        ]
-      }
-    ];
-    run_tests(tests);
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/metadata/fetch-preflight.https.sub.any.js b/third_party/blink/web_tests/external/wpt/fetch/metadata/fetch-preflight.https.sub.any.js
new file mode 100644
index 0000000..d5247435
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/metadata/fetch-preflight.https.sub.any.js
@@ -0,0 +1,29 @@
+// META: global=window,worker
+// META: script=/fetch/metadata/resources/helper.js
+
+// Site
+promise_test(t => {
+  return validate_expectations_custom_url("https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py",
+                {
+                  mode: "cors",
+                  headers: { 'x-test': 'testing' }
+                }, {
+          "site": "same-site",
+          "user": "",
+          "mode": "cors",
+          "dest": "empty"
+        }, "Same-site fetch with preflight");
+}, "Same-site fetch with preflight");
+
+promise_test(t => {
+  return validate_expectations_custom_url("https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py",
+                {
+                  mode: "cors",
+                  headers: { 'x-test': 'testing' }
+                }, {
+          "site": "cross-site",
+          "user": "",
+          "mode": "cors",
+          "dest": "empty"
+        }, "Cross-site fetch with preflight");
+}, "Cross-site fetch with preflight");
diff --git a/third_party/blink/web_tests/external/wpt/fetch/metadata/fetch-preflight.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/metadata/fetch-preflight.https.sub.html
deleted file mode 100644
index ec987e1c..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/metadata/fetch-preflight.https.sub.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<!DOCTYPE html>
-<script src=/resources/testharness.js></script>
-<script src=/resources/testharnessreport.js></script>
-<script src=/fetch/metadata/resources/helper.js></script>
-<script>
-  // Site
-  promise_test(t => {
-    return validate_expectations_custom_url("https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py",
-                 {
-                   mode: "cors",
-                   headers: { 'x-test': 'testing' }
-                 }, {
-            "site": "same-site",
-            "user": "",
-            "mode": "cors",
-            "dest": "empty"
-          }, "Same-site fetch with preflight");
-  }, "Same-site fetch with preflight");
-
-  promise_test(t => {
-    return validate_expectations_custom_url("https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py",
-                 {
-                   mode: "cors",
-                   headers: { 'x-test': 'testing' }
-                 }, {
-            "site": "cross-site",
-            "user": "",
-            "mode": "cors",
-            "dest": "empty"
-          }, "Cross-site fetch with preflight");
-  }, "Cross-site fetch with preflight");
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/metadata/fetch.https.sub.any.js b/third_party/blink/web_tests/external/wpt/fetch/metadata/fetch.https.sub.any.js
new file mode 100644
index 0000000..aeec5cdf
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/metadata/fetch.https.sub.any.js
@@ -0,0 +1,58 @@
+// META: global=window,worker
+// META: script=/fetch/metadata/resources/helper.js
+
+// Site
+promise_test(t => {
+  return validate_expectations_custom_url("https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py", {}, {
+          "site": "same-origin",
+          "user": "",
+          "mode": "cors",
+          "dest": "empty"
+        }, "Same-origin fetch");
+}, "Same-origin fetch");
+
+promise_test(t => {
+  return validate_expectations_custom_url("https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py", {}, {
+          "site": "same-site",
+          "user": "",
+          "mode": "cors",
+          "dest": "empty"
+        }, "Same-site fetch");
+}, "Same-site fetch");
+
+promise_test(t => {
+  return validate_expectations_custom_url("https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py", {}, {
+          "site": "cross-site",
+          "user": "",
+          "mode": "cors",
+          "dest": "empty"
+        }, "Cross-site fetch");
+}, "Cross-site fetch");
+
+// Mode
+promise_test(t => {
+  return validate_expectations_custom_url("https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py", {mode: "same-origin"}, {
+          "site": "same-origin",
+          "user": "",
+          "mode": "same-origin",
+          "dest": "empty"
+        }, "Same-origin mode");
+}, "Same-origin mode");
+
+promise_test(t => {
+  return validate_expectations_custom_url("https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py", {mode: "cors"}, {
+          "site": "same-origin",
+          "user": "",
+          "mode": "cors",
+          "dest": "empty"
+        }, "CORS mode");
+}, "CORS mode");
+
+promise_test(t => {
+  return validate_expectations_custom_url("https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py", {mode: "no-cors"}, {
+          "site": "same-origin",
+          "user": "",
+          "mode": "no-cors",
+          "dest": "empty"
+        }, "no-CORS mode");
+}, "no-CORS mode");
diff --git a/third_party/blink/web_tests/external/wpt/fetch/metadata/fetch.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/metadata/fetch.https.sub.html
deleted file mode 100644
index bb7d2000..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/metadata/fetch.https.sub.html
+++ /dev/null
@@ -1,61 +0,0 @@
-<!DOCTYPE html>
-<script src=/resources/testharness.js></script>
-<script src=/resources/testharnessreport.js></script>
-<script src=/fetch/metadata/resources/helper.js></script>
-<script>
-  // Site
-  promise_test(t => {
-    return validate_expectations_custom_url("https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py", {}, {
-            "site": "same-origin",
-            "user": "",
-            "mode": "cors",
-            "dest": "empty"
-          }, "Same-origin fetch");
-  }, "Same-origin fetch");
-
-  promise_test(t => {
-    return validate_expectations_custom_url("https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py", {}, {
-            "site": "same-site",
-            "user": "",
-            "mode": "cors",
-            "dest": "empty"
-          }, "Same-site fetch");
-  }, "Same-site fetch");
-
-  promise_test(t => {
-    return validate_expectations_custom_url("https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py", {}, {
-            "site": "cross-site",
-            "user": "",
-            "mode": "cors",
-            "dest": "empty"
-          }, "Cross-site fetch");
-  }, "Cross-site fetch");
-
-  // Mode
-  promise_test(t => {
-    return validate_expectations_custom_url("https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py", {mode: "same-origin"}, {
-            "site": "same-origin",
-            "user": "",
-            "mode": "same-origin",
-            "dest": "empty"
-          }, "Same-origin mode");
-  }, "Same-origin mode");
-
-  promise_test(t => {
-    return validate_expectations_custom_url("https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py", {mode: "cors"}, {
-            "site": "same-origin",
-            "user": "",
-            "mode": "cors",
-            "dest": "empty"
-          }, "CORS mode");
-  }, "CORS mode");
-
-  promise_test(t => {
-    return validate_expectations_custom_url("https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py", {mode: "no-cors"}, {
-            "site": "same-origin",
-            "user": "",
-            "mode": "no-cors",
-            "dest": "empty"
-          }, "no-CORS mode");
-  }, "no-CORS mode");
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/metadata/trailing-dot.https.sub.any.js b/third_party/blink/web_tests/external/wpt/fetch/metadata/trailing-dot.https.sub.any.js
new file mode 100644
index 0000000..5e32fc4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/metadata/trailing-dot.https.sub.any.js
@@ -0,0 +1,30 @@
+// META: global=window,worker
+// META: script=/fetch/metadata/resources/helper.js
+
+// Site
+promise_test(t => {
+  return validate_expectations_custom_url("https://{{host}}.:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py", {}, {
+          "site": "cross-site",
+          "user": "",
+          "mode": "cors",
+          "dest": "empty"
+        }, "Fetching a resource from the same origin, but spelled with a trailing dot.");
+}, "Fetching a resource from the same origin, but spelled with a trailing dot.");
+
+promise_test(t => {
+  return validate_expectations_custom_url("https://{{hosts[][www]}}.:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py", {}, {
+          "site": "cross-site",
+          "user": "",
+          "mode": "cors",
+          "dest": "empty"
+        }, "Fetching a resource from the same site, but spelled with a trailing dot.");
+}, "Fetching a resource from the same site, but spelled with a trailing dot.");
+
+promise_test(t => {
+  return validate_expectations_custom_url("https://{{hosts[alt][www]}}.:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py", {}, {
+          "site": "cross-site",
+          "user": "",
+          "mode": "cors",
+          "dest": "empty"
+        }, "Fetching a resource from a cross-site host, spelled with a trailing dot.");
+}, "Fetching a resource from a cross-site host, spelled with a trailing dot.");
diff --git a/third_party/blink/web_tests/external/wpt/fetch/metadata/trailing-dot.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/metadata/trailing-dot.https.sub.html
deleted file mode 100644
index afd876f..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/metadata/trailing-dot.https.sub.html
+++ /dev/null
@@ -1,33 +0,0 @@
-<!DOCTYPE html>
-<script src=/resources/testharness.js></script>
-<script src=/resources/testharnessreport.js></script>
-<script src=/fetch/metadata/resources/helper.js></script>
-<script>
-  // Site
-  promise_test(t => {
-    return validate_expectations_custom_url("https://{{host}}.:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py", {}, {
-            "site": "cross-site",
-            "user": "",
-            "mode": "cors",
-            "dest": "empty"
-          }, "Fetching a resource from the same origin, but spelled with a trailing dot.");
-  }, "Fetching a resource from the same origin, but spelled with a trailing dot.");
-
-  promise_test(t => {
-    return validate_expectations_custom_url("https://{{hosts[][www]}}.:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py", {}, {
-            "site": "cross-site",
-            "user": "",
-            "mode": "cors",
-            "dest": "empty"
-          }, "Fetching a resource from the same site, but spelled with a trailing dot.");
-  }, "Fetching a resource from the same site, but spelled with a trailing dot.");
-
-  promise_test(t => {
-    return validate_expectations_custom_url("https://{{hosts[alt][www]}}.:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py", {}, {
-            "site": "cross-site",
-            "user": "",
-            "mode": "cors",
-            "dest": "empty"
-          }, "Fetching a resource from a cross-site host, spelled with a trailing dot.");
-  }, "Fetching a resource from a cross-site host, spelled with a trailing dot.");
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/range/general.any.js b/third_party/blink/web_tests/external/wpt/fetch/range/general.any.js
index 656ac1c..80791c3 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/range/general.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/range/general.any.js
@@ -1,3 +1,4 @@
+// META: global=window,worker
 // META: script=/common/utils.js
 
 // Helpers that return headers objects with a particular guard
diff --git a/third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/fetch.html b/third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/fetch.any.js
similarity index 76%
rename from third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/fetch.html
rename to third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/fetch.any.js
index c2870801..3682b9d 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/fetch.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/fetch.any.js
@@ -1,10 +1,7 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>Tests Stale While Revalidate is executed for fetch API</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/common/utils.js"></script>
-<script>
+// META: global=window,worker
+// META: title=Tests Stale While Revalidate is executed for fetch API
+// META: script=/common/utils.js
+
 function wait25ms(test) {
   return new Promise(resolve => {
     test.step_timeout(() => {
@@ -33,4 +30,3 @@
     await wait25ms(test);
   }
 }, 'Second fetch returns same response');
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/sanitizer-api.tentative.idl b/third_party/blink/web_tests/external/wpt/interfaces/sanitizer-api.tentative.idl
index 11653d1..129c296 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/sanitizer-api.tentative.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/sanitizer-api.tentative.idl
@@ -4,8 +4,8 @@
   Exposed=Window
 ] interface Sanitizer {
   constructor(optional SanitizerConfig sanitizerConfig = {});
-  DocumentFragment sanitize(DOMString input);
-  DOMString sanitizeToString(DOMString input);
+  DocumentFragment sanitize((DOMString or DocumentFragment or Document) input);
+  DOMString sanitizeToString((DOMString or DocumentFragment or Document) input);
 };
 
 dictionary SanitizerConfig {
@@ -13,6 +13,5 @@
   sequence<DOMString> blockElements;
   sequence<DOMString> dropElements;
   sequence<DOMString> allowAttributes;
-  sequence<DOMString> blockAttributes;
   sequence<DOMString> dropAttributes;
 };
diff --git a/third_party/blink/web_tests/inspector-protocol/emulation/set-vision-deficiency-expected.txt b/third_party/blink/web_tests/inspector-protocol/emulation/set-vision-deficiency-expected.txt
index d11895bf..865f9191 100644
--- a/third_party/blink/web_tests/inspector-protocol/emulation/set-vision-deficiency-expected.txt
+++ b/third_party/blink/web_tests/inspector-protocol/emulation/set-vision-deficiency-expected.txt
@@ -2,7 +2,7 @@
 <p>Emulating "none":
 <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAAXNSR0IArs4c6QAAAFRJREFUWIXt18ENACAMw8DA5N0chnCQePgGiKz+ujI5aZru3K6uPWAgZSBlIGUgZSBlIGUgZSBlILWS030iyr6/oIGUgZSBlIGUgZSBlIGUgZSB1AXNwwVLtuf+dAAAAABJRU5ErkJggg==">
 <p>Emulating "achromatopsia":
-<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAAXNSR0IArs4c6QAAAFpJREFUWIXt10ENADEMxMD2eARR2IfQFYS3Uh8eACsrv+zu/lfQzCTn1hddu8BAykDKQMpAykDKQMpAykDKQGpXVfQnSXv+ggZSBlIGUgZSBlIGUgZSBlIGUgcPVwX7L3bHewAAAABJRU5ErkJggg==">
+<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAAXNSR0IArs4c6QAAAFpJREFUWIXt10ENADEMxMD2IARfcIbeFYS3Uh8eACsrv+zu/lfQzCTn1hddu8BAykDKQMpAykDKQMpAykDKQGpXVfQnSXv+ggZSBlIGUgZSBlIGUgZSBlIGUgdMlAW5OcC1dAAAAABJRU5ErkJggg==">
 <p>Emulating "blurredVision":
 <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAAXNSR0IArs4c6QAAAehJREFUWIXtl81u4jAURo8TN7RpASXqohKLvsG89DzXLJFm1ZZCyb89i5tAWtAQYlfqIp90FWEl1yfX186H4tdvy3wN8Qvc7CGoQVnA8n8psAqMhiqGfQrbFWye4X0FWSrjRst9qAv5zkuzWEPyBx7+QrQDXbZwAwBRUEdQPsDuSYbKOeQJFAtQZhTUZ8C7F4FbrGG2EUBlhgHaQACLhQzlCURbCAtZicOLjqueAN7spXK3G5i9jQCcyfz5TlokLI9tMp6rBxjUkjQsBU4X1wEC1GUPrOn18KUcQwCV4WwM6kF6z1hvVfsMeJA9E5d07hk/lesUeMv0TZoAXTUBumoCdFXvHFRf4pKuvX+cNDbgJIDBn7qT8AusMRqaSKKO2rmvdDPd80aDDb1CaqpY/Fy+FKZRdmspOaq4B9pV0xUwS8VsAkRLN8OapWJYmxmYEB/9qXlfCUue+LH8WQplfKyiozSbZ3nr7bb1dM0AuB6kCWVZy7nAfTxCdS9jHjaNVDBLxKh2Nl0NBOwmN1qcdRVDed/7s+ReQcXtqyWor1ja0xSHpe5OBKPbHnTfKIqwsIddqxgJ2F39n4cK1bREri5YHa+2/9s5q/UM6FdfvsU/Tz/ezUyArpoAXTUBumoCdNUE6KoJ0FX/AAow6PKlz4YvAAAAAElFTkSuQmCC">
 <p>Emulating "none":
@@ -50,5 +50,5 @@
 <p>Navigating&mldr;
 <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAAXNSR0IArs4c6QAAAFhJREFUWIXt10ENACAQxEAgiMQJsnDHF0R0SXh0BGya+10tc5yStHZ0rkXXHjCQMpAykDKQMpAykDKQMpAykOrpHyLt+wsaSBlIGUgZSBlIGUgZSBlIGUhdCWsFapTFH60AAAAASUVORK5CYII=">
 <p>Emulating "achromatopsia":
-<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAAXNSR0IArs4c6QAAAFpJREFUWIXt10ENADEMxMD2eARR2IfQFYS3Uh8eACsrv+zu/lfQzCTn1hddu8BAykDKQMpAykDKQMpAykDKQGpXVfQnSXv+ggZSBlIGUgZSBlIGUgZSBlIGUgcPVwX7L3bHewAAAABJRU5ErkJggg==">
+<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAAXNSR0IArs4c6QAAAFpJREFUWIXt10ENADEMxMD2IARfcIbeFYS3Uh8eACsrv+zu/lfQzCTn1hddu8BAykDKQMpAykDKQMpAykDKQGpXVfQnSXv+ggZSBlIGUgZSBlIGUgZSBlIGUgdMlAW5OcC1dAAAAABJRU5ErkJggg==">
 
diff --git a/third_party/blink/web_tests/platform/mac-mac10.15/external/wpt/media-source/mediasource-detach-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.15/external/wpt/media-source/mediasource-detach-expected.txt
new file mode 100644
index 0000000..dd048132
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.15/external/wpt/media-source/mediasource-detach-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+PASS Test media.load() before appending data will trigger MediaSource detaching from a media element.
+FAIL Test media.load() after appending data will trigger MediaSource detaching from a media element. assert_greater_than: media readyState is greater than "HAVE_NOTHING" expected a number greater than 0 but got 0
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win7/external/wpt/media-source/mediasource-detach-expected.txt b/third_party/blink/web_tests/platform/win7/external/wpt/media-source/mediasource-detach-expected.txt
index 3a61110a..dd048132 100644
--- a/third_party/blink/web_tests/platform/win7/external/wpt/media-source/mediasource-detach-expected.txt
+++ b/third_party/blink/web_tests/platform/win7/external/wpt/media-source/mediasource-detach-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
 PASS Test media.load() before appending data will trigger MediaSource detaching from a media element.
-PASS Test media.load() after appending data will trigger MediaSource detaching from a media element.
+FAIL Test media.load() after appending data will trigger MediaSource detaching from a media element. assert_greater_than: media readyState is greater than "HAVE_NOTHING" expected a number greater than 0 but got 0
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/wpt_internal/sanitizer-api/sanitizer-sanitize.tentative-expected.txt b/third_party/blink/web_tests/wpt_internal/sanitizer-api/sanitizer-sanitize.tentative-expected.txt
index 0a9398c..a43f5ca 100644
--- a/third_party/blink/web_tests/wpt_internal/sanitizer-api/sanitizer-sanitize.tentative-expected.txt
+++ b/third_party/blink/web_tests/wpt_internal/sanitizer-api/sanitizer-sanitize.tentative-expected.txt
@@ -1,39 +1,108 @@
 This is a testharness.js-based test.
+Found 104 tests; 101 PASS, 3 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS SanitizerAPI sanitize function without argument should throw an error.
-PASS SanitizerAPI with config: string, sanitize function for string
-PASS SanitizerAPI with config: html fragment, sanitize function for html fragment
-PASS SanitizerAPI with config: broken html, sanitize function for broken html
-PASS SanitizerAPI with config: empty object, sanitize function for empty object
-PASS SanitizerAPI with config: number, sanitize function for number
-PASS SanitizerAPI with config: zeros, sanitize function for zeros
-PASS SanitizerAPI with config: arithmetic, sanitize function for arithmetic
-PASS SanitizerAPI with config: empty string, sanitize function for empty string
-PASS SanitizerAPI with config: undefined, sanitize function for undefined
-PASS SanitizerAPI with config: null, sanitize function for null
-PASS SanitizerAPI with config: document, sanitize function for document
-PASS SanitizerAPI with config: html without close tag, sanitize function for html without close tag
-PASS SanitizerAPI with config: scripts for default configs, sanitize function for scripts for default configs
-PASS SanitizerAPI with config: onclick scripts, sanitize function for onclick scripts
-PASS SanitizerAPI with config: invalid config_input, sanitize function for invalid config_input
-PASS SanitizerAPI with config: empty dropElements list, sanitize function for empty dropElements list
-PASS SanitizerAPI with config: test html without close tag with dropElements list ['div'], sanitize function for test html without close tag with dropElements list ['div']
-PASS SanitizerAPI with config: test script with ["script"] as dropElements list, sanitize function for test script with ["script"] as dropElements list
-PASS SanitizerAPI with config: dropElements list ["test", "i"]}, sanitize function for dropElements list ["test", "i"]}
-PASS SanitizerAPI with config: dropElements list ["I", "AM"]}, sanitize function for dropElements list ["I", "AM"]}
-PASS SanitizerAPI with config: dropElements list ["am", "p"]}, sanitize function for dropElements list ["am", "p"]}
-PASS SanitizerAPI with config: dropElements list with invalid values}, sanitize function for dropElements list with invalid values}
-PASS SanitizerAPI with config: blockElements list with invalid values}, sanitize function for blockElements list with invalid values}
-PASS SanitizerAPI with config: allowElements list ["p"]., sanitize function for allowElements list ["p"].
-PASS SanitizerAPI with config: allowElements list has no influence to dropElements., sanitize function for allowElements list has no influence to dropElements.
-PASS SanitizerAPI with config: dropAttributes list {"style": ["p"]} with style attribute, sanitize function for dropAttributes list {"style": ["p"]} with style attribute
-PASS SanitizerAPI with config: dropAttributes list {"*": ["a"]} with style attribute, sanitize function for dropAttributes list {"*": ["a"]} with style attribute
-PASS SanitizerAPI with config: empty dropAttributes list with id attribute, sanitize function for empty dropAttributes list with id attribute
-PASS SanitizerAPI with config: dropAttributes list {"id": ["*"]} with id attribute, sanitize function for dropAttributes list {"id": ["*"]} with id attribute
-PASS SanitizerAPI with config: dropAttributes list {"ID": ["*"]} with id attribute, sanitize function for dropAttributes list {"ID": ["*"]} with id attribute
-FAIL SanitizerAPI with config: dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access., sanitize function for dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access. assert_equals: expected "<p id=\"p\">Click.</p><script></script>" but got "<p id=\"p\">Click.</p>"
-PASS SanitizerAPI with config: allowAttributes list {"id": ["div"]} with id attribute, sanitize function for allowAttributes list {"id": ["div"]} with id attribute
-PASS SanitizerAPI with config: allowAttributes list {"id": ["*"]} with id attribute and onclick scripts, sanitize function for allowAttributes list {"id": ["*"]} with id attribute and onclick scripts
-PASS SanitizerAPI with config: allowAttributes list {"*": ["a"]} with style attribute, sanitize function for allowAttributes list {"*": ["a"]} with style attribute
-PASS SanitizerAPI with config: allowAttributes list has no influence to dropAttributes, sanitize function for allowAttributes list has no influence to dropAttributes
+PASS SanitizerAPI sanitize function for null.
+PASS SanitizerAPI with config: string, sanitize from string function for string
+PASS SanitizerAPI with config: html fragment, sanitize from string function for html fragment
+PASS SanitizerAPI with config: broken html, sanitize from string function for broken html
+PASS SanitizerAPI with config: empty object, sanitize from string function for empty object
+PASS SanitizerAPI with config: number, sanitize from string function for number
+PASS SanitizerAPI with config: zeros, sanitize from string function for zeros
+PASS SanitizerAPI with config: arithmetic, sanitize from string function for arithmetic
+PASS SanitizerAPI with config: empty string, sanitize from string function for empty string
+PASS SanitizerAPI with config: undefined, sanitize from string function for undefined
+PASS SanitizerAPI with config: document, sanitize from string function for document
+PASS SanitizerAPI with config: html without close tag, sanitize from string function for html without close tag
+PASS SanitizerAPI with config: scripts for default configs, sanitize from string function for scripts for default configs
+PASS SanitizerAPI with config: onclick scripts, sanitize from string function for onclick scripts
+PASS SanitizerAPI with config: invalid config_input, sanitize from string function for invalid config_input
+PASS SanitizerAPI with config: empty dropElements list, sanitize from string function for empty dropElements list
+PASS SanitizerAPI with config: test html without close tag with dropElements list ['div'], sanitize from string function for test html without close tag with dropElements list ['div']
+PASS SanitizerAPI with config: test script with ["script"] as dropElements list, sanitize from string function for test script with ["script"] as dropElements list
+PASS SanitizerAPI with config: dropElements list ["test", "i"]}, sanitize from string function for dropElements list ["test", "i"]}
+PASS SanitizerAPI with config: dropElements list ["I", "AM"]}, sanitize from string function for dropElements list ["I", "AM"]}
+PASS SanitizerAPI with config: dropElements list ["am", "p"]}, sanitize from string function for dropElements list ["am", "p"]}
+PASS SanitizerAPI with config: dropElements list with invalid values}, sanitize from string function for dropElements list with invalid values}
+PASS SanitizerAPI with config: blockElements list with invalid values}, sanitize from string function for blockElements list with invalid values}
+PASS SanitizerAPI with config: allowElements list ["p"]., sanitize from string function for allowElements list ["p"].
+PASS SanitizerAPI with config: allowElements list has no influence to dropElements., sanitize from string function for allowElements list has no influence to dropElements.
+PASS SanitizerAPI with config: dropAttributes list {"style": ["p"]} with style attribute, sanitize from string function for dropAttributes list {"style": ["p"]} with style attribute
+PASS SanitizerAPI with config: dropAttributes list {"*": ["a"]} with style attribute, sanitize from string function for dropAttributes list {"*": ["a"]} with style attribute
+PASS SanitizerAPI with config: empty dropAttributes list with id attribute, sanitize from string function for empty dropAttributes list with id attribute
+PASS SanitizerAPI with config: dropAttributes list {"id": ["*"]} with id attribute, sanitize from string function for dropAttributes list {"id": ["*"]} with id attribute
+PASS SanitizerAPI with config: dropAttributes list {"ID": ["*"]} with id attribute, sanitize from string function for dropAttributes list {"ID": ["*"]} with id attribute
+FAIL SanitizerAPI with config: dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access., sanitize from string function for dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access. assert_equals: expected "<p id=\"p\">Click.</p><script></script>" but got "<p id=\"p\">Click.</p>"
+PASS SanitizerAPI with config: allowAttributes list {"id": ["div"]} with id attribute, sanitize from string function for allowAttributes list {"id": ["div"]} with id attribute
+PASS SanitizerAPI with config: allowAttributes list {"id": ["*"]} with id attribute and onclick scripts, sanitize from string function for allowAttributes list {"id": ["*"]} with id attribute and onclick scripts
+PASS SanitizerAPI with config: allowAttributes list {"*": ["a"]} with style attribute, sanitize from string function for allowAttributes list {"*": ["a"]} with style attribute
+PASS SanitizerAPI with config: allowAttributes list has no influence to dropAttributes, sanitize from string function for allowAttributes list has no influence to dropAttributes
+PASS SanitizerAPI with config: string, sanitize from document function for string
+PASS SanitizerAPI with config: html fragment, sanitize from document function for html fragment
+PASS SanitizerAPI with config: broken html, sanitize from document function for broken html
+PASS SanitizerAPI with config: empty object, sanitize from document function for empty object
+PASS SanitizerAPI with config: number, sanitize from document function for number
+PASS SanitizerAPI with config: zeros, sanitize from document function for zeros
+PASS SanitizerAPI with config: arithmetic, sanitize from document function for arithmetic
+PASS SanitizerAPI with config: empty string, sanitize from document function for empty string
+PASS SanitizerAPI with config: undefined, sanitize from document function for undefined
+PASS SanitizerAPI with config: document, sanitize from document function for document
+PASS SanitizerAPI with config: html without close tag, sanitize from document function for html without close tag
+PASS SanitizerAPI with config: scripts for default configs, sanitize from document function for scripts for default configs
+PASS SanitizerAPI with config: onclick scripts, sanitize from document function for onclick scripts
+PASS SanitizerAPI with config: invalid config_input, sanitize from document function for invalid config_input
+PASS SanitizerAPI with config: empty dropElements list, sanitize from document function for empty dropElements list
+PASS SanitizerAPI with config: test html without close tag with dropElements list ['div'], sanitize from document function for test html without close tag with dropElements list ['div']
+PASS SanitizerAPI with config: test script with ["script"] as dropElements list, sanitize from document function for test script with ["script"] as dropElements list
+PASS SanitizerAPI with config: dropElements list ["test", "i"]}, sanitize from document function for dropElements list ["test", "i"]}
+PASS SanitizerAPI with config: dropElements list ["I", "AM"]}, sanitize from document function for dropElements list ["I", "AM"]}
+PASS SanitizerAPI with config: dropElements list ["am", "p"]}, sanitize from document function for dropElements list ["am", "p"]}
+PASS SanitizerAPI with config: dropElements list with invalid values}, sanitize from document function for dropElements list with invalid values}
+PASS SanitizerAPI with config: blockElements list with invalid values}, sanitize from document function for blockElements list with invalid values}
+PASS SanitizerAPI with config: allowElements list ["p"]., sanitize from document function for allowElements list ["p"].
+PASS SanitizerAPI with config: allowElements list has no influence to dropElements., sanitize from document function for allowElements list has no influence to dropElements.
+PASS SanitizerAPI with config: dropAttributes list {"style": ["p"]} with style attribute, sanitize from document function for dropAttributes list {"style": ["p"]} with style attribute
+PASS SanitizerAPI with config: dropAttributes list {"*": ["a"]} with style attribute, sanitize from document function for dropAttributes list {"*": ["a"]} with style attribute
+PASS SanitizerAPI with config: empty dropAttributes list with id attribute, sanitize from document function for empty dropAttributes list with id attribute
+PASS SanitizerAPI with config: dropAttributes list {"id": ["*"]} with id attribute, sanitize from document function for dropAttributes list {"id": ["*"]} with id attribute
+PASS SanitizerAPI with config: dropAttributes list {"ID": ["*"]} with id attribute, sanitize from document function for dropAttributes list {"ID": ["*"]} with id attribute
+FAIL SanitizerAPI with config: dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access., sanitize from document function for dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access. assert_equals: expected "<p id=\"p\">Click.</p><script></script>" but got "<p id=\"p\">Click.</p>"
+PASS SanitizerAPI with config: allowAttributes list {"id": ["div"]} with id attribute, sanitize from document function for allowAttributes list {"id": ["div"]} with id attribute
+PASS SanitizerAPI with config: allowAttributes list {"id": ["*"]} with id attribute and onclick scripts, sanitize from document function for allowAttributes list {"id": ["*"]} with id attribute and onclick scripts
+PASS SanitizerAPI with config: allowAttributes list {"*": ["a"]} with style attribute, sanitize from document function for allowAttributes list {"*": ["a"]} with style attribute
+PASS SanitizerAPI with config: allowAttributes list has no influence to dropAttributes, sanitize from document function for allowAttributes list has no influence to dropAttributes
+PASS SanitizerAPI with config: string, sanitize from document fragment function for string
+PASS SanitizerAPI with config: html fragment, sanitize from document fragment function for html fragment
+PASS SanitizerAPI with config: broken html, sanitize from document fragment function for broken html
+PASS SanitizerAPI with config: empty object, sanitize from document fragment function for empty object
+PASS SanitizerAPI with config: number, sanitize from document fragment function for number
+PASS SanitizerAPI with config: zeros, sanitize from document fragment function for zeros
+PASS SanitizerAPI with config: arithmetic, sanitize from document fragment function for arithmetic
+PASS SanitizerAPI with config: empty string, sanitize from document fragment function for empty string
+PASS SanitizerAPI with config: undefined, sanitize from document fragment function for undefined
+PASS SanitizerAPI with config: document, sanitize from document fragment function for document
+PASS SanitizerAPI with config: html without close tag, sanitize from document fragment function for html without close tag
+PASS SanitizerAPI with config: scripts for default configs, sanitize from document fragment function for scripts for default configs
+PASS SanitizerAPI with config: onclick scripts, sanitize from document fragment function for onclick scripts
+PASS SanitizerAPI with config: invalid config_input, sanitize from document fragment function for invalid config_input
+PASS SanitizerAPI with config: empty dropElements list, sanitize from document fragment function for empty dropElements list
+PASS SanitizerAPI with config: test html without close tag with dropElements list ['div'], sanitize from document fragment function for test html without close tag with dropElements list ['div']
+PASS SanitizerAPI with config: test script with ["script"] as dropElements list, sanitize from document fragment function for test script with ["script"] as dropElements list
+PASS SanitizerAPI with config: dropElements list ["test", "i"]}, sanitize from document fragment function for dropElements list ["test", "i"]}
+PASS SanitizerAPI with config: dropElements list ["I", "AM"]}, sanitize from document fragment function for dropElements list ["I", "AM"]}
+PASS SanitizerAPI with config: dropElements list ["am", "p"]}, sanitize from document fragment function for dropElements list ["am", "p"]}
+PASS SanitizerAPI with config: dropElements list with invalid values}, sanitize from document fragment function for dropElements list with invalid values}
+PASS SanitizerAPI with config: blockElements list with invalid values}, sanitize from document fragment function for blockElements list with invalid values}
+PASS SanitizerAPI with config: allowElements list ["p"]., sanitize from document fragment function for allowElements list ["p"].
+PASS SanitizerAPI with config: allowElements list has no influence to dropElements., sanitize from document fragment function for allowElements list has no influence to dropElements.
+PASS SanitizerAPI with config: dropAttributes list {"style": ["p"]} with style attribute, sanitize from document fragment function for dropAttributes list {"style": ["p"]} with style attribute
+PASS SanitizerAPI with config: dropAttributes list {"*": ["a"]} with style attribute, sanitize from document fragment function for dropAttributes list {"*": ["a"]} with style attribute
+PASS SanitizerAPI with config: empty dropAttributes list with id attribute, sanitize from document fragment function for empty dropAttributes list with id attribute
+PASS SanitizerAPI with config: dropAttributes list {"id": ["*"]} with id attribute, sanitize from document fragment function for dropAttributes list {"id": ["*"]} with id attribute
+PASS SanitizerAPI with config: dropAttributes list {"ID": ["*"]} with id attribute, sanitize from document fragment function for dropAttributes list {"ID": ["*"]} with id attribute
+FAIL SanitizerAPI with config: dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access., sanitize from document fragment function for dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access. assert_equals: expected "<p id=\"p\">Click.</p><script></script>" but got "<p id=\"p\">Click.</p>"
+PASS SanitizerAPI with config: allowAttributes list {"id": ["div"]} with id attribute, sanitize from document fragment function for allowAttributes list {"id": ["div"]} with id attribute
+PASS SanitizerAPI with config: allowAttributes list {"id": ["*"]} with id attribute and onclick scripts, sanitize from document fragment function for allowAttributes list {"id": ["*"]} with id attribute and onclick scripts
+PASS SanitizerAPI with config: allowAttributes list {"*": ["a"]} with style attribute, sanitize from document fragment function for allowAttributes list {"*": ["a"]} with style attribute
+PASS SanitizerAPI with config: allowAttributes list has no influence to dropAttributes, sanitize from document fragment function for allowAttributes list has no influence to dropAttributes
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/wpt_internal/sanitizer-api/sanitizer-sanitize.tentative.html b/third_party/blink/web_tests/wpt_internal/sanitizer-api/sanitizer-sanitize.tentative.html
index ee9290e..f3eb17e8 100644
--- a/third_party/blink/web_tests/wpt_internal/sanitizer-api/sanitizer-sanitize.tentative.html
+++ b/third_party/blink/web_tests/wpt_internal/sanitizer-api/sanitizer-sanitize.tentative.html
@@ -19,12 +19,46 @@
       assert_throws_js(TypeError, _ => s.sanitize());
     }, "SanitizerAPI sanitize function without argument should throw an error.");
 
+    test(t => {
+      let s = new Sanitizer({});
+      fragment = s.sanitize(null);
+      assert_true(fragment instanceof DocumentFragment);
+      assert_equals(getString(fragment), "null");
+    }, "SanitizerAPI sanitize function for null.");
+
     testcases.forEach(c => test(t => {
         let s = new Sanitizer(c.config_input);
         fragment = s.sanitize(c.value);
         assert_true(fragment instanceof DocumentFragment);
         assert_equals(getString(fragment), c.result);
-    }, "SanitizerAPI with config: " + c.message + ", sanitize function for " + c.message));
+    }, "SanitizerAPI with config: " + c.message + ", sanitize from string function for " + c.message));
+
+    testcases.forEach(c => test(t => {
+        let s = new Sanitizer(c.config_input);
+        var dom = document.implementation.createHTMLDocument();
+        dom.documentElement.innerHTML = c.value;
+        fragment = s.sanitize(dom);
+        assert_true(fragment instanceof DocumentFragment);
+
+        let result = getString(fragment);
+        // Remove <html> and </html>
+        if (c.message != "document" && result.slice(0,12) == "<html><body>" && result.slice(result.length-14, result.length) == "</body></html>")
+          result = result.substr(12, result.length - 26);
+        if (c.message == "document") {
+          assert_equals(result, "<html><body>test</body></html>");
+        } else {
+          assert_equals(result, c.result);
+        }
+    }, "SanitizerAPI with config: " + c.message + ", sanitize from document function for " + c.message));
+
+    testcases.forEach(c => test(t => {
+        let s = new Sanitizer(c.config_input);
+        let tpl = document.createElement("template");
+        tpl.innerHTML = c.value;
+        fragment = s.sanitize(tpl.content);
+        assert_true(fragment instanceof DocumentFragment);
+        assert_equals(getString(fragment), c.result);
+    }, "SanitizerAPI with config: " + c.message + ", sanitize from document fragment function for " + c.message));
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/wpt_internal/sanitizer-api/sanitizer-sanitizeToString.tentative-expected.txt b/third_party/blink/web_tests/wpt_internal/sanitizer-api/sanitizer-sanitizeToString.tentative-expected.txt
index 31f98a96..9cecc41 100644
--- a/third_party/blink/web_tests/wpt_internal/sanitizer-api/sanitizer-sanitizeToString.tentative-expected.txt
+++ b/third_party/blink/web_tests/wpt_internal/sanitizer-api/sanitizer-sanitizeToString.tentative-expected.txt
@@ -1,39 +1,108 @@
 This is a testharness.js-based test.
+Found 104 tests; 101 PASS, 3 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS SanitizerAPI sanitize function without argument should throw an error.
-PASS SanitizerAPI config: string, sanitizeToString function for string
-PASS SanitizerAPI config: html fragment, sanitizeToString function for html fragment
-PASS SanitizerAPI config: broken html, sanitizeToString function for broken html
-PASS SanitizerAPI config: empty object, sanitizeToString function for empty object
-PASS SanitizerAPI config: number, sanitizeToString function for number
-PASS SanitizerAPI config: zeros, sanitizeToString function for zeros
-PASS SanitizerAPI config: arithmetic, sanitizeToString function for arithmetic
-PASS SanitizerAPI config: empty string, sanitizeToString function for empty string
-PASS SanitizerAPI config: undefined, sanitizeToString function for undefined
-PASS SanitizerAPI config: null, sanitizeToString function for null
-PASS SanitizerAPI config: document, sanitizeToString function for document
-PASS SanitizerAPI config: html without close tag, sanitizeToString function for html without close tag
-PASS SanitizerAPI config: scripts for default configs, sanitizeToString function for scripts for default configs
-PASS SanitizerAPI config: onclick scripts, sanitizeToString function for onclick scripts
-PASS SanitizerAPI config: invalid config_input, sanitizeToString function for invalid config_input
-PASS SanitizerAPI config: empty dropElements list, sanitizeToString function for empty dropElements list
-PASS SanitizerAPI config: test html without close tag with dropElements list ['div'], sanitizeToString function for test html without close tag with dropElements list ['div']
-PASS SanitizerAPI config: test script with ["script"] as dropElements list, sanitizeToString function for test script with ["script"] as dropElements list
-PASS SanitizerAPI config: dropElements list ["test", "i"]}, sanitizeToString function for dropElements list ["test", "i"]}
-PASS SanitizerAPI config: dropElements list ["I", "AM"]}, sanitizeToString function for dropElements list ["I", "AM"]}
-PASS SanitizerAPI config: dropElements list ["am", "p"]}, sanitizeToString function for dropElements list ["am", "p"]}
-PASS SanitizerAPI config: dropElements list with invalid values}, sanitizeToString function for dropElements list with invalid values}
-PASS SanitizerAPI config: blockElements list with invalid values}, sanitizeToString function for blockElements list with invalid values}
-PASS SanitizerAPI config: allowElements list ["p"]., sanitizeToString function for allowElements list ["p"].
-PASS SanitizerAPI config: allowElements list has no influence to dropElements., sanitizeToString function for allowElements list has no influence to dropElements.
-PASS SanitizerAPI config: dropAttributes list {"style": ["p"]} with style attribute, sanitizeToString function for dropAttributes list {"style": ["p"]} with style attribute
-PASS SanitizerAPI config: dropAttributes list {"*": ["a"]} with style attribute, sanitizeToString function for dropAttributes list {"*": ["a"]} with style attribute
-PASS SanitizerAPI config: empty dropAttributes list with id attribute, sanitizeToString function for empty dropAttributes list with id attribute
-PASS SanitizerAPI config: dropAttributes list {"id": ["*"]} with id attribute, sanitizeToString function for dropAttributes list {"id": ["*"]} with id attribute
-PASS SanitizerAPI config: dropAttributes list {"ID": ["*"]} with id attribute, sanitizeToString function for dropAttributes list {"ID": ["*"]} with id attribute
-FAIL SanitizerAPI config: dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access., sanitizeToString function for dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access. assert_equals: expected "<p id=\"p\">Click.</p><script></script>" but got "<p id=\"p\">Click.</p>"
-PASS SanitizerAPI config: allowAttributes list {"id": ["div"]} with id attribute, sanitizeToString function for allowAttributes list {"id": ["div"]} with id attribute
-PASS SanitizerAPI config: allowAttributes list {"id": ["*"]} with id attribute and onclick scripts, sanitizeToString function for allowAttributes list {"id": ["*"]} with id attribute and onclick scripts
-PASS SanitizerAPI config: allowAttributes list {"*": ["a"]} with style attribute, sanitizeToString function for allowAttributes list {"*": ["a"]} with style attribute
-PASS SanitizerAPI config: allowAttributes list has no influence to dropAttributes, sanitizeToString function for allowAttributes list has no influence to dropAttributes
+PASS SanitizerAPI sanitizeToString function for null.
+PASS SanitizerAPI config: string, sanitizeToString from string function for string
+PASS SanitizerAPI config: html fragment, sanitizeToString from string function for html fragment
+PASS SanitizerAPI config: broken html, sanitizeToString from string function for broken html
+PASS SanitizerAPI config: empty object, sanitizeToString from string function for empty object
+PASS SanitizerAPI config: number, sanitizeToString from string function for number
+PASS SanitizerAPI config: zeros, sanitizeToString from string function for zeros
+PASS SanitizerAPI config: arithmetic, sanitizeToString from string function for arithmetic
+PASS SanitizerAPI config: empty string, sanitizeToString from string function for empty string
+PASS SanitizerAPI config: undefined, sanitizeToString from string function for undefined
+PASS SanitizerAPI config: document, sanitizeToString from string function for document
+PASS SanitizerAPI config: html without close tag, sanitizeToString from string function for html without close tag
+PASS SanitizerAPI config: scripts for default configs, sanitizeToString from string function for scripts for default configs
+PASS SanitizerAPI config: onclick scripts, sanitizeToString from string function for onclick scripts
+PASS SanitizerAPI config: invalid config_input, sanitizeToString from string function for invalid config_input
+PASS SanitizerAPI config: empty dropElements list, sanitizeToString from string function for empty dropElements list
+PASS SanitizerAPI config: test html without close tag with dropElements list ['div'], sanitizeToString from string function for test html without close tag with dropElements list ['div']
+PASS SanitizerAPI config: test script with ["script"] as dropElements list, sanitizeToString from string function for test script with ["script"] as dropElements list
+PASS SanitizerAPI config: dropElements list ["test", "i"]}, sanitizeToString from string function for dropElements list ["test", "i"]}
+PASS SanitizerAPI config: dropElements list ["I", "AM"]}, sanitizeToString from string function for dropElements list ["I", "AM"]}
+PASS SanitizerAPI config: dropElements list ["am", "p"]}, sanitizeToString from string function for dropElements list ["am", "p"]}
+PASS SanitizerAPI config: dropElements list with invalid values}, sanitizeToString from string function for dropElements list with invalid values}
+PASS SanitizerAPI config: blockElements list with invalid values}, sanitizeToString from string function for blockElements list with invalid values}
+PASS SanitizerAPI config: allowElements list ["p"]., sanitizeToString from string function for allowElements list ["p"].
+PASS SanitizerAPI config: allowElements list has no influence to dropElements., sanitizeToString from string function for allowElements list has no influence to dropElements.
+PASS SanitizerAPI config: dropAttributes list {"style": ["p"]} with style attribute, sanitizeToString from string function for dropAttributes list {"style": ["p"]} with style attribute
+PASS SanitizerAPI config: dropAttributes list {"*": ["a"]} with style attribute, sanitizeToString from string function for dropAttributes list {"*": ["a"]} with style attribute
+PASS SanitizerAPI config: empty dropAttributes list with id attribute, sanitizeToString from string function for empty dropAttributes list with id attribute
+PASS SanitizerAPI config: dropAttributes list {"id": ["*"]} with id attribute, sanitizeToString from string function for dropAttributes list {"id": ["*"]} with id attribute
+PASS SanitizerAPI config: dropAttributes list {"ID": ["*"]} with id attribute, sanitizeToString from string function for dropAttributes list {"ID": ["*"]} with id attribute
+FAIL SanitizerAPI config: dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access., sanitizeToString from string function for dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access. assert_equals: expected "<p id=\"p\">Click.</p><script></script>" but got "<p id=\"p\">Click.</p>"
+PASS SanitizerAPI config: allowAttributes list {"id": ["div"]} with id attribute, sanitizeToString from string function for allowAttributes list {"id": ["div"]} with id attribute
+PASS SanitizerAPI config: allowAttributes list {"id": ["*"]} with id attribute and onclick scripts, sanitizeToString from string function for allowAttributes list {"id": ["*"]} with id attribute and onclick scripts
+PASS SanitizerAPI config: allowAttributes list {"*": ["a"]} with style attribute, sanitizeToString from string function for allowAttributes list {"*": ["a"]} with style attribute
+PASS SanitizerAPI config: allowAttributes list has no influence to dropAttributes, sanitizeToString from string function for allowAttributes list has no influence to dropAttributes
+PASS SanitizerAPI with config: string, sanitizeToString from document function for string
+PASS SanitizerAPI with config: html fragment, sanitizeToString from document function for html fragment
+PASS SanitizerAPI with config: broken html, sanitizeToString from document function for broken html
+PASS SanitizerAPI with config: empty object, sanitizeToString from document function for empty object
+PASS SanitizerAPI with config: number, sanitizeToString from document function for number
+PASS SanitizerAPI with config: zeros, sanitizeToString from document function for zeros
+PASS SanitizerAPI with config: arithmetic, sanitizeToString from document function for arithmetic
+PASS SanitizerAPI with config: empty string, sanitizeToString from document function for empty string
+PASS SanitizerAPI with config: undefined, sanitizeToString from document function for undefined
+PASS SanitizerAPI with config: document, sanitizeToString from document function for document
+PASS SanitizerAPI with config: html without close tag, sanitizeToString from document function for html without close tag
+PASS SanitizerAPI with config: scripts for default configs, sanitizeToString from document function for scripts for default configs
+PASS SanitizerAPI with config: onclick scripts, sanitizeToString from document function for onclick scripts
+PASS SanitizerAPI with config: invalid config_input, sanitizeToString from document function for invalid config_input
+PASS SanitizerAPI with config: empty dropElements list, sanitizeToString from document function for empty dropElements list
+PASS SanitizerAPI with config: test html without close tag with dropElements list ['div'], sanitizeToString from document function for test html without close tag with dropElements list ['div']
+PASS SanitizerAPI with config: test script with ["script"] as dropElements list, sanitizeToString from document function for test script with ["script"] as dropElements list
+PASS SanitizerAPI with config: dropElements list ["test", "i"]}, sanitizeToString from document function for dropElements list ["test", "i"]}
+PASS SanitizerAPI with config: dropElements list ["I", "AM"]}, sanitizeToString from document function for dropElements list ["I", "AM"]}
+PASS SanitizerAPI with config: dropElements list ["am", "p"]}, sanitizeToString from document function for dropElements list ["am", "p"]}
+PASS SanitizerAPI with config: dropElements list with invalid values}, sanitizeToString from document function for dropElements list with invalid values}
+PASS SanitizerAPI with config: blockElements list with invalid values}, sanitizeToString from document function for blockElements list with invalid values}
+PASS SanitizerAPI with config: allowElements list ["p"]., sanitizeToString from document function for allowElements list ["p"].
+PASS SanitizerAPI with config: allowElements list has no influence to dropElements., sanitizeToString from document function for allowElements list has no influence to dropElements.
+PASS SanitizerAPI with config: dropAttributes list {"style": ["p"]} with style attribute, sanitizeToString from document function for dropAttributes list {"style": ["p"]} with style attribute
+PASS SanitizerAPI with config: dropAttributes list {"*": ["a"]} with style attribute, sanitizeToString from document function for dropAttributes list {"*": ["a"]} with style attribute
+PASS SanitizerAPI with config: empty dropAttributes list with id attribute, sanitizeToString from document function for empty dropAttributes list with id attribute
+PASS SanitizerAPI with config: dropAttributes list {"id": ["*"]} with id attribute, sanitizeToString from document function for dropAttributes list {"id": ["*"]} with id attribute
+PASS SanitizerAPI with config: dropAttributes list {"ID": ["*"]} with id attribute, sanitizeToString from document function for dropAttributes list {"ID": ["*"]} with id attribute
+FAIL SanitizerAPI with config: dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access., sanitizeToString from document function for dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access. assert_equals: expected "<p id=\"p\">Click.</p><script></script>" but got "<p id=\"p\">Click.</p>"
+PASS SanitizerAPI with config: allowAttributes list {"id": ["div"]} with id attribute, sanitizeToString from document function for allowAttributes list {"id": ["div"]} with id attribute
+PASS SanitizerAPI with config: allowAttributes list {"id": ["*"]} with id attribute and onclick scripts, sanitizeToString from document function for allowAttributes list {"id": ["*"]} with id attribute and onclick scripts
+PASS SanitizerAPI with config: allowAttributes list {"*": ["a"]} with style attribute, sanitizeToString from document function for allowAttributes list {"*": ["a"]} with style attribute
+PASS SanitizerAPI with config: allowAttributes list has no influence to dropAttributes, sanitizeToString from document function for allowAttributes list has no influence to dropAttributes
+PASS SanitizerAPI with config: string, sanitizeToString from document fragment function for string
+PASS SanitizerAPI with config: html fragment, sanitizeToString from document fragment function for html fragment
+PASS SanitizerAPI with config: broken html, sanitizeToString from document fragment function for broken html
+PASS SanitizerAPI with config: empty object, sanitizeToString from document fragment function for empty object
+PASS SanitizerAPI with config: number, sanitizeToString from document fragment function for number
+PASS SanitizerAPI with config: zeros, sanitizeToString from document fragment function for zeros
+PASS SanitizerAPI with config: arithmetic, sanitizeToString from document fragment function for arithmetic
+PASS SanitizerAPI with config: empty string, sanitizeToString from document fragment function for empty string
+PASS SanitizerAPI with config: undefined, sanitizeToString from document fragment function for undefined
+PASS SanitizerAPI with config: document, sanitizeToString from document fragment function for document
+PASS SanitizerAPI with config: html without close tag, sanitizeToString from document fragment function for html without close tag
+PASS SanitizerAPI with config: scripts for default configs, sanitizeToString from document fragment function for scripts for default configs
+PASS SanitizerAPI with config: onclick scripts, sanitizeToString from document fragment function for onclick scripts
+PASS SanitizerAPI with config: invalid config_input, sanitizeToString from document fragment function for invalid config_input
+PASS SanitizerAPI with config: empty dropElements list, sanitizeToString from document fragment function for empty dropElements list
+PASS SanitizerAPI with config: test html without close tag with dropElements list ['div'], sanitizeToString from document fragment function for test html without close tag with dropElements list ['div']
+PASS SanitizerAPI with config: test script with ["script"] as dropElements list, sanitizeToString from document fragment function for test script with ["script"] as dropElements list
+PASS SanitizerAPI with config: dropElements list ["test", "i"]}, sanitizeToString from document fragment function for dropElements list ["test", "i"]}
+PASS SanitizerAPI with config: dropElements list ["I", "AM"]}, sanitizeToString from document fragment function for dropElements list ["I", "AM"]}
+PASS SanitizerAPI with config: dropElements list ["am", "p"]}, sanitizeToString from document fragment function for dropElements list ["am", "p"]}
+PASS SanitizerAPI with config: dropElements list with invalid values}, sanitizeToString from document fragment function for dropElements list with invalid values}
+PASS SanitizerAPI with config: blockElements list with invalid values}, sanitizeToString from document fragment function for blockElements list with invalid values}
+PASS SanitizerAPI with config: allowElements list ["p"]., sanitizeToString from document fragment function for allowElements list ["p"].
+PASS SanitizerAPI with config: allowElements list has no influence to dropElements., sanitizeToString from document fragment function for allowElements list has no influence to dropElements.
+PASS SanitizerAPI with config: dropAttributes list {"style": ["p"]} with style attribute, sanitizeToString from document fragment function for dropAttributes list {"style": ["p"]} with style attribute
+PASS SanitizerAPI with config: dropAttributes list {"*": ["a"]} with style attribute, sanitizeToString from document fragment function for dropAttributes list {"*": ["a"]} with style attribute
+PASS SanitizerAPI with config: empty dropAttributes list with id attribute, sanitizeToString from document fragment function for empty dropAttributes list with id attribute
+PASS SanitizerAPI with config: dropAttributes list {"id": ["*"]} with id attribute, sanitizeToString from document fragment function for dropAttributes list {"id": ["*"]} with id attribute
+PASS SanitizerAPI with config: dropAttributes list {"ID": ["*"]} with id attribute, sanitizeToString from document fragment function for dropAttributes list {"ID": ["*"]} with id attribute
+FAIL SanitizerAPI with config: dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access., sanitizeToString from document fragment function for dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access. assert_equals: expected "<p id=\"p\">Click.</p><script></script>" but got "<p id=\"p\">Click.</p>"
+PASS SanitizerAPI with config: allowAttributes list {"id": ["div"]} with id attribute, sanitizeToString from document fragment function for allowAttributes list {"id": ["div"]} with id attribute
+PASS SanitizerAPI with config: allowAttributes list {"id": ["*"]} with id attribute and onclick scripts, sanitizeToString from document fragment function for allowAttributes list {"id": ["*"]} with id attribute and onclick scripts
+PASS SanitizerAPI with config: allowAttributes list {"*": ["a"]} with style attribute, sanitizeToString from document fragment function for allowAttributes list {"*": ["a"]} with style attribute
+PASS SanitizerAPI with config: allowAttributes list has no influence to dropAttributes, sanitizeToString from document fragment function for allowAttributes list has no influence to dropAttributes
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/wpt_internal/sanitizer-api/sanitizer-sanitizeToString.tentative.html b/third_party/blink/web_tests/wpt_internal/sanitizer-api/sanitizer-sanitizeToString.tentative.html
index 6aaff8e8..78d8d994 100644
--- a/third_party/blink/web_tests/wpt_internal/sanitizer-api/sanitizer-sanitizeToString.tentative.html
+++ b/third_party/blink/web_tests/wpt_internal/sanitizer-api/sanitizer-sanitizeToString.tentative.html
@@ -13,10 +13,38 @@
       assert_throws_js(TypeError, _ => s.sanitizeToString());
     }, "SanitizerAPI sanitize function without argument should throw an error.");
 
+    test(t => {
+      let s = new Sanitizer({});
+      fragment = s.sanitize(null);
+        assert_equals(s.sanitizeToString(null), "null");
+    }, "SanitizerAPI sanitizeToString function for null.");
+
     testcases.forEach(c => test(t => {
         let s = new Sanitizer(c.config_input);
         assert_equals(s.sanitizeToString(c.value), c.result);
-    }, "SanitizerAPI config: " + c.message + ", sanitizeToString function for " + c.message));
+    }, "SanitizerAPI config: " + c.message + ", sanitizeToString from string function for " + c.message));
+
+    testcases.forEach(c => test(t => {
+        let s = new Sanitizer(c.config_input);
+        var dom = document.implementation.createHTMLDocument();
+        dom.documentElement.innerHTML = c.value;
+        let result = s.sanitizeToString(dom);
+        // Remove <html> and </html>
+        if (c.message != "document" && result.slice(0,12) == "<html><body>" && result.slice(result.length-14, result.length) == "</body></html>")
+          result = result.substr(12, result.length - 26);
+        if (c.message == "document") {
+          assert_equals(result, "<html><body>test</body></html>");
+        } else {
+          assert_equals(result, c.result);
+        }
+    }, "SanitizerAPI with config: " + c.message + ", sanitizeToString from document function for " + c.message));
+
+    testcases.forEach(c => test(t => {
+        let s = new Sanitizer(c.config_input);
+        let tpl = document.createElement("template");
+        tpl.innerHTML = c.value;
+        assert_equals(s.sanitizeToString(tpl.content), c.result);
+    }, "SanitizerAPI with config: " + c.message + ", sanitizeToString from document fragment function for " + c.message));
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/wpt_internal/sanitizer-api/support/testcases.sub.js b/third_party/blink/web_tests/wpt_internal/sanitizer-api/support/testcases.sub.js
index 9886ded..90b5c605 100644
--- a/third_party/blink/web_tests/wpt_internal/sanitizer-api/support/testcases.sub.js
+++ b/third_party/blink/web_tests/wpt_internal/sanitizer-api/support/testcases.sub.js
@@ -8,7 +8,6 @@
   {config_input: {}, value: 1+2, result: "3", message: "arithmetic"},
   {config_input: {}, value: "", result: "", message: "empty string"},
   {config_input: {}, value: undefined, result: "undefined", message: "undefined"},
-  {config_input: {}, value: null, result: "null", message: "null"},
   {config_input: {}, value: "<html><head></head><body>test</body></html>", result: "test", message: "document"},
   {config_input: {}, value: "<div>test", result: "<div>test</div>", message: "html without close tag"},
   {config_input: {}, value: "<script>alert('i am a test')<\/script>", result: "", message: "scripts for default configs"},
diff --git a/third_party/byte_buddy/BUILD.gn b/third_party/byte_buddy/BUILD.gn
index 66d5512..5b112565 100644
--- a/third_party/byte_buddy/BUILD.gn
+++ b/third_party/byte_buddy/BUILD.gn
@@ -8,6 +8,7 @@
   testonly = true
   supports_android = true
   enable_bytecode_checks = false
+  enable_desugar = false
   jar_path = "lib/byte-buddy.jar"
 }
 
@@ -15,6 +16,7 @@
   testonly = true
   supports_android = true
   enable_bytecode_checks = false
+  enable_desugar = false
   jar_path = "lib/byte-buddy-agent.jar"
 }
 
@@ -25,12 +27,14 @@
   supports_android = true
   requires_android = true
   no_build_hooks = true
+  enable_desugar = false
   jar_path = "android_sdk_build_tools_25_0_2/build-tools/25.0.2/lib/dx.jar"
 }
 
 android_java_prebuilt("byte_buddy_android_java") {
   testonly = true
   enable_bytecode_checks = false
+  enable_desugar = false
   deps = [ ":dx_25_0_2_java" ]
   proguard_configs = [ "//third_party/byte_buddy/proguard.flags" ]
   jar_path = "lib/byte-buddy-android.jar"
diff --git a/third_party/closure_compiler/externs/accessibility_private.js b/third_party/closure_compiler/externs/accessibility_private.js
index 45c952be..25760b6 100644
--- a/third_party/closure_compiler/externs/accessibility_private.js
+++ b/third_party/closure_compiler/externs/accessibility_private.js
@@ -196,6 +196,13 @@
 };
 
 /**
+ * @enum {string}
+ */
+chrome.accessibilityPrivate.AccessibilityFeature = {
+  SELECT_TO_SPEAK_NAVIGATION_CONTROL: 'selectToSpeakNavigationControl',
+};
+
+/**
  * Called to translate localeCodeToTranslate into human-readable string in the
  * locale specified by displayLocaleCode
  * @param {string} localeCodeToTranslate
@@ -359,6 +366,13 @@
 chrome.accessibilityPrivate.performAcceleratorAction = function(acceleratorAction) {};
 
 /**
+ * Checks to see if an accessibility feature is enabled.
+ * @param {!chrome.accessibilityPrivate.AccessibilityFeature} feature
+ * @param {function(boolean): void} callback Returns whether feature is enabled.
+ */
+chrome.accessibilityPrivate.isFeatureEnabled = function(feature, callback) {};
+
+/**
  * Fired whenever ChromeVox should output introduction.
  * @type {!ChromeEvent}
  */
diff --git a/third_party/google-truth/BUILD.gn b/third_party/google-truth/BUILD.gn
index 5d57221..dfcc9d10 100644
--- a/third_party/google-truth/BUILD.gn
+++ b/third_party/google-truth/BUILD.gn
@@ -9,6 +9,7 @@
 
   # Uses the difflib package, which doesn't exist in third_party.
   enable_bytecode_checks = false
+  enable_desugar = false
   supports_android = true
 
   # requires_android because of dependency on guava_android.
diff --git a/third_party/win_build_output/midl/remoting/host/win/arm64/chromoting_lib.h b/third_party/win_build_output/midl/remoting/host/win/arm64/chromoting_lib.h
index d498cf6..74beaff 100644
--- a/third_party/win_build_output/midl/remoting/host/win/arm64/chromoting_lib.h
+++ b/third_party/win_build_output/midl/remoting/host/win/arm64/chromoting_lib.h
@@ -304,7 +304,7 @@
 

 #ifdef __cplusplus

 

-class DECLSPEC_UUID("7bf898db-ce6c-57a3-a473-3aa21bf8c4c4")

+class DECLSPEC_UUID("6741fd0a-6a8a-5838-a35e-8088697e2088")

 RdpDesktopSession;

 #endif

 #endif /* __ChromotingLib_LIBRARY_DEFINED__ */

diff --git a/third_party/win_build_output/midl/remoting/host/win/arm64/chromoting_lib.tlb b/third_party/win_build_output/midl/remoting/host/win/arm64/chromoting_lib.tlb
index 0a7f3139..01bf6f0 100644
--- a/third_party/win_build_output/midl/remoting/host/win/arm64/chromoting_lib.tlb
+++ b/third_party/win_build_output/midl/remoting/host/win/arm64/chromoting_lib.tlb
Binary files differ
diff --git a/third_party/win_build_output/midl/remoting/host/win/arm64/chromoting_lib_i.c b/third_party/win_build_output/midl/remoting/host/win/arm64/chromoting_lib_i.c
index 7172c90..da95fe85 100644
--- a/third_party/win_build_output/midl/remoting/host/win/arm64/chromoting_lib_i.c
+++ b/third_party/win_build_output/midl/remoting/host/win/arm64/chromoting_lib_i.c
@@ -76,7 +76,7 @@
 MIDL_DEFINE_GUID(IID, LIBID_ChromotingLib,0xb6396c45,0xb0cc,0x456b,0x9f,0x49,0xf1,0x29,0x64,0xee,0x6d,0xf4);

 

 

-MIDL_DEFINE_GUID(CLSID, CLSID_RdpDesktopSession,0x7bf898db,0xce6c,0x57a3,0xa4,0x73,0x3a,0xa2,0x1b,0xf8,0xc4,0xc4);

+MIDL_DEFINE_GUID(CLSID, CLSID_RdpDesktopSession,0x6741fd0a,0x6a8a,0x5838,0xa3,0x5e,0x80,0x88,0x69,0x7e,0x20,0x88);

 

 #undef MIDL_DEFINE_GUID

 

diff --git a/tools/clang/scripts/upload_revision.py b/tools/clang/scripts/upload_revision.py
index f20cb6ab..6f68fb4 100755
--- a/tools/clang/scripts/upload_revision.py
+++ b/tools/clang/scripts/upload_revision.py
@@ -29,7 +29,9 @@
 # Keep lines in here at <= 72 columns, else they wrap in gerrit.
 COMMIT_FOOTER = \
 '''
-Bug: TODO
+Bug: TODO. Remove the Tricium: line below when filling this in.
+Tricium: skip
+
 Cq-Include-Trybots: chromium/try:chromeos-amd64-generic-cfi-thin-lto-rel
 Cq-Include-Trybots: chromium/try:dawn-win10-x86-deps-rel
 Cq-Include-Trybots: chromium/try:linux-chromeos-dbg
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 4fa7c7dc..3114bd52 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -25190,6 +25190,7 @@
   <int value="1523" label="CHROMEOSINFOPRIVATE_ISTABLETMODEENABLED"/>
   <int value="1524"
       label="FILEMANAGERPRIVATEINTERNAL_GETARCDOCUMENTSPROVIDERTHUMBNAIL"/>
+  <int value="1525" label="ACCESSIBILITY_PRIVATE_ISFEATUREENABLED"/>
 </enum>
 
 <enum name="ExtensionIconState">
diff --git a/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml b/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml
index 6ecf22a9..9327d61c 100644
--- a/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml
@@ -333,6 +333,9 @@
 
 <histogram name="ChromeOS.GAIA.AuthenticatorContentWindowNull" enum="Boolean"
     expires_after="M85">
+  <obsolete>
+    Removed 2020-10.
+  </obsolete>
   <owner>wjmaclean@chromium.org</owner>
   <summary>
     Whether the GAIA Authenticator unexpectedly encountered a null contentWindow
diff --git a/tools/metrics/histograms/histograms_xml/compositing/histograms.xml b/tools/metrics/histograms/histograms_xml/compositing/histograms.xml
index 83087fd..de0ba38 100644
--- a/tools/metrics/histograms/histograms_xml/compositing/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/compositing/histograms.xml
@@ -587,6 +587,9 @@
 
 <histogram name="Compositing.SurfaceDependencyDeadline.Duration" units="ms"
     expires_after="2020-12-01">
+  <obsolete>
+    Expired October 2020.
+  </obsolete>
   <owner>jonross@chromium.org</owner>
   <owner>kylechar@chromium.org</owner>
   <summary>
@@ -598,6 +601,9 @@
 
 <histogram name="Compositing.SurfaceManager.AliveSurfaces" units="surfaces"
     expires_after="2020-12-01">
+  <obsolete>
+    Expired October 2020.
+  </obsolete>
   <owner>jonross@chromium.org</owner>
   <owner>kylechar@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/content/histograms.xml b/tools/metrics/histograms/histograms_xml/content/histograms.xml
index f3c9a1c..9dde809 100644
--- a/tools/metrics/histograms/histograms_xml/content/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/content/histograms.xml
@@ -904,11 +904,23 @@
 
 <histogram name="ContentSuggestions.Feed.NoticeCardFulfilled" enum="Boolean"
     expires_after="2021-03-07">
-  <owner>frechette@chromium.org</owner>
+  <owner>vincb@google.com</owner>
   <owner>feed@chromium.org</owner>
   <summary>
-    Android: Whether the notice card for feed action reporting has been
-    fulfilled.
+    Android: Reports whether the notice card for feed action reporting has been
+    fulfilled. Recorded when reading the response content of the feed query that
+    is successful (includes both load stream and load more queries).
+  </summary>
+</histogram>
+
+<histogram name="ContentSuggestions.Feed.NoticeCardFulfilled2" enum="Boolean"
+    expires_after="2021-06-16">
+  <owner>vincb@google.com</owner>
+  <owner>feed@chromium.org</owner>
+  <summary>
+    Android: Reports whether the notice card for feed action reporting has been
+    fulfilled. Recorded when reading the response content of the load stream
+    query that is successful.
   </summary>
 </histogram>
 
diff --git a/tools/metrics/histograms/histograms_xml/extensions/histograms.xml b/tools/metrics/histograms/histograms_xml/extensions/histograms.xml
index 42c5b7bc..55d25c3 100644
--- a/tools/metrics/histograms/histograms_xml/extensions/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/extensions/histograms.xml
@@ -1721,6 +1721,17 @@
   </summary>
 </histogram>
 
+<histogram name="Extensions.ForceToolbarPinnedCount" units="extensions"
+    expires_after="2021-03-01">
+  <owner>nicolaso@chromium.org</owner>
+  <owner>chrome-enterprise-team-core@google.com</owner>
+  <summary>
+    Number of extensions that are &quot;force-pinned&quot; in the
+    ExtensionSettings policy. Recorded after policies are parsed, or refreshed.
+    Only recorded if non-zero.
+  </summary>
+</histogram>
+
 <histogram name="Extensions.FromWebstoreInconsistency"
     enum="ExtensionFromWebstoreInconcistencyEnum" expires_after="2018-08-30">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
diff --git a/tools/metrics/histograms/histograms_xml/omnibox/histograms.xml b/tools/metrics/histograms/histograms_xml/omnibox/histograms.xml
index a3bed22..6c93bc4 100644
--- a/tools/metrics/histograms/histograms_xml/omnibox/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/omnibox/histograms.xml
@@ -350,6 +350,9 @@
 
 <histogram name="Omnibox.IconOrFaviconShown" enum="SuggestionIconOrFaviconType"
     expires_after="M83">
+  <obsolete>
+    Removed 2020-10.
+  </obsolete>
   <owner>ender@chromium.org</owner>
   <owner>jdonnelly@chromium.org</owner>
   <owner>mpearson@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/phonehub/histograms.xml b/tools/metrics/histograms/histograms_xml/phonehub/histograms.xml
index e3dc40a..1efe632 100644
--- a/tools/metrics/histograms/histograms_xml/phonehub/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/phonehub/histograms.xml
@@ -5,7 +5,7 @@
 -->
 
 <!--
-This file is used to generate a comprehensive list of WebLayer histograms
+This file is used to generate a comprehensive list of PhoneHub histograms
 along with a detailed description for each histogram.
 
 For best practices on writing histogram descriptions, see
diff --git a/tools/metrics/histograms/histograms_xml/session/histograms.xml b/tools/metrics/histograms/histograms_xml/session/histograms.xml
index a398c2c..20f7c89 100644
--- a/tools/metrics/histograms/histograms_xml/session/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/session/histograms.xml
@@ -421,6 +421,9 @@
 
 <histogram name="Session.WebStates.ForwardItemsCountAfterNavigation"
     units="items" expires_after="2020-12-01">
+  <obsolete>
+    Removed 10/2020.
+  </obsolete>
   <owner>ajuma@chromium.org</owner>
   <owner>eugenebut@chromium.org</owner>
   <owner>gambard@chromium.org</owner>
@@ -435,6 +438,9 @@
 
 <histogram name="Session.WebStates.HasForwardItemsAfterNavigation"
     enum="BooleanPresent" expires_after="2020-12-01">
+  <obsolete>
+    Removed 10/2020.
+  </obsolete>
   <owner>ajuma@chromium.org</owner>
   <owner>eugenebut@chromium.org</owner>
   <owner>gambard@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml b/tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml
index 1c6a1f4..fe07239 100644
--- a/tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml
@@ -1310,6 +1310,7 @@
 <histogram name="WebRTC.PeerConnection.SdpFormatReceived"
     enum="PeerConnectionSdpFormatReceived" expires_after="2021-04-04">
   <owner>steveanton@chromium.org</owner>
+  <owner>hta@chromium.org</owner>
   <summary>
     What SDP format is received in the remote offer. The value &quot;no
     tracks&quot; means that no audio or video tracks were received. The value
@@ -1318,6 +1319,18 @@
     or more than one video track was received, and how this was signaled is
     indicated (&quot;Plan B&quot; meaning with a=ssrc lines within the same m=
     section and &quot;Unified Plan&quot; meaning with a separate m= section).
+    This is recorded when calling setRemoteDescription with an SDP Offer.
+  </summary>
+</histogram>
+
+<histogram name="WebRTC.PeerConnection.SdpFormatReceivedAnswer"
+    enum="PeerConnectionSdpFormatReceived" expires_after="2021-04-04">
+  <owner>steveanton@chromium.org</owner>
+  <owner>hta@chromium.org</owner>
+  <summary>
+    What SDP format is received in the remote answer. See
+    WebRTC.PeerConnection.SdpFormatReceived for the description of the values.
+    This is recorded when calling setRemoteDescription with an SDP Answer.
   </summary>
 </histogram>
 
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml
index cb543773..b6848f2 100644
--- a/tools/traffic_annotation/summary/annotations.xml
+++ b/tools/traffic_annotation/summary/annotations.xml
@@ -264,7 +264,6 @@
  <item id="ranker_url_fetcher" added_in_milestone="62" hash_code="95682324" type="0" content_hash_code="45958626" os_list="linux,windows" file_path="components/assist_ranker/ranker_url_fetcher.cc"/>
  <item id="rappor_report" added_in_milestone="62" hash_code="44606780" type="0" content_hash_code="111287826" os_list="linux,windows" file_path="components/rappor/log_uploader.cc"/>
  <item id="receive_messages_express" added_in_milestone="85" hash_code="29506140" type="0" deprecated="2020-09-21" content_hash_code="38581365" file_path=""/>
- <item id="recipe_tasks_service" added_in_milestone="88" hash_code="73597231" type="0" content_hash_code="31830923" os_list="linux,windows" file_path="chrome/browser/search/recipe_tasks/recipe_tasks_service.cc"/>
  <item id="refresh_token_annotation_request" added_in_milestone="62" hash_code="7433837" type="1" second_id="29188932" deprecated="2018-01-17" content_hash_code="137103383" file_path=""/>
  <item id="remote_copy_message_handler" added_in_milestone="80" hash_code="80255301" type="0" content_hash_code="117673331" os_list="linux,windows" file_path="chrome/browser/sharing/shared_clipboard/remote_copy_message_handler.cc"/>
  <item id="remote_suggestions_provider" added_in_milestone="62" hash_code="49544361" type="0" content_hash_code="126329742" os_list="linux,windows" file_path="components/ntp_snippets/remote/cached_image_fetcher.cc"/>
@@ -310,7 +309,6 @@
  <item id="service_worker_navigation_preload" added_in_milestone="63" hash_code="129872904" type="0" content_hash_code="79473248" os_list="linux,windows" file_path="content/browser/service_worker/service_worker_fetch_dispatcher.cc"/>
  <item id="service_worker_update_checker" added_in_milestone="71" hash_code="130931413" type="0" content_hash_code="46608086" os_list="linux,windows" file_path="content/browser/service_worker/service_worker_single_script_update_checker.cc"/>
  <item id="services_http_server_error_response" added_in_milestone="68" hash_code="59302801" type="0" content_hash_code="127774041" os_list="linux,windows" file_path="services/network/public/cpp/server/http_server.cc"/>
- <item id="shopping_tasks_service" added_in_milestone="87" hash_code="90297622" type="0" content_hash_code="133566501" os_list="windows,linux" file_path="chrome/browser/search/shopping_tasks/shopping_tasks_service.cc"/>
  <item id="sigined_exchange_cert_fetcher" added_in_milestone="66" hash_code="79442849" type="0" content_hash_code="8138156" os_list="linux,windows" file_path="content/browser/web_package/signed_exchange_cert_fetcher.cc"/>
  <item id="sigined_exchange_validity_pinger" added_in_milestone="75" hash_code="57114284" type="0" content_hash_code="119482488" os_list="linux,windows" file_path="content/browser/web_package/signed_exchange_validity_pinger.cc"/>
  <item id="signed_in_profile_avatar" added_in_milestone="62" hash_code="108903331" type="0" content_hash_code="72850619" os_list="linux,windows" file_path="chrome/browser/profiles/profile_downloader.cc"/>
@@ -335,6 +333,7 @@
  <item id="sync_file_system" added_in_milestone="62" hash_code="102819690" type="0" content_hash_code="52153962" os_list="linux,windows" file_path="chrome/browser/sync_file_system/drive_backend/sync_engine.cc"/>
  <item id="sync_http_bridge" added_in_milestone="62" hash_code="57144960" type="0" content_hash_code="32868346" os_list="linux,windows" file_path="components/sync/engine/net/http_bridge.cc"/>
  <item id="sync_stop_reporter" added_in_milestone="62" hash_code="5021348" type="0" content_hash_code="56902850" os_list="linux,windows" file_path="components/sync/driver/sync_stopped_reporter.cc"/>
+ <item id="task_module_service" added_in_milestone="88" hash_code="50808258" type="0" content_hash_code="12116330" os_list="linux,windows" file_path="chrome/browser/search/task_module/task_module_service.cc"/>
  <item id="test" added_in_milestone="62" hash_code="3556498" type="0" reserved="1" os_list="linux,windows" file_path=""/>
  <item id="test_partial" added_in_milestone="62" hash_code="22096011" type="0" reserved="1" os_list="linux,windows" file_path=""/>
  <item id="tethering_handler_socket" added_in_milestone="65" hash_code="113065062" type="0" content_hash_code="986296" os_list="linux,windows" file_path="content/browser/devtools/protocol/tethering_handler.cc"/>
diff --git a/tools/traffic_annotation/summary/grouping.xml b/tools/traffic_annotation/summary/grouping.xml
index 9e17428..00ba0421 100644
--- a/tools/traffic_annotation/summary/grouping.xml
+++ b/tools/traffic_annotation/summary/grouping.xml
@@ -393,8 +393,7 @@
       <traffic_annotation unique_id="search_suggest_service"/>
       <traffic_annotation unique_id="remote_suggestions_provider"/>
       <traffic_annotation unique_id="promo_service"/>
-      <traffic_annotation unique_id="recipe_tasks_service"/>
-      <traffic_annotation unique_id="shopping_tasks_service"/>
+      <traffic_annotation unique_id="task_module_service"/>
     </sender>
     <sender name="Speech Recognition">
       <traffic_annotation unique_id="speech_recognition_downstream"/>
diff --git a/ui/aura/native_window_occlusion_tracker_win.cc b/ui/aura/native_window_occlusion_tracker_win.cc
index 3664544..a366639 100644
--- a/ui/aura/native_window_occlusion_tracker_win.cc
+++ b/ui/aura/native_window_occlusion_tracker_win.cc
@@ -7,10 +7,12 @@
 #include <dwmapi.h>
 #include <powersetting.h>
 #include <memory>
+#include <string>
 
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/task/post_task.h"
 #include "base/task/task_traits.h"
@@ -20,6 +22,7 @@
 #include "base/win/scoped_gdi_object.h"
 #include "base/win/windows_version.h"
 #include "ui/aura/window_tree_host.h"
+#include "ui/gfx/win/hwnd_util.h"
 
 namespace aura {
 
@@ -227,7 +230,8 @@
 
 void NativeWindowOcclusionTrackerWin::UpdateOcclusionState(
     const base::flat_map<HWND, Window::OcclusionState>&
-        root_window_hwnds_occlusion_state) {
+        root_window_hwnds_occlusion_state,
+    bool show_all_windows) {
   num_visible_root_windows_ = 0;
   for (const auto& root_window_pair : root_window_hwnds_occlusion_state) {
     auto it = hwnd_root_window_map_.find(root_window_pair.first);
@@ -243,11 +247,15 @@
           Window::OcclusionState::HIDDEN);
       continue;
     }
+    Window::OcclusionState occl_state = root_window_pair.second;
     // If the screen is locked or off, ignore occlusion state results and
     // mark the window as occluded.
-    it->second->GetHost()->SetNativeWindowOcclusionState(
-        screen_locked_ || !display_on_ ? Window::OcclusionState::OCCLUDED
-                                       : root_window_pair.second);
+    if (screen_locked_ || !display_on_)
+      occl_state = Window::OcclusionState::OCCLUDED;
+    else if (show_all_windows)
+      occl_state = Window::OcclusionState::VISIBLE;
+
+    it->second->GetHost()->SetNativeWindowOcclusionState(occl_state);
     num_visible_root_windows_++;
   }
 }
@@ -487,8 +495,9 @@
   // Post a task to the browser ui thread to update the window occlusion state
   // on the root windows.
   ui_thread_task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(update_occlusion_state_callback_,
-                                root_window_hwnds_occlusion_state_));
+      FROM_HERE,
+      base::BindOnce(update_occlusion_state_callback_,
+                     root_window_hwnds_occlusion_state_, showing_thumbnails_));
 }
 
 void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
@@ -533,6 +542,10 @@
   // Detects foreground window changing.
   RegisterGlobalEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND);
 
+  // Detects objects getting shown and hidden. Used to know when the task bar
+  // and alt tab are showing preview windows so we can unocclude Chrome windows.
+  RegisterGlobalEventHook(EVENT_OBJECT_SHOW, EVENT_OBJECT_HIDE);
+
   // Detects object state changes, e.g., enable/disable state, native window
   // maximize and native window restore events.
   RegisterGlobalEventHook(EVENT_OBJECT_STATECHANGE, EVENT_OBJECT_STATECHANGE);
@@ -644,6 +657,38 @@
   if (id_object != OBJID_WINDOW)
     return;
 
+  // Detect if either the alt tab view or the task list thumbnail is being
+  // shown. If so, mark all non-hidden windows as occluded, and remember that
+  // we're in the showing_thumbnails state. This lasts until we get told that
+  // either the alt tab view or task list thumbnail are hidden.
+  if (event == EVENT_OBJECT_SHOW) {
+    // Avoid getting the hwnd's class name, and recomputing occlusion, if not
+    // needed.
+    if (showing_thumbnails_)
+      return;
+    std::string hwnd_class_name = base::UTF16ToUTF8(gfx::GetClassName(hwnd));
+    if ((hwnd_class_name == "MultitaskingViewFrame" ||
+         hwnd_class_name == "TaskListThumbnailWnd")) {
+      showing_thumbnails_ = true;
+      ui_thread_task_runner_->PostTask(
+          FROM_HERE, base::BindOnce(update_occlusion_state_callback_,
+                                    root_window_hwnds_occlusion_state_,
+                                    showing_thumbnails_));
+      return;
+    }
+  } else if (event == EVENT_OBJECT_HIDE) {
+    // Avoid getting the hwnd's class name, and recomputing occlusion, if not
+    // needed.
+    if (!showing_thumbnails_)
+      return;
+    std::string hwnd_class_name = base::UTF16ToUTF8(gfx::GetClassName(hwnd));
+    if (hwnd_class_name == "MultitaskingViewFrame" ||
+        hwnd_class_name == "TaskListThumbnailWnd") {
+      showing_thumbnails_ = false;
+      // Let occlusion calculation fix occlusion state.
+    }
+  }
+
   // Don't continually calculate occlusion while a window is moving, but rather
   // once at the beginning and once at the end.
   if (event == EVENT_SYSTEM_MOVESIZESTART) {
diff --git a/ui/aura/native_window_occlusion_tracker_win.h b/ui/aura/native_window_occlusion_tracker_win.h
index a36dba9..6c2f1ad 100644
--- a/ui/aura/native_window_occlusion_tracker_win.h
+++ b/ui/aura/native_window_occlusion_tracker_win.h
@@ -70,7 +70,8 @@
   class WindowOcclusionCalculator {
    public:
     using UpdateOcclusionStateCallback = base::RepeatingCallback<void(
-        const base::flat_map<HWND, Window::OcclusionState>&)>;
+        const base::flat_map<HWND, Window::OcclusionState>&,
+        bool show_all_windows)>;
 
     // Creates WindowOcclusionCalculator instance. Must be called on UI thread.
     static void CreateInstance(
@@ -234,6 +235,10 @@
     // windows from |unoccluded_desktop_region_|.
     int num_root_windows_with_unknown_occlusion_state_;
 
+    // This is true if the task bar thumbnails or the alt tab thumbnails are
+    // showing.
+    bool showing_thumbnails_ = false;
+
     // Only used on Win10+.
     Microsoft::WRL::ComPtr<IVirtualDesktopManager> virtual_desktop_manager_;
 
@@ -253,9 +258,12 @@
   // window rectangle in |window_rect|.
   static bool IsWindowVisibleAndFullyOpaque(HWND hwnd, gfx::Rect* window_rect);
 
-  // Updates root windows occclusion state.
+  // Updates root windows occclusion state. If |show_all_windows| is true,
+  // all non-hidden windows will be marked visible.  This is used to force
+  // rendering of thumbnails.
   void UpdateOcclusionState(const base::flat_map<HWND, Window::OcclusionState>&
-                                root_window_hwnds_occlusion_state);
+                                root_window_hwnds_occlusion_state,
+                            bool show_all_windows);
 
   // This is called with session changed notifications. If the screen is locked
   // by the current session, it marks app windows as occluded.
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn
index 6663ca7..e241b36d 100644
--- a/ui/base/BUILD.gn
+++ b/ui/base/BUILD.gn
@@ -609,6 +609,8 @@
     "//ui/gfx/geometry",
     "//url",
   ]
+
+  public_deps = [ "//ui/base/data_transfer_policy" ]
 }
 
 component("features") {
diff --git a/ui/base/clipboard/BUILD.gn b/ui/base/clipboard/BUILD.gn
index 24dcdac8..a24dfe5 100644
--- a/ui/base/clipboard/BUILD.gn
+++ b/ui/base/clipboard/BUILD.gn
@@ -67,10 +67,6 @@
     "clipboard_observer.h",
     "custom_data_helper.cc",
     "custom_data_helper.h",
-    "data_transfer_endpoint.cc",
-    "data_transfer_endpoint.h",
-    "data_transfer_policy_controller.cc",
-    "data_transfer_policy_controller.h",
     "scoped_clipboard_writer.cc",
     "scoped_clipboard_writer.h",
   ]
@@ -112,7 +108,10 @@
     "//ui/gfx/geometry",
   ]
 
-  public_deps = [ ":clipboard_types" ]
+  public_deps = [
+    ":clipboard_types",
+    "//ui/base/data_transfer_policy",
+  ]
 
   if (use_aura) {
     # Linux clipboard implementations.
diff --git a/ui/base/clipboard/clipboard.h b/ui/base/clipboard/clipboard.h
index 33a61f5c..410e293 100644
--- a/ui/base/clipboard/clipboard.h
+++ b/ui/base/clipboard/clipboard.h
@@ -28,7 +28,7 @@
 #include "mojo/public/cpp/base/big_buffer.h"
 #include "ui/base/clipboard/clipboard_buffer.h"
 #include "ui/base/clipboard/clipboard_format_type.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 
 class SkBitmap;
 
diff --git a/ui/base/clipboard/clipboard_android.cc b/ui/base/clipboard/clipboard_android.cc
index cdda023..7e29b14 100644
--- a/ui/base/clipboard/clipboard_android.cc
+++ b/ui/base/clipboard/clipboard_android.cc
@@ -28,7 +28,7 @@
 #include "ui/base/clipboard/clipboard_constants.h"
 #include "ui/base/clipboard/clipboard_format_type.h"
 #include "ui/base/clipboard/clipboard_metrics.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 #include "ui/base/ui_base_jni_headers/Clipboard_jni.h"
 #include "ui/gfx/android/java_bitmap.h"
 #include "ui/gfx/image/image.h"
diff --git a/ui/base/clipboard/clipboard_data.cc b/ui/base/clipboard/clipboard_data.cc
index 51fea138..02876ec 100644
--- a/ui/base/clipboard/clipboard_data.cc
+++ b/ui/base/clipboard/clipboard_data.cc
@@ -9,7 +9,7 @@
 
 #include "base/notreached.h"
 #include "skia/ext/skia_utils_base.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 #include "ui/gfx/skia_util.h"
 
 namespace ui {
diff --git a/ui/base/clipboard/clipboard_data.h b/ui/base/clipboard/clipboard_data.h
index ac4cb05..ac89e4f6 100644
--- a/ui/base/clipboard/clipboard_data.h
+++ b/ui/base/clipboard/clipboard_data.h
@@ -10,7 +10,7 @@
 
 #include "base/component_export.h"
 #include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 
 class SkBitmap;
 
diff --git a/ui/base/clipboard/clipboard_data_endpoint.cc b/ui/base/clipboard/clipboard_data_endpoint.cc
index 51382d3..10aed99 100644
--- a/ui/base/clipboard/clipboard_data_endpoint.cc
+++ b/ui/base/clipboard/clipboard_data_endpoint.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/base/clipboard/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 
 #include "base/check_op.h"
 #include "base/optional.h"
diff --git a/ui/base/clipboard/clipboard_data_unittest.cc b/ui/base/clipboard/clipboard_data_unittest.cc
index 3c1d329e..627793f 100644
--- a/ui/base/clipboard/clipboard_data_unittest.cc
+++ b/ui/base/clipboard/clipboard_data_unittest.cc
@@ -8,7 +8,7 @@
 
 #include "base/strings/string_piece_forward.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 #include "url/gurl.h"
 
 namespace ui {
diff --git a/ui/base/clipboard/clipboard_mac.mm b/ui/base/clipboard/clipboard_mac.mm
index 9857d02..615b159 100644
--- a/ui/base/clipboard/clipboard_mac.mm
+++ b/ui/base/clipboard/clipboard_mac.mm
@@ -27,7 +27,7 @@
 #include "ui/base/clipboard/clipboard_metrics.h"
 #include "ui/base/clipboard/clipboard_util_mac.h"
 #include "ui/base/clipboard/custom_data_helper.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
diff --git a/ui/base/clipboard/clipboard_non_backed.cc b/ui/base/clipboard/clipboard_non_backed.cc
index e1187f9..05513ec 100644
--- a/ui/base/clipboard/clipboard_non_backed.cc
+++ b/ui/base/clipboard/clipboard_non_backed.cc
@@ -28,8 +28,8 @@
 #include "ui/base/clipboard/clipboard_metrics.h"
 #include "ui/base/clipboard/clipboard_monitor.h"
 #include "ui/base/clipboard/custom_data_helper.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
-#include "ui/base/clipboard/data_transfer_policy_controller.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_policy_controller.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/ozone/buildflags.h"
 
diff --git a/ui/base/clipboard/clipboard_ozone.cc b/ui/base/clipboard/clipboard_ozone.cc
index 9605fbe..774c8848 100644
--- a/ui/base/clipboard/clipboard_ozone.cc
+++ b/ui/base/clipboard/clipboard_ozone.cc
@@ -22,7 +22,7 @@
 #include "ui/base/clipboard/clipboard_metrics.h"
 #include "ui/base/clipboard/clipboard_monitor.h"
 #include "ui/base/clipboard/custom_data_helper.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 #include "ui/gfx/codec/png_codec.h"
 #include "ui/ozone/buildflags.h"
 #include "ui/ozone/public/ozone_platform.h"
diff --git a/ui/base/clipboard/clipboard_test_template.h b/ui/base/clipboard/clipboard_test_template.h
index 5d652c8..5e9b7568 100644
--- a/ui/base/clipboard/clipboard_test_template.h
+++ b/ui/base/clipboard/clipboard_test_template.h
@@ -39,11 +39,11 @@
 #include "third_party/skia/include/core/SkUnPreMultiply.h"
 #include "ui/base/clipboard/clipboard.h"
 #include "ui/base/clipboard/clipboard_constants.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
-#include "ui/base/clipboard/data_transfer_policy_controller.h"
 #include "ui/base/clipboard/scoped_clipboard_writer.h"
 #include "ui/base/clipboard/test/clipboard_test_util.h"
 #include "ui/base/clipboard/test/test_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/gfx/geometry/size.h"
 #include "ui/gfx/half_float.h"
 #include "url/origin.h"
diff --git a/ui/base/clipboard/clipboard_win.cc b/ui/base/clipboard/clipboard_win.cc
index 3dff517a..b4d64ac 100644
--- a/ui/base/clipboard/clipboard_win.cc
+++ b/ui/base/clipboard/clipboard_win.cc
@@ -33,7 +33,7 @@
 #include "ui/base/clipboard/clipboard_metrics.h"
 #include "ui/base/clipboard/clipboard_util_win.h"
 #include "ui/base/clipboard/custom_data_helper.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/size.h"
 
diff --git a/ui/base/clipboard/clipboard_x11.cc b/ui/base/clipboard/clipboard_x11.cc
index 12375b2..1396668 100644
--- a/ui/base/clipboard/clipboard_x11.cc
+++ b/ui/base/clipboard/clipboard_x11.cc
@@ -25,7 +25,7 @@
 #include "ui/base/clipboard/clipboard_metrics.h"
 #include "ui/base/clipboard/clipboard_monitor.h"
 #include "ui/base/clipboard/custom_data_helper.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 #include "ui/base/nine_image_painter_factory.h"
 #include "ui/base/x/selection_owner.h"
 #include "ui/base/x/selection_requestor.h"
diff --git a/ui/base/clipboard/scoped_clipboard_writer.h b/ui/base/clipboard/scoped_clipboard_writer.h
index 48eb9df74..1dd0bae 100644
--- a/ui/base/clipboard/scoped_clipboard_writer.h
+++ b/ui/base/clipboard/scoped_clipboard_writer.h
@@ -12,7 +12,7 @@
 #include "base/strings/string16.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/clipboard/clipboard.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 
 namespace base {
 class Pickle;
diff --git a/ui/base/clipboard/test/test_clipboard.cc b/ui/base/clipboard/test/test_clipboard.cc
index 6e4f42d..e7589c2 100644
--- a/ui/base/clipboard/test/test_clipboard.cc
+++ b/ui/base/clipboard/test/test_clipboard.cc
@@ -14,8 +14,8 @@
 #include "skia/ext/skia_utils_base.h"
 #include "ui/base/clipboard/clipboard_constants.h"
 #include "ui/base/clipboard/clipboard_monitor.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
-#include "ui/base/clipboard/data_transfer_policy_controller.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_policy_controller.h"
 
 namespace ui {
 
diff --git a/ui/base/clipboard/test/test_clipboard.h b/ui/base/clipboard/test/test_clipboard.h
index ce55516..2fe8092e 100644
--- a/ui/base/clipboard/test/test_clipboard.h
+++ b/ui/base/clipboard/test/test_clipboard.h
@@ -16,7 +16,7 @@
 #include "base/macros.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/clipboard/clipboard.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 
 namespace ui {
 
diff --git a/ui/base/data_transfer_policy/BUILD.gn b/ui/base/data_transfer_policy/BUILD.gn
new file mode 100644
index 0000000..aeea4b1d
--- /dev/null
+++ b/ui/base/data_transfer_policy/BUILD.gn
@@ -0,0 +1,22 @@
+# 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("//build/config/ui.gni")
+
+component("data_transfer_policy") {
+  output_name = "ui_base_data_transfer_policy"
+  sources = [
+    "data_transfer_endpoint.cc",
+    "data_transfer_endpoint.h",
+    "data_transfer_policy_controller.cc",
+    "data_transfer_policy_controller.h",
+  ]
+
+  defines = [ "IS_UI_BASE_DATA_TRANSFER_POLICY_IMPL" ]
+
+  deps = [
+    "//base",
+    "//url",
+  ]
+}
diff --git a/ui/base/data_transfer_policy/DIR_METADATA b/ui/base/data_transfer_policy/DIR_METADATA
new file mode 100644
index 0000000..c470185
--- /dev/null
+++ b/ui/base/data_transfer_policy/DIR_METADATA
@@ -0,0 +1,12 @@
+# Metadata information for this directory.
+#
+# For more information on DIR_METADATA files, see:
+#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
+#
+# For the schema of this file, see Metadata message:
+#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
+
+monorail {
+  component: "OS>Software>Enterprise>DLP"
+}
+team_email: "chromeos-dlp@google.com"
\ No newline at end of file
diff --git a/ui/base/data_transfer_policy/OWNERS b/ui/base/data_transfer_policy/OWNERS
new file mode 100644
index 0000000..11249b9
--- /dev/null
+++ b/ui/base/data_transfer_policy/OWNERS
@@ -0,0 +1,5 @@
+# Primary:
+ayaelattar@chromium.org
+
+# Secondary:
+huangdarwin@chromium.org
\ No newline at end of file
diff --git a/ui/base/clipboard/data_transfer_endpoint.cc b/ui/base/data_transfer_policy/data_transfer_endpoint.cc
similarity index 94%
rename from ui/base/clipboard/data_transfer_endpoint.cc
rename to ui/base/data_transfer_policy/data_transfer_endpoint.cc
index 5cbb186d..a5f3c7bd 100644
--- a/ui/base/clipboard/data_transfer_endpoint.cc
+++ b/ui/base/data_transfer_policy/data_transfer_endpoint.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/base/clipboard/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 
 #include "base/check_op.h"
 #include "base/optional.h"
diff --git a/ui/base/clipboard/data_transfer_endpoint.h b/ui/base/data_transfer_policy/data_transfer_endpoint.h
similarity index 91%
rename from ui/base/clipboard/data_transfer_endpoint.h
rename to ui/base/data_transfer_policy/data_transfer_endpoint.h
index e265dc35..cd510a560 100644
--- a/ui/base/clipboard/data_transfer_endpoint.h
+++ b/ui/base/data_transfer_policy/data_transfer_endpoint.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_BASE_CLIPBOARD_DATA_TRANSFER_ENDPOINT_H_
-#define UI_BASE_CLIPBOARD_DATA_TRANSFER_ENDPOINT_H_
+#ifndef UI_BASE_DATA_TRANSFER_POLICY_DATA_TRANSFER_ENDPOINT_H_
+#define UI_BASE_DATA_TRANSFER_POLICY_DATA_TRANSFER_ENDPOINT_H_
 
 #include "base/optional.h"
 #include "base/stl_util.h"
@@ -38,7 +38,7 @@
 // DataTransferEndpoint(kDefault, true). Both specify the same types of
 // endpoints (not a URL/ARC++/...etc, and should show a notification to the user
 // if the data read is not allowed.)
-class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) DataTransferEndpoint {
+class COMPONENT_EXPORT(UI_BASE_DATA_TRANSFER_POLICY) DataTransferEndpoint {
  public:
   explicit DataTransferEndpoint(const url::Origin& origin,
                                 bool notify_if_restricted = true);
@@ -79,4 +79,4 @@
 
 }  // namespace ui
 
-#endif  // UI_BASE_CLIPBOARD_DATA_TRANSFER_ENDPOINT_H_
+#endif  // UI_BASE_DATA_TRANSFER_POLICY_DATA_TRANSFER_ENDPOINT_H_
diff --git a/ui/base/clipboard/data_transfer_policy_controller.cc b/ui/base/data_transfer_policy/data_transfer_policy_controller.cc
similarity index 92%
rename from ui/base/clipboard/data_transfer_policy_controller.cc
rename to ui/base/data_transfer_policy/data_transfer_policy_controller.cc
index b1a66f8..fc02854 100644
--- a/ui/base/clipboard/data_transfer_policy_controller.cc
+++ b/ui/base/data_transfer_policy/data_transfer_policy_controller.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/base/clipboard/data_transfer_policy_controller.h"
+#include "ui/base/data_transfer_policy/data_transfer_policy_controller.h"
 
 namespace ui {
 
diff --git a/ui/base/clipboard/data_transfer_policy_controller.h b/ui/base/data_transfer_policy/data_transfer_policy_controller.h
similarity index 78%
rename from ui/base/clipboard/data_transfer_policy_controller.h
rename to ui/base/data_transfer_policy/data_transfer_policy_controller.h
index d2c8d40..a858af9 100644
--- a/ui/base/clipboard/data_transfer_policy_controller.h
+++ b/ui/base/data_transfer_policy/data_transfer_policy_controller.h
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_BASE_CLIPBOARD_DATA_TRANSFER_POLICY_CONTROLLER_H_
-#define UI_BASE_CLIPBOARD_DATA_TRANSFER_POLICY_CONTROLLER_H_
+#ifndef UI_BASE_DATA_TRANSFER_POLICY_DATA_TRANSFER_POLICY_CONTROLLER_H_
+#define UI_BASE_DATA_TRANSFER_POLICY_DATA_TRANSFER_POLICY_CONTROLLER_H_
 
 #include "base/component_export.h"
-#include "ui/base/clipboard/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 
 namespace ui {
 
@@ -14,7 +14,8 @@
 // clipboard read operations. It allows/disallows transferring the data given
 // the source of the data and the destination trying to access the data and a
 // set of rules controlling these source and destination.
-class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) DataTransferPolicyController {
+class COMPONENT_EXPORT(UI_BASE_DATA_TRANSFER_POLICY)
+    DataTransferPolicyController {
  public:
   // Returns a pointer to the existing instance of the class.
   static DataTransferPolicyController* Get();
@@ -42,4 +43,4 @@
 
 }  // namespace ui
 
-#endif  // UI_BASE_CLIPBOARD_DATA_TRANSFER_POLICY_CONTROLLER_H_
+#endif  // UI_BASE_DATA_TRANSFER_POLICY_DATA_TRANSFER_POLICY_CONTROLLER_H_
diff --git a/ui/base/dragdrop/os_exchange_data.cc b/ui/base/dragdrop/os_exchange_data.cc
index 7f2da0d..9d708ac 100644
--- a/ui/base/dragdrop/os_exchange_data.cc
+++ b/ui/base/dragdrop/os_exchange_data.cc
@@ -10,6 +10,7 @@
 #include "base/callback.h"
 #include "base/pickle.h"
 #include "ui/base/clipboard/clipboard_format_type.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 #include "ui/base/dragdrop/os_exchange_data_provider_factory.h"
 #include "url/gurl.h"
 
@@ -160,4 +161,13 @@
 }
 #endif
 
+void OSExchangeData::SetSource(
+    std::unique_ptr<DataTransferEndpoint> data_source) {
+  provider_->SetSource(std::move(data_source));
+}
+
+DataTransferEndpoint* OSExchangeData::GetSource() const {
+  return provider_->GetSource();
+}
+
 }  // namespace ui
diff --git a/ui/base/dragdrop/os_exchange_data.h b/ui/base/dragdrop/os_exchange_data.h
index a5098f574..067e210 100644
--- a/ui/base/dragdrop/os_exchange_data.h
+++ b/ui/base/dragdrop/os_exchange_data.h
@@ -32,6 +32,7 @@
 namespace ui {
 
 class ClipboardFormatType;
+class DataTransferEndpoint;
 struct FileInfo;
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -186,6 +187,12 @@
   bool HasHtml() const;
 #endif
 
+  // Adds a DataTransferEndpoint to represent the source of the data.
+  // TODO(crbug.com/1142406): Update all drag-and-drop references to set the
+  // source of the data.
+  void SetSource(std::unique_ptr<DataTransferEndpoint> data_source);
+  DataTransferEndpoint* GetSource() const;
+
  private:
   // Provides the actual data.
   std::unique_ptr<OSExchangeDataProvider> provider_;
diff --git a/ui/base/dragdrop/os_exchange_data_provider.h b/ui/base/dragdrop/os_exchange_data_provider.h
index e6529cf8..b398fe6 100644
--- a/ui/base/dragdrop/os_exchange_data_provider.h
+++ b/ui/base/dragdrop/os_exchange_data_provider.h
@@ -31,6 +31,8 @@
 
 namespace ui {
 
+class DataTransferEndpoint;
+
 // Controls whether or not filenames should be converted to file: URLs when
 // getting a URL.
 enum class FilenameToURLPolicy {
@@ -105,6 +107,10 @@
   virtual gfx::ImageSkia GetDragImage() const = 0;
   virtual gfx::Vector2d GetDragImageOffset() const = 0;
 #endif
+
+  // These functions are only implemented on Chrome OS currently.
+  virtual void SetSource(std::unique_ptr<DataTransferEndpoint> data_source) = 0;
+  virtual DataTransferEndpoint* GetSource() const = 0;
 };
 
 }  // namespace ui
diff --git a/ui/base/dragdrop/os_exchange_data_provider_mac.h b/ui/base/dragdrop/os_exchange_data_provider_mac.h
index 8fb6a3a..1626a14 100644
--- a/ui/base/dragdrop/os_exchange_data_provider_mac.h
+++ b/ui/base/dragdrop/os_exchange_data_provider_mac.h
@@ -76,6 +76,9 @@
   // OSExchangeData.
   static NSArray* SupportedPasteboardTypes();
 
+  void SetSource(std::unique_ptr<DataTransferEndpoint> data_source) override;
+  DataTransferEndpoint* GetSource() const override;
+
  protected:
   OSExchangeDataProviderMac();
   OSExchangeDataProviderMac(const OSExchangeDataProviderMac&);
diff --git a/ui/base/dragdrop/os_exchange_data_provider_mac.mm b/ui/base/dragdrop/os_exchange_data_provider_mac.mm
index b7f14445..f264b8b5e 100644
--- a/ui/base/dragdrop/os_exchange_data_provider_mac.mm
+++ b/ui/base/dragdrop/os_exchange_data_provider_mac.mm
@@ -17,6 +17,7 @@
 #include "ui/base/clipboard/clipboard_format_type.h"
 #import "ui/base/clipboard/clipboard_util_mac.h"
 #include "ui/base/clipboard/custom_data_helper.h"
+#include "ui/base/data_transfer_policy/data_transfer_policy_controller.h"
 #import "ui/base/dragdrop/cocoa_dnd_util.h"
 #include "ui/base/dragdrop/file_info/file_info.h"
 #include "url/gurl.h"
@@ -337,4 +338,11 @@
   ];
 }
 
+void OSExchangeDataProviderMac::SetSource(
+    std::unique_ptr<DataTransferEndpoint> data_source) {}
+
+DataTransferEndpoint* OSExchangeDataProviderMac::GetSource() const {
+  return nullptr;
+}
+
 }  // namespace ui
diff --git a/ui/base/dragdrop/os_exchange_data_provider_non_backed.cc b/ui/base/dragdrop/os_exchange_data_provider_non_backed.cc
index 9d5cb80..dfa2f98 100644
--- a/ui/base/dragdrop/os_exchange_data_provider_non_backed.cc
+++ b/ui/base/dragdrop/os_exchange_data_provider_non_backed.cc
@@ -12,6 +12,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "net/base/filename_util.h"
 #include "ui/base/clipboard/clipboard_format_type.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 #include "ui/base/dragdrop/file_info/file_info.h"
 #include "ui/base/dragdrop/os_exchange_data.h"
 #include "url/gurl.h"
@@ -238,4 +239,13 @@
   return true;
 }
 
+void OSExchangeDataProviderNonBacked::SetSource(
+    std::unique_ptr<DataTransferEndpoint> data_source) {
+  source_ = std::move(data_source);
+}
+
+DataTransferEndpoint* OSExchangeDataProviderNonBacked::GetSource() const {
+  return source_.get();
+}
+
 }  // namespace ui
diff --git a/ui/base/dragdrop/os_exchange_data_provider_non_backed.h b/ui/base/dragdrop/os_exchange_data_provider_non_backed.h
index 201aa5c..08f148ec 100644
--- a/ui/base/dragdrop/os_exchange_data_provider_non_backed.h
+++ b/ui/base/dragdrop/os_exchange_data_provider_non_backed.h
@@ -6,6 +6,7 @@
 #define UI_BASE_DRAGDROP_OS_EXCHANGE_DATA_PROVIDER_NON_BACKED_H_
 
 #include <map>
+#include <memory>
 
 #include "base/component_export.h"
 #include "base/pickle.h"
@@ -72,6 +73,9 @@
   gfx::ImageSkia GetDragImage() const override;
   gfx::Vector2d GetDragImageOffset() const override;
 
+  void SetSource(std::unique_ptr<DataTransferEndpoint> data_source) override;
+  DataTransferEndpoint* GetSource() const override;
+
  private:
   // Returns true if |formats_| contains a file format and the file name can be
   // parsed as a URL.
@@ -107,6 +111,9 @@
   GURL base_url_;
 
   bool originated_from_renderer_ = false;
+
+  // Data source.
+  std::unique_ptr<DataTransferEndpoint> source_;
 };
 
 }  // namespace ui
diff --git a/ui/base/dragdrop/os_exchange_data_provider_win.cc b/ui/base/dragdrop/os_exchange_data_provider_win.cc
index 0ce4cae..b6ab7a4 100644
--- a/ui/base/dragdrop/os_exchange_data_provider_win.cc
+++ b/ui/base/dragdrop/os_exchange_data_provider_win.cc
@@ -34,6 +34,7 @@
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/clipboard/clipboard_format_type.h"
 #include "ui/base/clipboard/clipboard_util_win.h"
+#include "ui/base/data_transfer_policy/data_transfer_policy_controller.h"
 #include "ui/base/dragdrop/file_info/file_info.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/l10n/l10n_util_win.h"
@@ -754,6 +755,13 @@
   return gfx::Vector2d();
 }
 
+void OSExchangeDataProviderWin::SetSource(
+    std::unique_ptr<DataTransferEndpoint> data_source) {}
+
+DataTransferEndpoint* OSExchangeDataProviderWin::GetSource() const {
+  return nullptr;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // DataObjectImpl, IDataObject implementation:
 
diff --git a/ui/base/dragdrop/os_exchange_data_provider_win.h b/ui/base/dragdrop/os_exchange_data_provider_win.h
index 1fb90911..447a3ef 100644
--- a/ui/base/dragdrop/os_exchange_data_provider_win.h
+++ b/ui/base/dragdrop/os_exchange_data_provider_win.h
@@ -191,6 +191,9 @@
   gfx::ImageSkia GetDragImage() const override;
   gfx::Vector2d GetDragImageOffset() const override;
 
+  void SetSource(std::unique_ptr<DataTransferEndpoint> data_source) override;
+  DataTransferEndpoint* GetSource() const override;
+
  private:
   void SetVirtualFileContentAtIndexForTesting(base::span<const uint8_t> data,
                                               DWORD tymed,
diff --git a/ui/base/dragdrop/os_exchange_data_provider_x11.cc b/ui/base/dragdrop/os_exchange_data_provider_x11.cc
index d4555f1..8365cc4 100644
--- a/ui/base/dragdrop/os_exchange_data_provider_x11.cc
+++ b/ui/base/dragdrop/os_exchange_data_provider_x11.cc
@@ -8,6 +8,7 @@
 
 #include "base/check.h"
 #include "ui/base/clipboard/clipboard_constants.h"
+#include "ui/base/data_transfer_policy/data_transfer_policy_controller.h"
 #include "ui/base/x/selection_utils.h"
 #include "ui/events/platform/platform_event_source.h"
 #include "ui/gfx/x/x11_atom_cache.h"
@@ -46,4 +47,11 @@
   return false;
 }
 
+void OSExchangeDataProviderX11::SetSource(
+    std::unique_ptr<DataTransferEndpoint> data_source) {}
+
+DataTransferEndpoint* OSExchangeDataProviderX11::GetSource() const {
+  return nullptr;
+}
+
 }  // namespace ui
diff --git a/ui/base/dragdrop/os_exchange_data_provider_x11.h b/ui/base/dragdrop/os_exchange_data_provider_x11.h
index a85e864..60dac52 100644
--- a/ui/base/dragdrop/os_exchange_data_provider_x11.h
+++ b/ui/base/dragdrop/os_exchange_data_provider_x11.h
@@ -38,6 +38,9 @@
   // XEventDispatcher:
   bool DispatchXEvent(x11::Event* xev) override;
 
+  void SetSource(std::unique_ptr<DataTransferEndpoint> data_source) override;
+  DataTransferEndpoint* GetSource() const override;
+
  private:
   friend class OSExchangeDataProviderX11Test;
 };
diff --git a/ui/base/test/skia_gold_pixel_diff.cc b/ui/base/test/skia_gold_pixel_diff.cc
index dc5ecbb..54f09e90 100644
--- a/ui/base/test/skia_gold_pixel_diff.cc
+++ b/ui/base/test/skia_gold_pixel_diff.cc
@@ -246,7 +246,8 @@
       code_review_system_ = "gerrit";
     }
   }
-  if (cmd_line->HasSwitch(kNoLuciAuth)) {
+  if (cmd_line->HasSwitch(kNoLuciAuth) ||
+      !cmd_line->HasSwitch(switches::kTestLauncherBotMode)) {
     luci_auth_ = false;
   }
   initialized_ = true;
diff --git a/ui/base/test/skia_gold_pixel_diff_unittest.cc b/ui/base/test/skia_gold_pixel_diff_unittest.cc
index cac9a87..741263b 100644
--- a/ui/base/test/skia_gold_pixel_diff_unittest.cc
+++ b/ui/base/test/skia_gold_pixel_diff_unittest.cc
@@ -73,6 +73,52 @@
   EXPECT_TRUE(ret);
 }
 
+TEST_F(SkiaGoldPixelDiffTest, LuciAuthSwitch) {
+  MockSkiaGoldPixelDiff mock_pixel;
+  auto* cmd_line = base::CommandLine::ForCurrentProcess();
+  cmd_line->AppendSwitch(switches::kTestLauncherBotMode);
+
+  EXPECT_CALL(mock_pixel, LaunchProcess(_)).Times(AnyNumber());
+  EXPECT_CALL(
+      mock_pixel,
+      LaunchProcess(AllOf(Property(&base::CommandLine::GetCommandLineString,
+                                   HasSubstr(FILE_PATH_LITERAL("--luci"))))))
+      .Times(1);
+  mock_pixel.Init("Prefix");
+  bool ret = mock_pixel.CompareScreenshot("test", GetTestBitmap());
+  EXPECT_TRUE(ret);
+}
+
+TEST_F(SkiaGoldPixelDiffTest, NoLuciAuthSwitch) {
+  MockSkiaGoldPixelDiff mock_pixel;
+  auto* cmd_line = base::CommandLine::ForCurrentProcess();
+  cmd_line->AppendSwitch("no-luci-auth");
+
+  EXPECT_CALL(mock_pixel, LaunchProcess(_)).Times(AnyNumber());
+  EXPECT_CALL(mock_pixel, LaunchProcess(AllOf(Property(
+                              &base::CommandLine::GetCommandLineString,
+                              Not(HasSubstr(FILE_PATH_LITERAL("--luci")))))))
+      .Times(3);
+  mock_pixel.Init("Prefix");
+  bool ret = mock_pixel.CompareScreenshot("test", GetTestBitmap());
+  EXPECT_TRUE(ret);
+}
+
+TEST_F(SkiaGoldPixelDiffTest, LocalNoLuciAuth) {
+  MockSkiaGoldPixelDiff mock_pixel;
+  auto* cmd_line = base::CommandLine::ForCurrentProcess();
+  cmd_line->RemoveSwitch(switches::kTestLauncherBotMode);
+
+  EXPECT_CALL(mock_pixel, LaunchProcess(_)).Times(AnyNumber());
+  EXPECT_CALL(mock_pixel, LaunchProcess(AllOf(Property(
+                              &base::CommandLine::GetCommandLineString,
+                              Not(HasSubstr(FILE_PATH_LITERAL("--luci")))))))
+      .Times(3);
+  mock_pixel.Init("Prefix");
+  bool ret = mock_pixel.CompareScreenshot("test", GetTestBitmap());
+  EXPECT_TRUE(ret);
+}
+
 TEST_F(SkiaGoldPixelDiffTest, FuzzyMatching) {
   MockSkiaGoldPixelDiff mock_pixel;
   EXPECT_CALL(mock_pixel, LaunchProcess(_)).Times(AnyNumber());
diff --git a/ui/base/x/x11_os_exchange_data_provider.cc b/ui/base/x/x11_os_exchange_data_provider.cc
index bb64bb3..d76cbc9d 100644
--- a/ui/base/x/x11_os_exchange_data_provider.cc
+++ b/ui/base/x/x11_os_exchange_data_provider.cc
@@ -13,6 +13,7 @@
 #include "net/base/filename_util.h"
 #include "ui/base/clipboard/clipboard_constants.h"
 #include "ui/base/clipboard/clipboard_format_type.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 #include "ui/base/dragdrop/file_info/file_info.h"
 #include "ui/base/x/selection_utils.h"
 #include "ui/base/x/x11_util.h"
@@ -475,4 +476,11 @@
   format_map_.Insert(format, data);
 }
 
+void XOSExchangeDataProvider::SetSource(
+    std::unique_ptr<DataTransferEndpoint> data_source) {}
+
+DataTransferEndpoint* XOSExchangeDataProvider::GetSource() const {
+  return nullptr;
+}
+
 }  // namespace ui
diff --git a/ui/base/x/x11_os_exchange_data_provider.h b/ui/base/x/x11_os_exchange_data_provider.h
index ff119a7c..fbc79e5 100644
--- a/ui/base/x/x11_os_exchange_data_provider.h
+++ b/ui/base/x/x11_os_exchange_data_provider.h
@@ -92,6 +92,9 @@
   gfx::ImageSkia GetDragImage() const override;
   gfx::Vector2d GetDragImageOffset() const override;
 
+  void SetSource(std::unique_ptr<DataTransferEndpoint> data_source) override;
+  DataTransferEndpoint* GetSource() const override;
+
  protected:
   friend class OSExchangeDataProviderX11Test;
   using PickleData = std::map<ClipboardFormatType, base::Pickle>;
diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn
index 68abeb8c..07dadb5c 100644
--- a/ui/ozone/platform/wayland/BUILD.gn
+++ b/ui/ozone/platform/wayland/BUILD.gn
@@ -212,10 +212,7 @@
 
   # TODO(crbug.com/1052397): Rename chromeos_is_browser_only to is_lacros.
   if (chromeos_is_browser_only) {
-    deps += [
-      "//chromeos/crosapi/cpp",
-      "//chromeos/ui/base",
-    ]
+    deps += [ "//chromeos/crosapi/cpp" ]
   }
 
   defines = [ "OZONE_IMPLEMENTATION" ]
diff --git a/ui/ozone/platform/wayland/host/wayland_connection.h b/ui/ozone/platform/wayland/host/wayland_connection.h
index 688de8c..f25e699 100644
--- a/ui/ozone/platform/wayland/host/wayland_connection.h
+++ b/ui/ozone/platform/wayland/host/wayland_connection.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <vector>
 
-#include "build/chromeos_buildflags.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/events/event.h"
 #include "ui/ozone/platform/wayland/common/wayland_object.h"
@@ -17,10 +16,6 @@
 #include "ui/ozone/platform/wayland/host/wayland_data_source.h"
 #include "ui/ozone/platform/wayland/host/wayland_window_manager.h"
 
-#if BUILDFLAG(IS_LACROS)
-#include "chromeos/ui/base/tablet_state.h"
-#endif
-
 namespace gfx {
 class Point;
 }
@@ -241,10 +236,6 @@
   // Manages Wayland windows.
   WaylandWindowManager wayland_window_manager_;
 
-#if BUILDFLAG(IS_LACROS)
-  chromeos::TabletState tablet_state_;
-#endif
-
   bool scheduled_flush_ = false;
 
   EventSerial serial_;
diff --git a/ui/snapshot/snapshot_aura_unittest.cc b/ui/snapshot/snapshot_aura_unittest.cc
index 0537792f..de78f94 100644
--- a/ui/snapshot/snapshot_aura_unittest.cc
+++ b/ui/snapshot/snapshot_aura_unittest.cc
@@ -200,12 +200,12 @@
 #define MAYBE_FullScreenWindow FullScreenWindow
 #endif
 TEST_P(SnapshotAuraTest, MAYBE_FullScreenWindow) {
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
-  // TODO(https://crbug.com/1002716): Fix this test to run in < action_timeout()
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_FUCHSIA)
+  // TODO(https://crbug.com/1143031): Fix this test to run in < action_timeout()
   // on the Linux Debug & TSAN bots.
   const base::test::ScopedRunLoopTimeout increased_run_timeout(
       FROM_HERE, TestTimeouts::action_max_timeout());
-#endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
+#endif  // defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_FUCHSIA)
 
 #if defined(OS_WIN)
   // TODO(https://crbug.com/850556): Make work on Win10.
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index 52e4ef5a..432332a 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -8,7 +8,7 @@
 #include <set>
 #include <string>
 #include <utility>
-#include "ui/base/clipboard/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 #include "ui/events/gesture_event_details.h"
 
 #if defined(OS_WIN)
diff --git a/ui/webui/resources/cr_components/BUILD.gn b/ui/webui/resources/cr_components/BUILD.gn
index 952ac2d..0388c2a 100644
--- a/ui/webui/resources/cr_components/BUILD.gn
+++ b/ui/webui/resources/cr_components/BUILD.gn
@@ -96,6 +96,8 @@
       "chromeos/cellular_setup/sim_detect_page.m.js",
       "chromeos/cellular_setup/subflow_behavior.m.js",
       "chromeos/cellular_setup/webview_post_util.m.js",
+      "chromeos/network_health/network_diagnostics.m.js",
+      "chromeos/network_health/network_diagnostics_mojo.m.js",
       "chromeos/network/cr_policy_network_behavior_mojo.m.js",
       "chromeos/network/cr_policy_network_indicator_mojo.m.js",
       "chromeos/network/mojo_interface_provider.m.js",
@@ -238,6 +240,8 @@
       "chromeos/network/cr_policy_network_indicator_mojo.js",
       "chromeos/network_health/network_diagnostics.html",
       "chromeos/network_health/network_diagnostics.js",
+      "chromeos/network_health/network_diagnostics_mojo.html",
+      "chromeos/network_health/network_diagnostics_mojo.js",
       "chromeos/network_health/network_health_summary.html",
       "chromeos/network_health/network_health_summary.js",
       "chromeos/network/mojo_interface_provider.html",
diff --git a/ui/webui/resources/cr_components/chromeos/network_health/BUILD.gn b/ui/webui/resources/cr_components/chromeos/network_health/BUILD.gn
index 607bd812..a326dc5 100644
--- a/ui/webui/resources/cr_components/chromeos/network_health/BUILD.gn
+++ b/ui/webui/resources/cr_components/chromeos/network_health/BUILD.gn
@@ -21,6 +21,7 @@
   is_polymer3 = true
   deps = [
     ":network_diagnostics.m",
+    ":network_diagnostics_mojo.m",
     ":network_health_summary.m",
   ]
 }
@@ -42,6 +43,13 @@
   ]
 }
 
+js_library("network_diagnostics_mojo") {
+  deps = [
+    "//chromeos/services/network_health/public/mojom:mojom_js_library_for_compile",
+    "//ui/webui/resources/js:cr",
+  ]
+}
+
 js_library("network_health_summary.m") {
   sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/network_health/network_health_summary.m.js" ]
   deps = [
@@ -56,6 +64,7 @@
 js_library("network_diagnostics.m") {
   sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics.m.js" ]
   deps = [
+    ":network_diagnostics_mojo.m",
     "//chromeos/services/network_health/public/mojom:mojom_js_library_for_compile",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
     "//ui/webui/resources/js:i18n_behavior.m",
@@ -63,6 +72,12 @@
   extra_deps = [ ":network_diagnostics_module" ]
 }
 
+js_library("network_diagnostics_mojo.m") {
+  sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics_mojo.m.js" ]
+  deps = [ "//chrome/browser/ui/webui/settings/chromeos/search:mojo_bindings_js_library_for_compile" ]
+  extra_deps = [ ":modulize" ]
+}
+
 # polymer_modulizer for converting Polymer2 to Polymer3
 
 polymer_modulizer("network_health_summary") {
@@ -77,8 +92,13 @@
   html_type = "dom-module"
 }
 
+js_modulizer("modulize") {
+  input_files = [ "network_diagnostics_mojo.js" ]
+}
+
 group("polymer3_elements") {
   public_deps = [
+    ":modulize",
     ":network_diagnostics_module",
     ":network_health_summary_module",
   ]
diff --git a/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics.html b/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics.html
index 63657be..454a4e9 100644
--- a/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics.html
+++ b/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics.html
@@ -1,7 +1,6 @@
 <link rel="import" href="../../../html/polymer.html">
 
-<link rel="import" href="chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.html">
-<link rel="import" href="chrome://resources/mojo/chromeos/services/network_health/public/mojom/network_diagnostics.mojom.html">
+<link rel="import" href="chrome://resources/cr_components/chromeos/network_health/network_diagnostics_mojo.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html">
 <link rel="import" href="../../../cr_elements/cr_button/cr_button.html">
 <link rel="import" href="../../../html/i18n_behavior.html">
diff --git a/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics_mojo.html b/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics_mojo.html
new file mode 100644
index 0000000..7af8965
--- /dev/null
+++ b/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics_mojo.html
@@ -0,0 +1,4 @@
+<link rel="import" href="chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.html">
+
+<script src="chrome://resources/mojo/chromeos/services/network_health/public/mojom/network_diagnostics.mojom-lite.js"></script>
+<script src="network_diagnostics_mojo.js"></script>
diff --git a/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics_mojo.js b/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics_mojo.js
new file mode 100644
index 0000000..f89eb43
--- /dev/null
+++ b/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics_mojo.js
@@ -0,0 +1,15 @@
+// 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.
+
+// clang-format off
+// #import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
+// #import 'chrome://resources/mojo/chromeos/services/network_health/public/mojom/network_diagnostics.mojom-lite.js';
+// clang-format on
+
+/**
+ * @fileoverview Wrapper around Network Diagnostics mojom file and associated
+ * utilities.
+ * TODO(crbug/1111852): Remove this wrapper once Polymer2 no longer needs to be
+ * supported. These imports can be used directly.
+ */