diff --git a/DEPS b/DEPS
index cd3f39e..cbf82bb 100644
--- a/DEPS
+++ b/DEPS
@@ -295,15 +295,15 @@
   # 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': '10f4cf9a817dbc0e86179ce38c48f6e44ddd25af',
+  'skia_revision': 'b64f5854c4148431f1dba95b592795dc98f3e6c7',
   # 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': '08f66b181c57e381cda1ee15023d53a620616ed7',
+  'v8_revision': 'be3c06167b01bc7cd70edb4e44ec76ce8058390d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '7fb1ac40706f4717fc4f04d1aca207066041ce3c',
+  'angle_revision': '799d301f76944d4bf3a124c4ddf8e5bf19037357',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -387,7 +387,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': 'cfa11f3ba573a287a9e0fb71ab1ab640746f3477',
+  'devtools_frontend_revision': 'cf70a057cfa87616144125951b1e88c633006eac',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -411,7 +411,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': '025b5011849104e079510121385aa099125ea65c',
+  'dawn_revision': '66a8850fbf4baf4311fa4410f88a3af9ed8f43b5',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -519,7 +519,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling llvm-libc
   # and whatever else without interference from each other.
-  'llvm_libc_revision':    '225cbadd34448e99d4fe6f2a75f20ec59bcdab83',
+  'llvm_libc_revision':    'ffdeea1ab212d6349484afb9ba9532e252fde09d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling llvm-libc
   # and whatever else without interference from each other.
@@ -1149,7 +1149,7 @@
   },
 
   'src/chrome/release_scripts': {
-      'url': Var('chrome_git') + '/chrome/tools/release/scripts' + '@' + '68cf7f7a742a11fd5cf852234ca7da522e5030cd',
+      'url': Var('chrome_git') + '/chrome/tools/release/scripts' + '@' + 'b1c7bf06c3daeac7c9d718ae5d64d1a46ac002f4',
       'condition': 'checkout_chrome_release_scripts',
   },
 
@@ -1492,7 +1492,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '308cc67f3ac6f1b4fdff05ecad102362b3821320',
+    '98a170bfb1752b85a4786f27a326a076c86344dd',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -2846,16 +2846,16 @@
       'dep_type': 'cipd',
   },
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@b9840c73fad2fd81fe88dd40806b3ef0ddbf5c13',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@1d9c182c6fab8ac1826d0487e4508a1016771277',
   'src/third_party/glslang/src': '{chromium_git}/external/github.com/KhronosGroup/glslang@e57f993cff981c8c3ffd38967e030f04d13781a9',
   'src/third_party/spirv-cross/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Cross@b8fcf307f1f347089e3c46eb4451d27f32ebc8d3',
-  'src/third_party/spirv-headers/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Headers@0e710677989b4326ac974fd80c5308191ed80965',
+  'src/third_party/spirv-headers/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Headers@8c88e0c4c94a21de825efccba5f99a862b049825',
   'src/third_party/spirv-tools/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Tools@393d5c7df150532045c50affffea2df22e8231b0',
   'src/third_party/vulkan-headers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Headers@78c359741d855213e8685278eb81bb62599f8e56',
   'src/third_party/vulkan-loader/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Loader@723d6b4aa35853315c6e021ec86388b3a2559fae',
-  'src/third_party/vulkan-tools/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Tools@da7c7db28d36f66dff88f00412dceb480ccc77ea',
+  'src/third_party/vulkan-tools/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Tools@289efccc7560f2b970e2b4e0f50349da87669311',
   'src/third_party/vulkan-utility-libraries/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Utility-Libraries@0d5b49b80f17bca25e7f9321ad4e671a56f70887',
-  'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@2e6787d498d65bc20c195d667b8cd3c63e1a8aa9',
+  'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@912f6b6645b309c46828e43304d331cc9a218469',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + '56300b29fbfcc693ee6609ddad3fdd5b7a449a21',
@@ -2894,13 +2894,13 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'c01b768bce4a143e152c1870b6ba99ea6267d2b0',
 
   'src/third_party/webgpu-cts/src':
-    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '2c09e17c32931273808700d7544ec28470e5d5fe',
+    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'bd792919c655555a98c9813e2817a83e634a4111',
 
   'src/third_party/webpagereplay':
     Var('chromium_git') + '/webpagereplay.git' + '@' + Var('webpagereplay_revision'),
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'dbb6921457926818beaedbd1ea0ab4096ecd50be',
+    Var('webrtc_git') + '/src.git' + '@' + '77d37aec1d71b636781a7717537cf8538e60068f',
 
   # Wuffs' canonical repository is at github.com/google/wuffs, but we use
   # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file.
@@ -3019,7 +3019,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/boca_app/app',
-        'version': 'uRzwMTEcUkslnOKBJo183DLLVu1EFvX_al2R60JMFBwC',
+        'version': 'BQKkg2yFZqM0BT-kkPHKdJNZLkhyVmhNGNawk-FCKqMC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -3101,7 +3101,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/autorolled',
-              'version': 'hC2tVuJ_9gfUl2Grztk_eU8GrGLEDstUoZgtaPGLSfsC',
+              'version': 'tdwMr59zJpk4_nRDZFn1OSWoe8FrLQ_rnJZxvVnUUh8C',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -4629,7 +4629,7 @@
 
   'src/components/plus_addresses/resources/internal': {
       'url': Var('chrome_git') + '/chrome/components/plus_addresses/resources.git' + '@' +
-        '85e0ab9fd2d5d2c25d4593596b81d4977c60fd1a',
+        '32ee8b65a346a72e8692d112ba9304d6344e3dd6',
       'condition': 'checkout_src_internal',
   },
 
@@ -4689,7 +4689,7 @@
 
   'src/ios_internal':  {
       'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' +
-        '34b77766e5677df1c0699fb97f42071a468ab696',
+        '5246c294f4718ee3ff4b0003ab484359423f9818',
       'condition': 'checkout_ios and checkout_src_internal',
   },
 
diff --git a/WATCHLISTS b/WATCHLISTS
index 655ce49a..a1feae6 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -1396,7 +1396,7 @@
                   'ios/chrome/browser/resources/Settings.bundle/Experimental\.plist',
     },
     'ios_ntp': {
-      'filepath': 'ios/chrome/browser/ui/ntp/',
+      'filepath': 'ios/chrome/browser/ntp/',
     },
     'ios_payments_autofill': {
       'filepath': 'ios/chrome/browser/autofill/ui_bundled/ios_chrome_payments'\
@@ -1415,9 +1415,8 @@
                   'components/password_manager/ios|'\
                   'ios/chrome/browser/autofill|'\
                   'ios/chrome/browser/passwords|'\
-                  'ios/chrome/browser/ui/passwords|'\
-                  'ios/chrome/browser/ui/settings/autofill|'\
-                  'ios/chrome/browser/ui/settings/password',
+                  'ios/chrome/browser/settings/ui_bundled/autofill|'\
+                  'ios/chrome/browser/settings/ui_bundled/password',
     },
     'ios_web': {
       'filepath': 'ios/web(_view)?/',
@@ -1804,7 +1803,7 @@
                   '|chrome/browser/ui/.*/page_info/'\
                   '|chrome/android/java/src/org/chromium/chrome/browser/page_info/'\
                   '|components/page_info_strings.grdp'\
-                  '|ios/chrome/browser/ui/page_info/'
+                  '|ios/chrome/browser/page_info/'
     },
     'page_load_metrics' : {
       'filepath': '/page_load_metrics/'
@@ -1847,7 +1846,6 @@
                   '|content/browser/payments'\
                   '|content/test/data/payments'\
                   '|ios/chrome/browser/payments'\
-                  '|ios/chrome/browser/ui/payments'\
                   '|ios/web/payments'\
                   '|ios/web/public/payments'\
                   '|third_party/blink/web_tests/external/wpt/payment-request'\
@@ -2284,7 +2282,6 @@
                   'components/translate|'\
                   'components/translate_strings_grdp|'\
                   'ios/chrome/browser/translate|'\
-                  'ios/chrome/browser/ui/translate|'\
                   'ios/web_view/internal/translate'
     },
     'turtledove': {
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 52c546f..0ad5a70 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -582,7 +582,7 @@
 // sign in is enable. No-op if demo mode sign in is disabled.
 BASE_FEATURE(kDemoModeSignInFileCleanup,
              "DemoModeSignInFileCleanup",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 // Toggle different display features based on user setting and power state
 BASE_FEATURE(kDisplayPerformanceMode,
diff --git a/base/files/scoped_temp_file.cc b/base/files/scoped_temp_file.cc
index b00f0bc..0d4775d 100644
--- a/base/files/scoped_temp_file.cc
+++ b/base/files/scoped_temp_file.cc
@@ -22,7 +22,7 @@
     CHECK_NE(path_, other.path_);
   }
   if (!Delete()) {
-    DLOG(WARNING) << "Could not delete temp dir in operator=().";
+    DLOG(WARNING) << "Could not delete temp file in operator=().";
   }
   path_ = std::move(other.path_);
   return *this;
@@ -30,7 +30,7 @@
 
 ScopedTempFile::~ScopedTempFile() {
   if (!Delete()) {
-    DLOG(WARNING) << "Could not delete temp dir in destructor.";
+    DLOG(WARNING) << "Could not delete temp file in destructor.";
   }
 }
 
@@ -52,7 +52,7 @@
 
 void ScopedTempFile::Reset() {
   if (!Delete()) {
-    DLOG(WARNING) << "Could not delete temp dir in Reset().";
+    DLOG(WARNING) << "Could not delete temp file in Reset().";
   }
   path_.clear();
 }
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 2ca37507..1e499d56 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -229,8 +229,6 @@
     "metrics/ukm_smoothness_data.h",
     "metrics/video_playback_roughness_reporter.cc",
     "metrics/video_playback_roughness_reporter.h",
-    "raster/bitmap_raster_buffer_provider.cc",
-    "raster/bitmap_raster_buffer_provider.h",
     "raster/categorized_worker_pool.cc",
     "raster/categorized_worker_pool.h",
     "raster/gpu_raster_buffer_provider.cc",
diff --git a/cc/raster/bitmap_raster_buffer_provider.cc b/cc/raster/bitmap_raster_buffer_provider.cc
deleted file mode 100644
index 0eaf7ae..0000000
--- a/cc/raster/bitmap_raster_buffer_provider.cc
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2014 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/raster/bitmap_raster_buffer_provider.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <utility>
-
-#include "base/memory/raw_ptr.h"
-#include "base/trace_event/process_memory_dump.h"
-#include "base/trace_event/trace_event.h"
-#include "base/trace_event/traced_value.h"
-#include "cc/raster/raster_buffer.h"
-#include "cc/raster/zero_copy_raster_buffer_provider.h"
-#include "cc/trees/layer_tree_frame_sink.h"
-#include "components/viz/client/client_resource_provider.h"
-#include "components/viz/common/resources/shared_image_format.h"
-#include "gpu/command_buffer/client/client_shared_image.h"
-#include "gpu/command_buffer/common/shared_image_usage.h"
-#include "gpu/ipc/client/client_shared_image_interface.h"
-#include "ui/gfx/color_space.h"
-#include "url/gurl.h"
-
-namespace cc {
-
-BitmapRasterBufferProvider::BitmapRasterBufferProvider(
-    LayerTreeFrameSink* frame_sink)
-    : shared_image_interface_(frame_sink->shared_image_interface()) {
-  CHECK(shared_image_interface_)
-      << "SharedImageInterface is null in BitmapRasterBufferProvider ctor!";
-}
-
-BitmapRasterBufferProvider::~BitmapRasterBufferProvider() = default;
-
-std::unique_ptr<RasterBuffer>
-BitmapRasterBufferProvider::AcquireBufferForRaster(
-    const ResourcePool::InUsePoolResource& resource,
-    uint64_t resource_content_id,
-    uint64_t previous_content_id,
-    bool depends_on_at_raster_decodes,
-    bool depends_on_hardware_accelerated_jpeg_candidates,
-    bool depends_on_hardware_accelerated_webp_candidates) {
-  bool resource_has_previous_content =
-      resource_content_id && resource_content_id == previous_content_id;
-  return std::make_unique<ZeroCopyRasterBufferImpl>(
-      resource, shared_image_interface_, resource_has_previous_content);
-}
-
-void BitmapRasterBufferProvider::Flush() {}
-
-viz::SharedImageFormat BitmapRasterBufferProvider::GetFormat() const {
-  return viz::SinglePlaneFormat::kBGRA_8888;
-}
-
-bool BitmapRasterBufferProvider::IsResourcePremultiplied() const {
-  return true;
-}
-
-bool BitmapRasterBufferProvider::CanPartialRasterIntoProvidedResource() const {
-  return true;
-}
-
-bool BitmapRasterBufferProvider::IsResourceReadyToDraw(
-    const ResourcePool::InUsePoolResource& resource) {
-  // Bitmap resources are immediately ready to draw.
-  return true;
-}
-
-uint64_t BitmapRasterBufferProvider::SetReadyToDrawCallback(
-    const std::vector<const ResourcePool::InUsePoolResource*>& resources,
-    base::OnceClosure callback,
-    uint64_t pending_callback_id) {
-  // Bitmap resources are immediately ready to draw.
-  return 0;
-}
-
-void BitmapRasterBufferProvider::Shutdown() {}
-
-}  // namespace cc
diff --git a/cc/raster/bitmap_raster_buffer_provider.h b/cc/raster/bitmap_raster_buffer_provider.h
deleted file mode 100644
index 2491b01..0000000
--- a/cc/raster/bitmap_raster_buffer_provider.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2014 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_RASTER_BITMAP_RASTER_BUFFER_PROVIDER_H_
-#define CC_RASTER_BITMAP_RASTER_BUFFER_PROVIDER_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <vector>
-
-#include "base/memory/raw_ptr.h"
-#include "cc/raster/raster_buffer_provider.h"
-
-namespace base {
-namespace trace_event {
-class ConvertableToTraceFormat;
-}
-}
-
-namespace gpu {
-class SharedImageInterface;
-}
-
-namespace cc {
-class LayerTreeFrameSink;
-
-class CC_EXPORT BitmapRasterBufferProvider : public RasterBufferProvider {
- public:
-  BitmapRasterBufferProvider(const BitmapRasterBufferProvider&) = delete;
-  ~BitmapRasterBufferProvider() override;
-
-  BitmapRasterBufferProvider& operator=(const BitmapRasterBufferProvider&) =
-      delete;
-
-  explicit BitmapRasterBufferProvider(LayerTreeFrameSink* frame_sink);
-
-  // Overridden from RasterBufferProvider:
-  std::unique_ptr<RasterBuffer> AcquireBufferForRaster(
-      const ResourcePool::InUsePoolResource& resource,
-      uint64_t resource_content_id,
-      uint64_t previous_content_id,
-      bool depends_on_at_raster_decodes,
-      bool depends_on_hardware_accelerated_jpeg_candidates,
-      bool depends_on_hardware_accelerated_webp_candidates) override;
-  viz::SharedImageFormat GetFormat() const override;
-  bool IsResourcePremultiplied() const override;
-  bool CanPartialRasterIntoProvidedResource() const override;
-  bool IsResourceReadyToDraw(
-      const ResourcePool::InUsePoolResource& resource) override;
-  uint64_t SetReadyToDrawCallback(
-      const std::vector<const ResourcePool::InUsePoolResource*>& resources,
-      base::OnceClosure callback,
-      uint64_t pending_callback_id) override;
-  void Shutdown() override;
-
- protected:
-  void Flush() override;
-
- private:
-  std::unique_ptr<base::trace_event::ConvertableToTraceFormat> StateAsValue()
-      const;
-
-  scoped_refptr<gpu::SharedImageInterface> shared_image_interface_;
-};
-
-}  // namespace cc
-
-#endif  // CC_RASTER_BITMAP_RASTER_BUFFER_PROVIDER_H_
diff --git a/cc/raster/raster_buffer_provider_perftest.cc b/cc/raster/raster_buffer_provider_perftest.cc
index 8699ae5..f5c0264 100644
--- a/cc/raster/raster_buffer_provider_perftest.cc
+++ b/cc/raster/raster_buffer_provider_perftest.cc
@@ -20,7 +20,6 @@
 #include "base/time/time.h"
 #include "base/timer/lap_timer.h"
 #include "build/build_config.h"
-#include "cc/raster/bitmap_raster_buffer_provider.h"
 #include "cc/raster/gpu_raster_buffer_provider.h"
 #include "cc/raster/one_copy_raster_buffer_provider.h"
 #include "cc/raster/raster_query_queue.h"
@@ -394,8 +393,9 @@
         break;
       case RASTER_BUFFER_PROVIDER_TYPE_BITMAP:
         CreateSoftwareResourceProvider();
-        raster_buffer_provider_ = std::make_unique<BitmapRasterBufferProvider>(
-            layer_tree_frame_sink_.get());
+        raster_buffer_provider_ =
+            std::make_unique<ZeroCopyRasterBufferProvider>(
+                layer_tree_frame_sink_.get());
         break;
     }
     DCHECK(raster_buffer_provider_);
@@ -561,7 +561,7 @@
       case RASTER_BUFFER_PROVIDER_TYPE_GPU:
         return std::string("_gpu_raster_buffer_provider");
       case RASTER_BUFFER_PROVIDER_TYPE_BITMAP:
-        return std::string("_bitmap_raster_buffer_provider");
+        return std::string("_sw_compositing_zero_copy_raster_buffer_provider");
     }
     NOTREACHED();
   }
diff --git a/cc/raster/raster_buffer_provider_unittest.cc b/cc/raster/raster_buffer_provider_unittest.cc
index 469efdd..014ad1be 100644
--- a/cc/raster/raster_buffer_provider_unittest.cc
+++ b/cc/raster/raster_buffer_provider_unittest.cc
@@ -31,7 +31,6 @@
 #include "build/build_config.h"
 #include "cc/base/unique_notifier.h"
 #include "cc/paint/draw_image.h"
-#include "cc/raster/bitmap_raster_buffer_provider.h"
 #include "cc/raster/gpu_raster_buffer_provider.h"
 #include "cc/raster/one_copy_raster_buffer_provider.h"
 #include "cc/raster/raster_query_queue.h"
@@ -200,8 +199,9 @@
         break;
       case RASTER_BUFFER_PROVIDER_TYPE_BITMAP:
         CreateSoftwareResourceProvider();
-        raster_buffer_provider_ = std::make_unique<BitmapRasterBufferProvider>(
-            layer_tree_frame_sink_.get());
+        raster_buffer_provider_ =
+            std::make_unique<ZeroCopyRasterBufferProvider>(
+                layer_tree_frame_sink_.get());
         break;
     }
 
diff --git a/cc/raster/zero_copy_raster_buffer_provider.cc b/cc/raster/zero_copy_raster_buffer_provider.cc
index 8765b0952..394674b 100644
--- a/cc/raster/zero_copy_raster_buffer_provider.cc
+++ b/cc/raster/zero_copy_raster_buffer_provider.cc
@@ -14,6 +14,7 @@
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/traced_value.h"
 #include "cc/resources/resource_pool.h"
+#include "cc/trees/layer_tree_frame_sink.h"
 #include "components/viz/client/client_resource_provider.h"
 #include "components/viz/common/gpu/raster_context_provider.h"
 #include "components/viz/common/resources/platform_color.h"
@@ -22,6 +23,7 @@
 #include "gpu/command_buffer/client/shared_image_interface.h"
 #include "gpu/command_buffer/common/shared_image_trace_utils.h"
 #include "gpu/command_buffer/common/shared_image_usage.h"
+#include "gpu/ipc/client/client_shared_image_interface.h"
 #include "ui/gfx/buffer_format_util.h"
 #include "url/gurl.h"
 
@@ -34,18 +36,29 @@
 
 ZeroCopyRasterBufferImpl::ZeroCopyRasterBufferImpl(
     const ResourcePool::InUsePoolResource& in_use_resource,
-    scoped_refptr<gpu::SharedImageInterface> sii)
-    : sii_(sii) {
+    scoped_refptr<gpu::SharedImageInterface> sii,
+    bool resource_has_previous_content,
+    bool is_software)
+    : sii_(sii),
+      resource_has_previous_content_(resource_has_previous_content),
+      is_software_(is_software) {
   if (!in_use_resource.backing()) {
-    auto backing = std::make_unique<ResourcePool::Backing>(
-        in_use_resource.size(), in_use_resource.format(),
-        in_use_resource.color_space());
-    // This RasterBufferProvider will modify the resource outside of the
-    // GL command stream. So resources should not become available for reuse
-    // until they are not in use by the gpu anymore, which a fence is used
-    // to determine.
-    backing->wait_on_fence_required = true;
-    in_use_resource.set_backing(std::move(backing));
+    if (is_software) {
+      in_use_resource.InstallSoftwareBacking(
+          sii, "ZeroCopyRasterBufferProviderSoftware");
+      in_use_resource.backing()->mailbox_sync_token =
+          sii->GenVerifiedSyncToken();
+    } else {
+      auto backing = std::make_unique<ResourcePool::Backing>(
+          in_use_resource.size(), in_use_resource.format(),
+          in_use_resource.color_space());
+      // This RasterBufferProvider will modify the resource outside of the
+      // GL command stream. So resources should not become available for reuse
+      // until they are not in use by the gpu anymore, which a fence is used
+      // to determine.
+      backing->wait_on_fence_required = true;
+      in_use_resource.set_backing(std::move(backing));
+    }
   }
   backing_ = in_use_resource.backing();
   if (!backing_->shared_image()) {
@@ -58,20 +71,6 @@
   }
 }
 
-ZeroCopyRasterBufferImpl::ZeroCopyRasterBufferImpl(
-    const ResourcePool::InUsePoolResource& in_use_resource,
-    scoped_refptr<gpu::SharedImageInterface> sii,
-    bool resource_has_previous_content)
-    : resource_has_previous_content_(resource_has_previous_content),
-      is_software_(true) {
-  if (!in_use_resource.backing()) {
-    in_use_resource.InstallSoftwareBacking(sii, "BitmapRasterBufferProvider");
-
-    in_use_resource.backing()->mailbox_sync_token = sii->GenVerifiedSyncToken();
-  }
-  backing_ = in_use_resource.backing();
-}
-
 ZeroCopyRasterBufferImpl::~ZeroCopyRasterBufferImpl() {
   // This raster task is complete, so if the backing's SharedImage was created
   // on a worker thread during the raster work that has now happened.
@@ -172,6 +171,14 @@
     : compositor_context_provider_(compositor_context_provider),
       tile_format_(raster_caps.tile_format) {}
 
+ZeroCopyRasterBufferProvider::ZeroCopyRasterBufferProvider(
+    LayerTreeFrameSink* frame_sink)
+    : is_software_(true),
+      shared_image_interface_(frame_sink->shared_image_interface()) {
+  CHECK(shared_image_interface_)
+      << "SharedImageInterface is null in ZeroCopyRasterBufferProvider ctor!";
+}
+
 ZeroCopyRasterBufferProvider::~ZeroCopyRasterBufferProvider() = default;
 
 std::unique_ptr<RasterBuffer>
@@ -182,15 +189,25 @@
     bool depends_on_at_raster_decodes,
     bool depends_on_hardware_accelerated_jpeg_candidates,
     bool depends_on_hardware_accelerated_webp_candidates) {
+  if (is_software_) {
+    bool resource_has_previous_content =
+        resource_content_id && resource_content_id == previous_content_id;
+    return std::make_unique<ZeroCopyRasterBufferImpl>(
+        resource, shared_image_interface_, resource_has_previous_content,
+        /*is_software=*/true);
+  }
+
   return std::make_unique<ZeroCopyRasterBufferImpl>(
-      resource, base::WrapRefCounted(
-                    compositor_context_provider_->SharedImageInterface()));
+      resource,
+      base::WrapRefCounted(
+          compositor_context_provider_->SharedImageInterface()),
+      /*resource_has_previous_content=*/false, /*is_software=*/false);
 }
 
 void ZeroCopyRasterBufferProvider::Flush() {}
 
 viz::SharedImageFormat ZeroCopyRasterBufferProvider::GetFormat() const {
-  return tile_format_;
+  return (is_software_) ? viz::SinglePlaneFormat::kBGRA_8888 : tile_format_;
 }
 
 bool ZeroCopyRasterBufferProvider::IsResourcePremultiplied() const {
@@ -199,7 +216,7 @@
 
 bool ZeroCopyRasterBufferProvider::CanPartialRasterIntoProvidedResource()
     const {
-  return false;
+  return is_software_;
 }
 
 bool ZeroCopyRasterBufferProvider::IsResourceReadyToDraw(
diff --git a/cc/raster/zero_copy_raster_buffer_provider.h b/cc/raster/zero_copy_raster_buffer_provider.h
index 45e7d06..ac326ce 100644
--- a/cc/raster/zero_copy_raster_buffer_provider.h
+++ b/cc/raster/zero_copy_raster_buffer_provider.h
@@ -22,7 +22,12 @@
 }
 }
 
+namespace gpu {
+class SharedImageInterface;
+}
+
 namespace cc {
+class LayerTreeFrameSink;
 
 // RasterBuffer for the zero copy upload, which is given to the raster worker
 // threads for raster/upload.
@@ -30,14 +35,9 @@
  public:
   ZeroCopyRasterBufferImpl(
       const ResourcePool::InUsePoolResource& in_use_resource,
-      scoped_refptr<gpu::SharedImageInterface> sii);
-  // Used with the software compositor.
-  // TODO(crbug.com/403372453): Unify with above constructor in followup via
-  // `is_software` param.
-  ZeroCopyRasterBufferImpl(
-      const ResourcePool::InUsePoolResource& in_use_resource,
       scoped_refptr<gpu::SharedImageInterface> sii,
-      bool resource_has_previous_content);
+      bool resource_has_previous_content,
+      bool is_software);
 
   ZeroCopyRasterBufferImpl(const ZeroCopyRasterBufferImpl&) = delete;
 
@@ -70,6 +70,10 @@
   ZeroCopyRasterBufferProvider(
       viz::RasterContextProvider* compositor_context_provider,
       const RasterCapabilities& raster_caps);
+
+  // Constructor used with software compositing.
+  explicit ZeroCopyRasterBufferProvider(LayerTreeFrameSink* frame_sink);
+
   ZeroCopyRasterBufferProvider(const ZeroCopyRasterBufferProvider&) = delete;
   ~ZeroCopyRasterBufferProvider() override;
 
@@ -102,8 +106,14 @@
   std::unique_ptr<base::trace_event::ConvertableToTraceFormat> StateAsValue()
       const;
 
+  bool is_software_ = false;
+
+  // Used with the GPU compositor.
   raw_ptr<viz::RasterContextProvider> compositor_context_provider_;
   const viz::SharedImageFormat tile_format_;
+
+  // Used with the software compositor.
+  scoped_refptr<gpu::SharedImageInterface> shared_image_interface_;
 };
 
 }  // namespace cc
diff --git a/cc/test/layer_tree_pixel_resource_test.cc b/cc/test/layer_tree_pixel_resource_test.cc
index 23f718b2..2e61bc2 100644
--- a/cc/test/layer_tree_pixel_resource_test.cc
+++ b/cc/test/layer_tree_pixel_resource_test.cc
@@ -6,7 +6,6 @@
 
 #include "base/task/single_thread_task_runner.h"
 #include "cc/layers/layer.h"
-#include "cc/raster/bitmap_raster_buffer_provider.h"
 #include "cc/raster/gpu_raster_buffer_provider.h"
 #include "cc/raster/one_copy_raster_buffer_provider.h"
 #include "cc/raster/raster_buffer_provider.h"
@@ -77,7 +76,7 @@
       EXPECT_FALSE(compositor_context_provider);
       EXPECT_TRUE(use_software_renderer());
 
-      return std::make_unique<BitmapRasterBufferProvider>(
+      return std::make_unique<ZeroCopyRasterBufferProvider>(
           host_impl->layer_tree_frame_sink());
     case TestRasterType::kGpu:
       EXPECT_TRUE(compositor_context_provider);
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 8bd3e6e..21f476b0 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -81,7 +81,6 @@
 #include "cc/paint/display_item_list.h"
 #include "cc/paint/paint_worklet_job.h"
 #include "cc/paint/paint_worklet_layer_painter.h"
-#include "cc/raster/bitmap_raster_buffer_provider.h"
 #include "cc/raster/gpu_raster_buffer_provider.h"
 #include "cc/raster/one_copy_raster_buffer_provider.h"
 #include "cc/raster/raster_buffer_provider.h"
@@ -4191,7 +4190,8 @@
       layer_tree_frame_sink_->context_provider();
 
   if (!compositor_context_provider) {
-    return std::make_unique<BitmapRasterBufferProvider>(layer_tree_frame_sink_);
+    return std::make_unique<ZeroCopyRasterBufferProvider>(
+        layer_tree_frame_sink_);
   }
 
   const gpu::Capabilities& caps =
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index c7f5b56..7ae6e03 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -470,6 +470,8 @@
   "java/src/org/chromium/chrome/browser/customtabs/content/RealtimeEngagementSignalObserver.java",
   "java/src/org/chromium/chrome/browser/customtabs/content/TabCreationMode.java",
   "java/src/org/chromium/chrome/browser/customtabs/content/TabObserverRegistrar.java",
+  "java/src/org/chromium/chrome/browser/customtabs/content/WebAppLaunchHandler.java",
+  "java/src/org/chromium/chrome/browser/customtabs/content/WebAppLaunchParams.java",
   "java/src/org/chromium/chrome/browser/customtabs/features/CustomTabDimensionUtils.java",
   "java/src/org/chromium/chrome/browser/customtabs/features/CustomTabNavigationBarController.java",
   "java/src/org/chromium/chrome/browser/customtabs/features/ImmersiveModeController.java",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
index 6a19814b..b3c3a004 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
@@ -1245,7 +1245,7 @@
     }
 
     @Override
-    public @Nullable String getUrlToLoad() {
+    public String getUrlToLoad() {
         if (mUrlToLoad == null) {
             mUrlToLoad = resolveUrlToLoad(getIntent());
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/IncognitoCustomTabIntentDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/IncognitoCustomTabIntentDataProvider.java
index 8db94bd1..312bff4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/IncognitoCustomTabIntentDataProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/IncognitoCustomTabIntentDataProvider.java
@@ -60,7 +60,7 @@
     private final boolean mShowShareItem;
     private final List<Pair<String, PendingIntent>> mMenuEntries = new ArrayList<>();
 
-    @Nullable private final String mUrlToLoad;
+    private final String mUrlToLoad;
     private final String mSendersPackageName;
 
     /** Whether this CustomTabActivity was explicitly started by another Chrome Activity. */
@@ -72,7 +72,7 @@
     public IncognitoCustomTabIntentDataProvider(Intent intent, Context context, int colorScheme) {
         assert intent != null;
         mIntent = intent;
-        mUrlToLoad = resolveUrlToLoad(intent);
+        mUrlToLoad = IntentHandler.getUrlFromIntent(intent);
         CustomTabsSessionToken token = CustomTabsSessionToken.getSessionTokenFromIntent(intent);
         mSession = token != null ? new SessionHolder<>(token) : null;
         mSendersPackageName = getClientPackageNameFromSessionOrCallingActivity(intent, mSession);
@@ -231,10 +231,6 @@
         return isTrusted;
     }
 
-    private String resolveUrlToLoad(Intent intent) {
-        return IntentHandler.getUrlFromIntent(intent);
-    }
-
     public String getSendersPackageName() {
         return mSendersPackageName;
     }
@@ -284,7 +280,7 @@
     }
 
     @Override
-    public @Nullable String getUrlToLoad() {
+    public String getUrlToLoad() {
         return mUrlToLoad;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/DefaultCustomTabIntentHandlingStrategy.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/DefaultCustomTabIntentHandlingStrategy.java
index f10161c..a062b7ca 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/DefaultCustomTabIntentHandlingStrategy.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/DefaultCustomTabIntentHandlingStrategy.java
@@ -6,9 +6,12 @@
 
 import android.text.TextUtils;
 
+import androidx.browser.trusted.LaunchHandlerClientMode;
+
 import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider;
 import org.chromium.chrome.browser.customtabs.CustomTabAuthUrlHeuristics;
 import org.chromium.chrome.browser.customtabs.CustomTabObserver;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.components.embedder_support.util.UrlUtilities;
 import org.chromium.content_public.browser.LoadUrlParams;
@@ -79,8 +82,23 @@
         mNavigationController.navigate(params, intentDataProvider.getIntent());
     }
 
+    private WebAppLaunchParams handleLaunch(BrowserServicesIntentDataProvider intentDataProvider) {
+        String packageName = intentDataProvider.getClientPackageName();
+        return WebAppLaunchHandler.getLaunchParams(
+                LaunchHandlerClientMode.NAVIGATE_EXISTING,
+                intentDataProvider.getUrlToLoad(),
+                packageName);
+    }
+
     @Override
     public void handleNewIntent(BrowserServicesIntentDataProvider intentDataProvider) {
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.ANDROID_WEB_APP_LAUNCH_HANDLER)) {
+            WebAppLaunchParams launchParams = handleLaunch(intentDataProvider);
+            if (!launchParams.startNewNavigation) {
+                return;
+            }
+        }
+
         String url = intentDataProvider.getUrlToLoad();
         if (TextUtils.isEmpty(url)) return;
         LoadUrlParams params = new LoadUrlParams(url);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/WebAppLaunchHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/WebAppLaunchHandler.java
new file mode 100644
index 0000000..49b5b45c
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/WebAppLaunchHandler.java
@@ -0,0 +1,55 @@
+// Copyright 2025 The Chromium Authors
+// 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.customtabs.content;
+
+import static androidx.browser.trusted.LaunchHandlerClientMode.FOCUS_EXISTING;
+import static androidx.browser.trusted.LaunchHandlerClientMode.NAVIGATE_EXISTING;
+import static androidx.browser.trusted.LaunchHandlerClientMode.NAVIGATE_NEW;
+
+import androidx.browser.trusted.LaunchHandlerClientMode.ClientMode;
+
+import java.util.Arrays;
+
+/**
+ * Manages web application launch configurations based on client mode. Provides methods to process
+ * client mode and generate launch parameters.
+ */
+public class WebAppLaunchHandler {
+
+    public static final @ClientMode int DEFAULT_CLIENT_MODE = NAVIGATE_EXISTING;
+
+    /**
+     * Retrieves the ClientMode enum value from a given AndroidX enum. Defaults to
+     * DEFAULT_CLIENT_MODE if the value is invalid or AUTO.
+     *
+     * @param clientMode The AndroidX representation of the client mode.
+     * @return The corresponding ClientMode enum value.
+     */
+    public static @ClientMode int getClientMode(@ClientMode int clientMode) {
+        if (Arrays.asList(NAVIGATE_EXISTING, FOCUS_EXISTING, NAVIGATE_NEW).contains(clientMode)) {
+            return clientMode;
+        } else {
+            return DEFAULT_CLIENT_MODE;
+        }
+    }
+
+    /**
+     * Generates WebAppLaunchParams based on the AndroidX representation of the client mode.
+     *
+     * @param clientModeParam The AndroidX representation of the client mode.
+     * @param targetUrl The URL to launch.
+     * @param packageName Android package name of the web app is being launched.
+     * @return The generated WebAppLaunchParams object.
+     */
+    public static WebAppLaunchParams getLaunchParams(
+            @ClientMode int clientModeParam, String targetUrl, String packageName) {
+        @ClientMode int clientMode = getClientMode(clientModeParam);
+
+        boolean startedNewNavigation = clientMode != FOCUS_EXISTING;
+        return new WebAppLaunchParams(startedNewNavigation, targetUrl, packageName);
+    }
+
+    private WebAppLaunchHandler() {}
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/WebAppLaunchParams.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/WebAppLaunchParams.java
new file mode 100644
index 0000000..c1cb045
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/WebAppLaunchParams.java
@@ -0,0 +1,32 @@
+// Copyright 2025 The Chromium Authors
+// 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.customtabs.content;
+
+/**
+ * Represents the LaunchParams values to be sent to a web app on app launch and whether the launch
+ * triggered a navigation or not.
+ */
+public class WebAppLaunchParams {
+    /**
+     * Whether this launch triggered a navigation that needs to be awaited before sending the launch
+     * params to the document.
+     */
+    public final boolean startNewNavigation;
+
+    /** The app being launched, used for scope validation. */
+    public final String packageName;
+
+    /**
+     * The URL the web app was launched with. Note that redirects may cause us to enqueue in a
+     * different URL, we still report the original launch target URL in the launch params.
+     */
+    public final String targetUrl;
+
+    public WebAppLaunchParams(boolean startNewNavigation, String targetUrl, String packageName) {
+        this.startNewNavigation = startNewNavigation;
+        this.targetUrl = targetUrl;
+        this.packageName = packageName;
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappIntentDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappIntentDataProvider.java
index a26c2455..9c745b7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappIntentDataProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappIntentDataProvider.java
@@ -101,7 +101,7 @@
     }
 
     @Override
-    public @Nullable String getUrlToLoad() {
+    public String getUrlToLoad() {
         return mWebappExtras.url;
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webid/DigitalCredentialProviderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webid/DigitalCredentialProviderTest.java
index d4ed16a..124822d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webid/DigitalCredentialProviderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webid/DigitalCredentialProviderTest.java
@@ -76,7 +76,9 @@
                         input ->
                                 Promise.fulfilled(
                                         new DigitalCredential(
-                                                "protocol", EXPECTED_MDOC.getBytes())));
+                                                "protocol",
+                                                ("{\"token\": \"" + EXPECTED_MDOC + "\"}")
+                                                        .getBytes())));
 
         mActivityTestRule.loadUrl(mTestServer.getURL(TEST_PAGE));
         DOMUtils.clickNode(mActivityTestRule.getWebContents(), "request_age_only_button");
@@ -100,7 +102,10 @@
     @EnableFeatures(ContentFeatureList.WEB_IDENTITY_DIGITAL_CREDENTIALS_CREATION)
     public void testCreate() throws TimeoutException {
         when(mDelegate.create(any(), any(), any()))
-                .thenAnswer(input -> Promise.fulfilled(EXPECTED_CREATION_RESPONSE));
+                .thenAnswer(
+                        input ->
+                                Promise.fulfilled(
+                                        ("{\"token\": \"" + EXPECTED_CREATION_RESPONSE + "\"}")));
 
         mActivityTestRule.loadUrl(mTestServer.getURL(TEST_PAGE));
         DOMUtils.clickNode(mActivityTestRule.getWebContents(), "create_button");
diff --git a/chrome/android/junit/BUILD.gn b/chrome/android/junit/BUILD.gn
index 300bbc7..8e03255 100644
--- a/chrome/android/junit/BUILD.gn
+++ b/chrome/android/junit/BUILD.gn
@@ -664,6 +664,7 @@
       "src/org/chromium/chrome/browser/customtabs/content/EngagementSignalsHandlerUnitTest.java",
       "src/org/chromium/chrome/browser/customtabs/content/EngagementSignalsInitialScrollObserverUnitTest.java",
       "src/org/chromium/chrome/browser/customtabs/content/RealtimeEngagementSignalObserverUnitTest.java",
+      "src/org/chromium/chrome/browser/customtabs/content/WebAppLaunchHandlerTest.java",
       "src/org/chromium/chrome/browser/customtabs/features/ImmersiveModeControllerTest.java",
       "src/org/chromium/chrome/browser/customtabs/features/TabInteractionRecorderUnitTest.java",
       "src/org/chromium/chrome/browser/customtabs/features/minimizedcustomtab/CustomTabMinimizationManagerUnitTest.java",
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityUrlLoadingTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityUrlLoadingTest.java
index 3ed2134..b5f164e 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityUrlLoadingTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityUrlLoadingTest.java
@@ -58,7 +58,10 @@
 @Config(
         manifest = Config.NONE,
         shadows = {CustomTabActivityUrlLoadingTest.ShadowOrigin.class})
-@Features.EnableFeatures(ChromeFeatureList.CCT_PREWARM_TAB)
+@Features.EnableFeatures({
+    ChromeFeatureList.CCT_PREWARM_TAB,
+    ChromeFeatureList.ANDROID_WEB_APP_LAUNCH_HANDLER
+})
 public class CustomTabActivityUrlLoadingTest {
     @Implements(Origin.class)
     public static class ShadowOrigin {
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/WebAppLaunchHandlerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/WebAppLaunchHandlerTest.java
new file mode 100644
index 0000000..6f7aa0b
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/WebAppLaunchHandlerTest.java
@@ -0,0 +1,69 @@
+// Copyright 2025 The Chromium Authors
+// 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.customtabs.content;
+
+import androidx.browser.trusted.LaunchHandlerClientMode;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.base.test.util.Batch;
+import org.chromium.url.JUnitTestGURLs;
+
+/** Tests for {@link WebAppLaunchHandler}. */
+@RunWith(BaseRobolectricTestRunner.class)
+@Batch(Batch.UNIT_TESTS)
+@Config(manifest = Config.NONE)
+public class WebAppLaunchHandlerTest {
+
+    @Test
+    public void getClientMode() {
+        int clientMode =
+                WebAppLaunchHandler.getClientMode(LaunchHandlerClientMode.NAVIGATE_EXISTING);
+        Assert.assertEquals(LaunchHandlerClientMode.NAVIGATE_EXISTING, clientMode);
+
+        clientMode = WebAppLaunchHandler.getClientMode(LaunchHandlerClientMode.FOCUS_EXISTING);
+        Assert.assertEquals(LaunchHandlerClientMode.FOCUS_EXISTING, clientMode);
+
+        clientMode = WebAppLaunchHandler.getClientMode(LaunchHandlerClientMode.NAVIGATE_NEW);
+        Assert.assertEquals(LaunchHandlerClientMode.NAVIGATE_NEW, clientMode);
+
+        clientMode = WebAppLaunchHandler.getClientMode(LaunchHandlerClientMode.AUTO);
+        Assert.assertEquals(LaunchHandlerClientMode.NAVIGATE_EXISTING, clientMode);
+
+        clientMode = WebAppLaunchHandler.getClientMode(45); // Invalid argument
+        Assert.assertEquals(LaunchHandlerClientMode.NAVIGATE_EXISTING, clientMode);
+    }
+
+    @Test
+    public void getLaunchParams() {
+        String url = JUnitTestGURLs.INITIAL_URL.getSpec();
+        String packageName = null;
+        WebAppLaunchParams launchParams =
+                WebAppLaunchHandler.getLaunchParams(
+                        LaunchHandlerClientMode.NAVIGATE_EXISTING, url, packageName);
+        Assert.assertTrue(launchParams.startNewNavigation);
+
+        launchParams =
+                WebAppLaunchHandler.getLaunchParams(
+                        LaunchHandlerClientMode.FOCUS_EXISTING, url, packageName);
+        Assert.assertFalse(launchParams.startNewNavigation);
+
+        launchParams =
+                WebAppLaunchHandler.getLaunchParams(
+                        LaunchHandlerClientMode.NAVIGATE_NEW, url, packageName);
+        Assert.assertTrue(launchParams.startNewNavigation);
+
+        launchParams =
+                WebAppLaunchHandler.getLaunchParams(LaunchHandlerClientMode.AUTO, url, packageName);
+        Assert.assertTrue(launchParams.startNewNavigation);
+
+        launchParams = WebAppLaunchHandler.getLaunchParams(65, url, packageName);
+        Assert.assertTrue(launchParams.startNewNavigation);
+    }
+}
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 18fa9de8..131c67b6 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -653,6 +653,15 @@
   <message name="IDS_SETTINGS_AUTOFILL_AI_ACCESSIBILITY_LABEL_YEAR_DROPDOWN" desc="The accessibility label on the year dropdown of a date field, to let users know the dropdown corresponds to the year.">
     <ph name="DROPDOWN_NAME">$1<ex>Expiration date</ex></ph> year
   </message>
+  <message name="IDS_SETTINGS_AUTOFILL_AI_MONTH_DROPDOWN_NO_OPTION_SELECTED" desc="The default option in a dropdown menu that serves both to suggest to the user that they select something and also allows them to not select anything (by leaving the default value chosen). For example, a month dropdown includes the values 'MM, Jan, Feb, Mar, etc.'. The user can choose to leave 'MM' selected — effectively not choosing a month at all.">
+    MM
+  </message>
+  <message name="IDS_SETTINGS_AUTOFILL_AI_DAY_DROPDOWN_NO_OPTION_SELECTED" desc="The default option in a dropdown menu that serves both to suggest to the user that they select something and also allows them to not select anything (by leaving the default value chosen). For example, a day dropdown includes the values 'DD, 1, 2, 3, etc.'. The user can choose to leave 'DD' selected — effectively not choosing a day at all.">
+    DD
+  </message>
+  <message name="IDS_SETTINGS_AUTOFILL_AI_YEAR_DROPDOWN_NO_OPTION_SELECTED" desc="The default option in a dropdown menu that serves both to suggest to the user that they select something and also allows them to not select anything (by leaving the default value chosen). For example, a year dropdown includes the values 'YYYY, 2025, 2024, 2023, etc.'. The user can choose to leave 'YYYY' selected — effectively not choosing a year at all.">
+    YYYY
+  </message>
   <message name="IDS_SETTINGS_AUTOFILL_AI_ADD_OR_EDIT_DIALOG_DATE_VALIDATION_ERROR" desc="An error message that appears beneath a date picker in the case that the user doesn't add a full date. For example, the user sees this error if they set the month but not the day or year, or choose an invalid date like February 30.">
     Check the date
   </message>
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_AUTOFILL_AI_DAY_DROPDOWN_NO_OPTION_SELECTED.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_AUTOFILL_AI_DAY_DROPDOWN_NO_OPTION_SELECTED.png.sha1
new file mode 100644
index 0000000..5cedecf
--- /dev/null
+++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_AUTOFILL_AI_DAY_DROPDOWN_NO_OPTION_SELECTED.png.sha1
@@ -0,0 +1 @@
+28bd24236452a22fd2cbb7ad79b76b53d7d39ab4
\ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_AUTOFILL_AI_MONTH_DROPDOWN_NO_OPTION_SELECTED.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_AUTOFILL_AI_MONTH_DROPDOWN_NO_OPTION_SELECTED.png.sha1
new file mode 100644
index 0000000..5cedecf
--- /dev/null
+++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_AUTOFILL_AI_MONTH_DROPDOWN_NO_OPTION_SELECTED.png.sha1
@@ -0,0 +1 @@
+28bd24236452a22fd2cbb7ad79b76b53d7d39ab4
\ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_AUTOFILL_AI_YEAR_DROPDOWN_NO_OPTION_SELECTED.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_AUTOFILL_AI_YEAR_DROPDOWN_NO_OPTION_SELECTED.png.sha1
new file mode 100644
index 0000000..5cedecf
--- /dev/null
+++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_AUTOFILL_AI_YEAR_DROPDOWN_NO_OPTION_SELECTED.png.sha1
@@ -0,0 +1 @@
+28bd24236452a22fd2cbb7ad79b76b53d7d39ab4
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index fd02559..22dfae2 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -6790,6 +6790,7 @@
       "//chrome/browser/enterprise/connectors/device_trust/key_management/browser",
       "//chrome/browser/enterprise/connectors/device_trust/key_management/core",
       "//chrome/browser/enterprise/connectors/device_trust/key_management/core/persistence",
+      "//chrome/browser/ui/webui/signin/history_sync_optin:mojo_bindings",
       "//chrome/services/system_signals/public/cpp/browser",
       "//components/supervised_user/core/common:features",
     ]
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index d32f9002..85b4ab2de 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -12024,12 +12024,12 @@
      FEATURE_VALUE_TYPE(
          autofill::features::kAutofillEnableNewFopDisplayDesktop)},
 
-#if BUILDFLAG(IS_CHROMEOS) && BUILDFLAG(ENABLE_EXTENSIONS)
+#if BUILDFLAG(IS_CHROMEOS)
     {"enable-printing-margins-and-scale",
      flag_descriptions::kEnablePrintingMarginsAndScale,
      flag_descriptions::kEnablePrintingMarginsAndScaleDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(extensions_features::kApiPrintingMarginsAndScale)},
-#endif  // BUILDFLAG(IS_CHROMEOS) && BUILDFLAG(ENABLE_EXTENSIONS)
+     FEATURE_VALUE_TYPE(printing::features::kApiPrintingMarginsAndScale)},
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
     {"supervised-user-block-interstitial-v3",
      flag_descriptions::kSupervisedUserBlockInterstitialV3Name,
diff --git a/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/BrowserServicesIntentDataProvider.java b/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/BrowserServicesIntentDataProvider.java
index 69b4e725..fd91612 100644
--- a/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/BrowserServicesIntentDataProvider.java
+++ b/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/BrowserServicesIntentDataProvider.java
@@ -184,12 +184,10 @@
     }
 
     /**
-     * @return The URL that should be used from this intent.
-     * Must be called only after native has loaded.
+     * @return The URL that should be used from this intent. Must be called only after native has
+     *     loaded.
      */
-    public @Nullable String getUrlToLoad() {
-        return null;
-    }
+    public abstract String getUrlToLoad();
 
     /**
      * @return Whether url bar hiding should be enabled in the custom tab.
diff --git a/chrome/browser/ash/accessibility/accessibility_manager_browsertest.cc b/chrome/browser/ash/accessibility/accessibility_manager_browsertest.cc
index ce34d1f..a5f85527 100644
--- a/chrome/browser/ash/accessibility/accessibility_manager_browsertest.cc
+++ b/chrome/browser/ash/accessibility/accessibility_manager_browsertest.cc
@@ -1825,7 +1825,7 @@
   }
 
   void CreateSession(const AccountId& account_id) {
-    ASSERT_TRUE(user_manager::TestHelper(*user_manager::UserManager::Get())
+    ASSERT_TRUE(user_manager::TestHelper(user_manager::UserManager::Get())
                     .AddRegularUser(account_id));
 
     auto* session_manager = session_manager::SessionManager::Get();
diff --git a/chrome/browser/ash/accessibility/magnification_manager_browsertest.cc b/chrome/browser/ash/accessibility/magnification_manager_browsertest.cc
index 47aad2c1..e0b179e0 100644
--- a/chrome/browser/ash/accessibility/magnification_manager_browsertest.cc
+++ b/chrome/browser/ash/accessibility/magnification_manager_browsertest.cc
@@ -85,7 +85,7 @@
 }
 
 [[nodiscard]] bool AddRegularUser(const AccountId& account_id) {
-  return user_manager::TestHelper(*user_manager::UserManager::Get())
+  return user_manager::TestHelper(user_manager::UserManager::Get())
       .AddRegularUser(account_id);
 }
 
diff --git a/chrome/browser/ash/account_manager/account_manager_policy_controller_browsertest.cc b/chrome/browser/ash/account_manager/account_manager_policy_controller_browsertest.cc
index 3f625f3..b3219d4 100644
--- a/chrome/browser/ash/account_manager/account_manager_policy_controller_browsertest.cc
+++ b/chrome/browser/ash/account_manager/account_manager_policy_controller_browsertest.cc
@@ -71,7 +71,7 @@
     const AccountId account_id = AccountId::FromUserEmailGaiaId(
         kFakePrimaryUsername,
         signin::GetTestGaiaIdForEmail(kFakePrimaryUsername));
-    ASSERT_TRUE(user_manager::TestHelper(*user_manager::UserManager::Get())
+    ASSERT_TRUE(user_manager::TestHelper(user_manager::UserManager::Get())
                     .AddRegularUser(account_id));
     session_manager::SessionManager::Get()->CreateSession(
         account_id, user_manager::TestHelper::GetFakeUsernameHash(account_id),
diff --git a/chrome/browser/ash/app_list/app_list_client_impl_browsertest.cc b/chrome/browser/ash/app_list/app_list_client_impl_browsertest.cc
index 69117b9..e9253fa2 100644
--- a/chrome/browser/ash/app_list/app_list_client_impl_browsertest.cc
+++ b/chrome/browser/ash/app_list/app_list_client_impl_browsertest.cc
@@ -1295,7 +1295,7 @@
     ash::ProfileHelper::SetProfileToUserForTestingEnabled(true);
     account_id_ =
         AccountId::FromUserEmailGaiaId("test@test-user", GaiaId("gaia-id"));
-    auto* user = user_manager::TestHelper(*user_manager::UserManager::Get())
+    auto* user = user_manager::TestHelper(user_manager::UserManager::Get())
                      .AddRegularUser(account_id_);
     ASSERT_TRUE(user);
     session_manager::SessionManager::Get()->CreateSession(
diff --git a/chrome/browser/ash/arc/auth/arc_auth_service_browsertest.cc b/chrome/browser/ash/arc/auth/arc_auth_service_browsertest.cc
index fe71eb3c..4e9d302 100644
--- a/chrome/browser/ash/arc/auth/arc_auth_service_browsertest.cc
+++ b/chrome/browser/ash/arc/auth/arc_auth_service_browsertest.cc
@@ -358,7 +358,7 @@
   void SetAccountAndProfile(const user_manager::UserType user_type) {
     const user_manager::User* user = nullptr;
     {
-      user_manager::TestHelper test_helper(*user_manager::UserManager::Get());
+      user_manager::TestHelper test_helper(user_manager::UserManager::Get());
       switch (user_type) {
         case user_manager::UserType::kChild:
           user = test_helper.AddChildUser(AccountId::FromUserEmailGaiaId(
diff --git a/chrome/browser/ash/arc/locked_fullscreen/arc_locked_fullscreen_manager_unittest.cc b/chrome/browser/ash/arc/locked_fullscreen/arc_locked_fullscreen_manager_unittest.cc
index 2df3c89..0d91e35 100644
--- a/chrome/browser/ash/arc/locked_fullscreen/arc_locked_fullscreen_manager_unittest.cc
+++ b/chrome/browser/ash/arc/locked_fullscreen/arc_locked_fullscreen_manager_unittest.cc
@@ -79,8 +79,8 @@
 
     const AccountId account_id(
         AccountId::FromUserEmailGaiaId(kUserEmail, GaiaId(kUserGaiaId)));
-    ASSERT_TRUE(
-        user_manager::TestHelper(*user_manager_).AddRegularUser(account_id));
+    ASSERT_TRUE(user_manager::TestHelper(user_manager_.get())
+                    .AddRegularUser(account_id));
     const std::string user_id_hash =
         user_manager::TestHelper::GetFakeUsernameHash(account_id);
     user_manager_->UserLoggedIn(account_id, user_id_hash);
diff --git a/chrome/browser/ash/bluetooth/bluetooth_log_controller_unittest.cc b/chrome/browser/ash/bluetooth/bluetooth_log_controller_unittest.cc
index e23ced2..5e2f76e 100644
--- a/chrome/browser/ash/bluetooth/bluetooth_log_controller_unittest.cc
+++ b/chrome/browser/ash/bluetooth/bluetooth_log_controller_unittest.cc
@@ -74,7 +74,7 @@
   auto* upstart_client = FakeUpstartClient::Get();
   upstart_client->StartRecordingUpstartOperations();
 
-  auto* user = user_manager::TestHelper(user_manager())
+  auto* user = user_manager::TestHelper(&user_manager())
                    .AddKioskAppUser("test@kiosk-apps.device-local.localhost");
   // TODO(b/278643115): use UserManager::UserLoggedIn() to notify observer.
   controller().OnUserLoggedIn(*user);
diff --git a/chrome/browser/ash/lobster/BUILD.gn b/chrome/browser/ash/lobster/BUILD.gn
index 0f3b15e..90482d94 100644
--- a/chrome/browser/ash/lobster/BUILD.gn
+++ b/chrome/browser/ash/lobster/BUILD.gn
@@ -54,6 +54,7 @@
     "//chrome/browser/resources/chromeos/mako:resources",
     "//chrome/browser/ui/webui/ash/lobster:lobster",
     "//chromeos/ash/components/browser_context_helper",
+    "//chromeos/ash/components/demo_mode:demo_mode",
     "//chromeos/ash/components/editor_menu/public/cpp",
     "//chromeos/ash/components/specialized_features:specialized_features",
     "//chromeos/components/magic_boost/public/cpp:cpp",
diff --git a/chrome/browser/ash/lobster/DEPS b/chrome/browser/ash/lobster/DEPS
index e4732a8..d13c40d3 100644
--- a/chrome/browser/ash/lobster/DEPS
+++ b/chrome/browser/ash/lobster/DEPS
@@ -10,6 +10,7 @@
   # Existing dependencies within //chrome. There is an active effort to
   # refactor //chrome/browser/ash to break these dependencies; see b/332804822.
   # Whenever possible, avoid adding new //chrome dependencies to this list.
+  "+chrome/browser/ash/login/demo_mode/demo_session.h",
   "+chrome/browser/ash/login/users/fake_chrome_user_manager.h",
   "+chrome/browser/ash/magic_boost",
   "+chrome/browser/browser_process.h",
diff --git a/chrome/browser/ash/lobster/lobster_service.cc b/chrome/browser/ash/lobster/lobster_service.cc
index f55b279..e09c62e0 100644
--- a/chrome/browser/ash/lobster/lobster_service.cc
+++ b/chrome/browser/ash/lobster/lobster_service.cc
@@ -28,6 +28,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chromeos/ash/components/browser_context_helper/annotated_account_id.h"
+#include "chromeos/ash/components/demo_mode/utils/demo_session_utils.h"
 #include "chromeos/ash/components/editor_menu/public/cpp/editor_consent_status.h"
 #include "chromeos/components/magic_boost/public/cpp/magic_boost_state.h"
 #include "chromeos/crosapi/mojom/magic_boost.mojom.h"
@@ -58,7 +59,8 @@
       resizer_(std::make_unique<LobsterCandidateResizer>(image_fetcher_.get())),
       system_state_provider_(std::make_unique<LobsterSystemStateProviderImpl>(
           profile->GetPrefs(),
-          IdentityManagerFactory::GetForProfile(profile))),
+          IdentityManagerFactory::GetForProfile(profile),
+          /*is_in_demo_mode=*/ash::demo_mode::IsDeviceInDemoMode())),
       announcer_(
           std::make_unique<LobsterLiveRegionAnnouncer>(kAnnouncementViewName)) {
   if (profile != nullptr) {
diff --git a/chrome/browser/ash/lobster/lobster_system_state_provider_impl.cc b/chrome/browser/ash/lobster/lobster_system_state_provider_impl.cc
index 7f2c278..f43a13a 100644
--- a/chrome/browser/ash/lobster/lobster_system_state_provider_impl.cc
+++ b/chrome/browser/ash/lobster/lobster_system_state_provider_impl.cc
@@ -20,7 +20,6 @@
 #include "chromeos/ash/components/specialized_features/feature_access_checker.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
-#include "lobster_system_state_provider_impl.h"
 #include "net/base/network_change_notifier.h"
 #include "ui/base/ime/ash/extension_ime_util.h"
 #include "ui/base/ime/ash/input_method_manager.h"
@@ -116,14 +115,16 @@
 
 LobsterSystemStateProviderImpl::LobsterSystemStateProviderImpl(
     PrefService* pref,
-    signin::IdentityManager* identity_manager)
+    signin::IdentityManager* identity_manager,
+    bool is_in_demo_mode)
     : pref_(pref),
       access_checker_(CreateFeatureAccessConfig(),
                       pref_,
                       identity_manager,
                       /*variations_service_callback=*/base::BindRepeating([]() {
                         return g_browser_process->variations_service();
-                      })) {}
+                      })),
+      is_in_demo_mode_(is_in_demo_mode) {}
 
 LobsterSystemStateProviderImpl::~LobsterSystemStateProviderImpl() = default;
 
@@ -159,10 +160,11 @@
     system_state.failed_checks.Put(ash::LobsterSystemCheck::kInvalidRegion);
   }
 
-  // Performs account capabilities check
-  if (access_checker_failure_set.Has(
-          specialized_features::FeatureAccessFailure::
-              kAccountCapabilitiesCheckFailed)) {
+  // TODO: b:406915099 - Migrate demo mode check into the shared feature checker module.
+  // Performs account capabilities check in non-demo mode only
+  if (!is_in_demo_mode_ && access_checker_failure_set.Has(
+                               specialized_features::FeatureAccessFailure::
+                                   kAccountCapabilitiesCheckFailed)) {
     system_state.status = ash::LobsterStatus::kBlocked;
     system_state.failed_checks.Put(
         ash::LobsterSystemCheck::kInvalidAccountCapabilities);
diff --git a/chrome/browser/ash/lobster/lobster_system_state_provider_impl.h b/chrome/browser/ash/lobster/lobster_system_state_provider_impl.h
index 4a676358..92fbfec 100644
--- a/chrome/browser/ash/lobster/lobster_system_state_provider_impl.h
+++ b/chrome/browser/ash/lobster/lobster_system_state_provider_impl.h
@@ -28,7 +28,8 @@
  public:
   explicit LobsterSystemStateProviderImpl(
       PrefService* pref,
-      signin::IdentityManager* identity_manager);
+      signin::IdentityManager* identity_manager,
+      bool is_in_demo_mode);
 
   ~LobsterSystemStateProviderImpl() override;
 
@@ -42,6 +43,7 @@
   raw_ptr<PrefService> pref_;
   specialized_features::FeatureAccessChecker access_checker_;
   bool is_in_tablet_mode_ = false;
+  bool is_in_demo_mode_ = false;
   display::ScopedDisplayObserver display_observer_{this};
 };
 
diff --git a/chrome/browser/ash/lobster/lobster_system_state_provider_impl_unittest.cc b/chrome/browser/ash/lobster/lobster_system_state_provider_impl_unittest.cc
index 1838b1e..17c3b2e0 100644
--- a/chrome/browser/ash/lobster/lobster_system_state_provider_impl_unittest.cc
+++ b/chrome/browser/ash/lobster/lobster_system_state_provider_impl_unittest.cc
@@ -92,7 +92,8 @@
   LobsterSystemStateProviderImplBaseTest()
       : test_screen_(/*create_display=*/true, /*register_screen=*/true),
         system_state_provider_(&pref_,
-                               identity_test_environment_.identity_manager()),
+                               identity_test_environment_.identity_manager(),
+                               /*is_in_demo_mode=*/false),
         metrics_enabled_state_provider_(/*consent=*/false, /*enabled=*/false) {
     // Sets up InputMethodManager
     InputMethodManagerFake::Initialize(new InputMethodManagerFake);
diff --git a/chrome/browser/ash/login/demo_mode/demo_session_browsertest.cc b/chrome/browser/ash/login/demo_mode/demo_session_browsertest.cc
index 4674a866..6624903 100644
--- a/chrome/browser/ash/login/demo_mode/demo_session_browsertest.cc
+++ b/chrome/browser/ash/login/demo_mode/demo_session_browsertest.cc
@@ -730,7 +730,9 @@
   std::unique_ptr<drive::FakeDriveFsHelper> fake_drivefs_helper_;
 };
 
-IN_PROC_BROWSER_TEST_F(DemoSessionLoginIdleHandlerTest, CleanUpLocalFiles) {
+// TODO(crbugs.com/406823191): Investigate the flaky and and re-enabled it.
+IN_PROC_BROWSER_TEST_F(DemoSessionLoginIdleHandlerTest,
+                       DISABLED_CleanUpLocalFiles) {
   demo_mode::SetForceEnableDemoAccountSignIn(true);
 
   // Mock login with demo account, which is a regular user.
diff --git a/chrome/browser/ash/login/users/user_manager_unittest.cc b/chrome/browser/ash/login/users/user_manager_unittest.cc
index 557f4be0..abace54 100644
--- a/chrome/browser/ash/login/users/user_manager_unittest.cc
+++ b/chrome/browser/ash/login/users/user_manager_unittest.cc
@@ -488,7 +488,7 @@
       kKioskAccountId,
       user_manager::TestHelper::GetFakeUsernameHash(kKioskAccountId));
   ResetUserManager();
-  ASSERT_TRUE(user_manager::TestHelper(*user_manager::UserManager::Get())
+  ASSERT_TRUE(user_manager::TestHelper(user_manager::UserManager::Get())
                   .AddRegularUser(kAccountId0));
   user_manager::UserManager::Get()->UserLoggedIn(
       kAccountId0, user_manager::TestHelper::GetFakeUsernameHash(kAccountId0));
@@ -512,8 +512,8 @@
 
 TEST_F(UserManagerTest, RemoveUser) {
   // Create owner account and login in.
-  ASSERT_TRUE(
-      user_manager::TestHelper(*user_manager_).AddRegularUser(kOwnerAccountId));
+  ASSERT_TRUE(user_manager::TestHelper(user_manager_.get())
+                  .AddRegularUser(kOwnerAccountId));
   user_manager_->UserLoggedIn(
       kOwnerAccountId,
       user_manager::TestHelper::GetFakeUsernameHash(kOwnerAccountId));
@@ -522,8 +522,8 @@
   ResetUserManager();
 
   // Create non-owner account  and login in.
-  ASSERT_TRUE(
-      user_manager::TestHelper(*user_manager_).AddRegularUser(kAccountId0));
+  ASSERT_TRUE(user_manager::TestHelper(user_manager_.get())
+                  .AddRegularUser(kAccountId0));
   user_manager_->UserLoggedIn(
       kAccountId0, user_manager::TestHelper::GetFakeUsernameHash(kAccountId0));
   // Log-in owner account.
@@ -578,18 +578,18 @@
 }
 
 TEST_F(UserManagerTest, RemoveRegularUsersExceptOwnerFromList) {
-  ASSERT_TRUE(user_manager::TestHelper(*user_manager::UserManager::Get())
+  ASSERT_TRUE(user_manager::TestHelper(user_manager::UserManager::Get())
                   .AddRegularUser(kOwnerAccountId));
   user_manager::UserManager::Get()->UserLoggedIn(
       kOwnerAccountId,
       user_manager::TestHelper::GetFakeUsernameHash(kOwnerAccountId));
   ResetUserManager();
-  ASSERT_TRUE(user_manager::TestHelper(*user_manager::UserManager::Get())
+  ASSERT_TRUE(user_manager::TestHelper(user_manager::UserManager::Get())
                   .AddRegularUser(kAccountId0));
   user_manager::UserManager::Get()->UserLoggedIn(
       kAccountId0, user_manager::TestHelper::GetFakeUsernameHash(kAccountId0));
   ResetUserManager();
-  ASSERT_TRUE(user_manager::TestHelper(*user_manager::UserManager::Get())
+  ASSERT_TRUE(user_manager::TestHelper(user_manager::UserManager::Get())
                   .AddRegularUser(kAccountId1));
   user_manager::UserManager::Get()->UserLoggedIn(
       kAccountId1, user_manager::TestHelper::GetFakeUsernameHash(kAccountId1));
@@ -627,13 +627,13 @@
       /* owner= */ kOwnerAccountId.GetUserEmail());
   RetrieveTrustedDevicePolicies();
 
-  ASSERT_TRUE(user_manager::TestHelper(*user_manager::UserManager::Get())
+  ASSERT_TRUE(user_manager::TestHelper(user_manager::UserManager::Get())
                   .AddRegularUser(kOwnerAccountId));
   user_manager::UserManager::Get()->UserLoggedIn(
       kOwnerAccountId,
       user_manager::TestHelper::GetFakeUsernameHash(kOwnerAccountId));
   ResetUserManager();
-  ASSERT_TRUE(user_manager::TestHelper(*user_manager::UserManager::Get())
+  ASSERT_TRUE(user_manager::TestHelper(user_manager::UserManager::Get())
                   .AddRegularUser(kAccountId0));
   user_manager::UserManager::Get()->UserLoggedIn(
       kAccountId0, user_manager::TestHelper::GetFakeUsernameHash(kAccountId0));
@@ -647,7 +647,7 @@
 
 TEST_F(UserManagerTest, ScreenLockAvailability) {
   // Log in the user and create the profile.
-  ASSERT_TRUE(user_manager::TestHelper(*user_manager::UserManager::Get())
+  ASSERT_TRUE(user_manager::TestHelper(user_manager::UserManager::Get())
                   .AddRegularUser(kOwnerAccountId));
   user_manager::UserManager::Get()->UserLoggedIn(
       kOwnerAccountId,
@@ -676,7 +676,7 @@
 }
 
 TEST_F(UserManagerTest, ProfileRequiresPolicyUnknown) {
-  ASSERT_TRUE(user_manager::TestHelper(*user_manager::UserManager::Get())
+  ASSERT_TRUE(user_manager::TestHelper(user_manager::UserManager::Get())
                   .AddRegularUser(kOwnerAccountId));
   user_manager::UserManager::Get()->UserLoggedIn(
       kOwnerAccountId,
@@ -747,8 +747,8 @@
 // callback.
 TEST_F(UserManagerTest, ProfilePrefs) {
   // Simulates login.
-  ASSERT_TRUE(
-      user_manager::TestHelper(*user_manager_).AddRegularUser(kAccountId0));
+  ASSERT_TRUE(user_manager::TestHelper(user_manager_.get())
+                  .AddRegularUser(kAccountId0));
   user_manager_->UserLoggedIn(
       kAccountId0, user_manager::TestHelper::GetFakeUsernameHash(kAccountId0));
 
diff --git a/chrome/browser/chrome_browser_interface_binders_webui.cc b/chrome/browser/chrome_browser_interface_binders_webui.cc
index 6cadf1b6..805b422f 100644
--- a/chrome/browser/chrome_browser_interface_binders_webui.cc
+++ b/chrome/browser/chrome_browser_interface_binders_webui.cc
@@ -59,7 +59,10 @@
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
 #include "chrome/browser/ui/webui/app_settings/web_app_settings_ui.h"
 #include "chrome/browser/ui/webui/on_device_translation_internals/on_device_translation_internals_ui.h"
+#include "chrome/browser/ui/webui/signin/history_sync_optin/history_sync_optin.mojom.h"
+#include "chrome/browser/ui/webui/signin/history_sync_optin/history_sync_optin_ui.h"
 #include "chrome/browser/ui/webui/whats_new/whats_new_ui.h"
+#include "components/signin/public/base/signin_switches.h"
 #endif
 
 #if BUILDFLAG(IS_ANDROID)
@@ -460,6 +463,11 @@
   RegisterWebUIControllerInterfaceBinder<
       on_device_translation_internals::mojom::PageHandlerFactory,
       OnDeviceTranslationInternalsUI>(map);
+
+  if (base::FeatureList::IsEnabled(switches::kEnableHistorySyncOptin)) {
+    RegisterWebUIControllerInterfaceBinder<
+        history_sync_optin::mojom::PageHandlerFactory, HistorySyncOptinUI>(map);
+  }
 #endif
 
 #if !BUILDFLAG(IS_ANDROID)
diff --git a/chrome/browser/chromeos/extensions/echo_private/BUILD.gn b/chrome/browser/chromeos/extensions/echo_private/BUILD.gn
index 8a5cae0..fadaa93 100644
--- a/chrome/browser/chromeos/extensions/echo_private/BUILD.gn
+++ b/chrome/browser/chromeos/extensions/echo_private/BUILD.gn
@@ -26,7 +26,7 @@
     "//chrome/common/extensions/api:api",
     "//chromeos/ash/components/report:utils",
     "//chromeos/ash/components/settings",
-    "//chromeos/crosapi/mojom",
+    "//chromeos/ash/components/system",
     "//components/prefs",
     "//content/public/browser",
     "//extensions/browser",
diff --git a/chrome/browser/chromeos/extensions/echo_private/DEPS b/chrome/browser/chromeos/extensions/echo_private/DEPS
index 33fd189c..0c78f1c 100644
--- a/chrome/browser/chromeos/extensions/echo_private/DEPS
+++ b/chrome/browser/chromeos/extensions/echo_private/DEPS
@@ -11,7 +11,6 @@
   # refactor chromeos codes in //chrome to break these dependencies; see
   # b/332804822. Whenever possible, avoid adding new //chrome dependencies to
   # this list.
-  "+chrome/browser/ash/crosapi",
   "+chrome/browser/ash/notifications",
   "+chrome/browser/ash/settings",
   "+chrome/browser/browser_process.h",
diff --git a/chrome/browser/chromeos/extensions/echo_private/echo_private_api.cc b/chrome/browser/chromeos/extensions/echo_private/echo_private_api.cc
index 4f1c58a..8fe0eda0 100644
--- a/chrome/browser/chromeos/extensions/echo_private/echo_private_api.cc
+++ b/chrome/browser/chromeos/extensions/echo_private/echo_private_api.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/chromeos/extensions/echo_private/echo_private_api.h"
 
 #include <string>
+#include <string_view>
 #include <utility>
 
 #include "base/files/file_util.h"
@@ -14,9 +15,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "base/values.h"
-#include "chrome/browser/ash/crosapi/crosapi_ash.h"
-#include "chrome/browser/ash/crosapi/crosapi_manager.h"
-#include "chrome/browser/ash/crosapi/echo_private_ash.h"
 #include "chrome/browser/ash/notifications/echo_dialog_view.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/extensions/echo_private/echo_private_api_util.h"
@@ -33,6 +31,7 @@
 #include "chromeos/ash/components/settings/cros_settings.h"
 #include "chromeos/ash/components/settings/cros_settings_names.h"
 #include "chromeos/ash/components/settings/cros_settings_provider.h"
+#include "chromeos/ash/components/system/statistics_provider.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
 #include "content/public/browser/web_contents.h"
@@ -43,6 +42,29 @@
 #include "third_party/icu/source/i18n/unicode/timezone.h"
 #include "ui/aura/window.h"
 
+namespace {
+std::string GetRegistrationCode(std::string_view type) {
+  // Possible ECHO code type and corresponding key name in StatisticsProvider.
+  const std::string kCouponType = "COUPON_CODE";
+  const std::string kGroupType = "GROUP_CODE";
+
+  ash::system::StatisticsProvider* provider =
+      ash::system::StatisticsProvider::GetInstance();
+  std::string result;
+  if (type == kCouponType) {
+    const std::optional<std::string_view> offers_code =
+        provider->GetMachineStatistic(ash::system::kOffersCouponCodeKey);
+    result = std::string(offers_code.value());
+  } else if (type == kGroupType) {
+    const std::optional<std::string_view> offers_code =
+        provider->GetMachineStatistic(ash::system::kOffersGroupCodeKey);
+    result = std::string(offers_code.value());
+  }
+
+  return result;
+}
+}  // namespace
+
 namespace echo_api = extensions::api::echo_private;
 
 EchoPrivateGetRegistrationCodeFunction::
@@ -57,33 +79,8 @@
       echo_api::GetRegistrationCode::Params::Create(args());
   EXTENSION_FUNCTION_VALIDATE(params);
 
-  // Possible ECHO code type and corresponding key name in StatisticsProvider.
-  const std::string kCouponType = "COUPON_CODE";
-  const std::string kGroupType = "GROUP_CODE";
-  std::optional<crosapi::mojom::RegistrationCodeType> type;
-  if (params->type == kCouponType) {
-    type = crosapi::mojom::RegistrationCodeType::kCoupon;
-  } else if (params->type == kGroupType) {
-    type = crosapi::mojom::RegistrationCodeType::kGroup;
-  }
-
-  if (!type) {
-    return RespondNow(ArgumentList(
-        echo_api::GetRegistrationCode::Results::Create(std::string())));
-  }
-
-  auto callback = base::BindOnce(
-      &EchoPrivateGetRegistrationCodeFunction::RespondWithResult, this);
-  crosapi::CrosapiManager::Get()
-      ->crosapi_ash()
-      ->echo_private_ash()
-      ->GetRegistrationCode(type.value(), std::move(callback));
-  return RespondLater();
-}
-
-void EchoPrivateGetRegistrationCodeFunction::RespondWithResult(
-    const std::string& result) {
-  Respond(WithArguments(result));
+  return RespondNow(ArgumentList(echo_api::GetRegistrationCode::Results::Create(
+      GetRegistrationCode(params->type))));
 }
 
 EchoPrivateSetOfferInfoFunction::EchoPrivateSetOfferInfoFunction() = default;
diff --git a/chrome/browser/chromeos/extensions/echo_private/echo_private_api.h b/chrome/browser/chromeos/extensions/echo_private/echo_private_api.h
index 3923f8b..2d9693e 100644
--- a/chrome/browser/chromeos/extensions/echo_private/echo_private_api.h
+++ b/chrome/browser/chromeos/extensions/echo_private/echo_private_api.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_CHROMEOS_EXTENSIONS_ECHO_PRIVATE_ECHO_PRIVATE_API_H_
 #define CHROME_BROWSER_CHROMEOS_EXTENSIONS_ECHO_PRIVATE_ECHO_PRIVATE_API_H_
 
-#include <string>
+#include <string_view>
 
 #include "base/types/expected.h"
 #include "chrome/browser/ash/notifications/echo_dialog_listener.h"
@@ -24,7 +24,6 @@
   ResponseAction Run() override;
 
  private:
-  void RespondWithResult(const std::string& result);
   DECLARE_EXTENSION_FUNCTION("echoPrivate.getRegistrationCode",
                              ECHOPRIVATE_GETREGISTRATIONCODE)
 };
diff --git a/chrome/browser/digital_credentials/digital_identity_provider_android.cc b/chrome/browser/digital_credentials/digital_identity_provider_android.cc
index 5cfc1fe..6c597c5 100644
--- a/chrome/browser/digital_credentials/digital_identity_provider_android.cc
+++ b/chrome/browser/digital_credentials/digital_identity_provider_android.cc
@@ -8,6 +8,7 @@
 
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
+#include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
 #include "base/values.h"
 #include "chrome/browser/digital_credentials/digital_identity_low_risk_origins.h"
@@ -124,6 +125,7 @@
   std::move(callback_).Run(
       (status_for_metrics == RequestStatusForMetrics::kSuccess)
           ? base::expected<DigitalCredential, RequestStatusForMetrics>(
-                DigitalCredential(std::move(protocol), std::move(result)))
+                DigitalCredential(std::move(protocol),
+                                  base::JSONReader::Read(result)))
           : base::unexpected(status_for_metrics));
 }
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index c823fcb..c57b3be 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -7738,7 +7738,7 @@
     "expiry_milestone": 145
   },
   {
-    "name": "reader-mode-distiller-heuristic-delay-string",
+    "name": "reader-mode-distiller-enabled",
     "owners": ["fernandex@google.com", "qpubert@google.com", "bling-flags@google.com"],
     "expiry_milestone": 145
   },
@@ -7748,11 +7748,6 @@
     "expiry_milestone": 145
   },
   {
-    "name": "reader-mode-distiller-heuristic-sampling",
-    "owners": ["fernandex@google.com", "qpubert@google.com", "bling-flags@google.com"],
-    "expiry_milestone": 145
-  },
-  {
     "name": "reader-mode-heuristics",
     "owners": [ "mdjones@chromium.org", "wychen@chromium.org" ],
     // This flag is a utility for testing Reader Mode heuristics or force
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index e94926e..422d932 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1766,13 +1766,13 @@
     "Proactively reuses same-site renderer processes to host multiple main "
     "frames, up to a certain threshold.";
 
-#if BUILDFLAG(IS_CHROMEOS) && BUILDFLAG(ENABLE_EXTENSIONS)
+#if BUILDFLAG(IS_CHROMEOS)
 const char kEnablePrintingMarginsAndScale[] =
-    "Enable printing margins and scale support in chrome.Printing API.";
+    "Enable printing margins and scale support in chrome.printing API.";
 const char kEnablePrintingMarginsAndScaleDescription[] =
-    "Allows extensions to specify margins and scale in chrome.Printing API "
+    "Allows extensions to specify margins and scale in chrome.printing API "
     "based on supported values provided by the printer.";
-#endif  // BUILDFLAG(IS_CHROMEOS) && BUILDFLAG(ENABLE_EXTENSIONS)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 const char kBoundaryEventDispatchTracksNodeRemovalName[] =
     "Boundary Event Dispatch Tracks Node Removal";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index f7c3705..f1b8cc7b 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -994,10 +994,10 @@
 extern const char kEnableProcessPerSiteUpToMainFrameThresholdName[];
 extern const char kEnableProcessPerSiteUpToMainFrameThresholdDescription[];
 
-#if BUILDFLAG(IS_CHROMEOS) && BUILDFLAG(ENABLE_EXTENSIONS)
+#if BUILDFLAG(IS_CHROMEOS)
 extern const char kEnablePrintingMarginsAndScale[];
 extern const char kEnablePrintingMarginsAndScaleDescription[];
-#endif  // BUILDFLAG(IS_CHROMEOS) && BUILDFLAG(ENABLE_EXTENSIONS)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 extern const char kEnableSearchCustomizableShortcutsInLauncherName[];
 extern const char kEnableSearchCustomizableShortcutsInLauncherDescription[];
diff --git a/chrome/browser/password_manager/android/login_db_deprecation_runner_factory.cc b/chrome/browser/password_manager/android/login_db_deprecation_runner_factory.cc
index 6f65c5a..7f5a3b5 100644
--- a/chrome/browser/password_manager/android/login_db_deprecation_runner_factory.cc
+++ b/chrome/browser/password_manager/android/login_db_deprecation_runner_factory.cc
@@ -51,11 +51,6 @@
 
   if (!base::FeatureList::IsEnabled(
           password_manager::features::kLoginDbDeprecationAndroid)) {
-    // Reset the pref if the flag is off, to ensure that if a client switches
-    // from the "Enabled" to the "Disabled" group, they redo the export once
-    // the feature is eventually enabled for them.
-    prefs->SetBoolean(password_manager::prefs::kUpmUnmigratedPasswordsExported,
-                      false);
     return nullptr;
   }
 
@@ -66,15 +61,6 @@
     return nullptr;
   }
 
-  // If there are no passwords saved, there is nothing to export prior to
-  // deprecation, so mark the export as done without instantiating the exporter.
-  if (prefs->GetBoolean(
-          password_manager::prefs::kEmptyProfileStoreLoginDatabase)) {
-    prefs->SetBoolean(password_manager::prefs::kUpmUnmigratedPasswordsExported,
-                      true);
-    return nullptr;
-  }
-
   return std::make_unique<password_manager::LoginDbDeprecationRunner>(
       std::make_unique<password_manager::LoginDbDeprecationPasswordExporter>(
           profile->GetPrefs(), profile->GetPath()));
diff --git a/chrome/browser/password_manager/android/login_db_deprecation_runner_factory_unittest.cc b/chrome/browser/password_manager/android/login_db_deprecation_runner_factory_unittest.cc
index 5112be2..3b7218f 100644
--- a/chrome/browser/password_manager/android/login_db_deprecation_runner_factory_unittest.cc
+++ b/chrome/browser/password_manager/android/login_db_deprecation_runner_factory_unittest.cc
@@ -35,24 +35,6 @@
       LoginDbDeprecationRunnerFactory::GetForProfile(&testing_profile_));
 }
 
-TEST_F(LoginDbDeprecationRunnerFactoryTest, NullServiceIfEmptyDb) {
-  scoped_feature_list_.InitAndEnableFeature(
-      password_manager::features::kLoginDbDeprecationAndroid);
-  PrefService* prefs = testing_profile_.GetPrefs();
-  prefs->SetInteger(
-      password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(
-          password_manager::prefs::UseUpmLocalAndSeparateStoresState::kOff));
-  prefs->SetBoolean(password_manager::prefs::kEmptyProfileStoreLoginDatabase,
-                    true);
-  prefs->SetBoolean(password_manager::prefs::kUpmUnmigratedPasswordsExported,
-                    false);
-  EXPECT_FALSE(
-      LoginDbDeprecationRunnerFactory::GetForProfile(&testing_profile_));
-  EXPECT_TRUE(prefs->GetBoolean(
-      password_manager::prefs::kUpmUnmigratedPasswordsExported));
-}
-
 TEST_F(LoginDbDeprecationRunnerFactoryTest, NullServiceIfFlagOff) {
   scoped_feature_list_.InitAndDisableFeature(
       password_manager::features::kLoginDbDeprecationAndroid);
@@ -61,14 +43,10 @@
       password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores,
       static_cast<int>(
           password_manager::prefs::UseUpmLocalAndSeparateStoresState::kOff));
-  prefs->SetBoolean(password_manager::prefs::kEmptyProfileStoreLoginDatabase,
-                    false);
   prefs->SetBoolean(password_manager::prefs::kUpmUnmigratedPasswordsExported,
                     true);
   EXPECT_FALSE(
       LoginDbDeprecationRunnerFactory::GetForProfile(&testing_profile_));
-  EXPECT_FALSE(prefs->GetBoolean(
-      password_manager::prefs::kUpmUnmigratedPasswordsExported));
 }
 
 TEST_F(LoginDbDeprecationRunnerFactoryTest, NullIfAlreadyExported) {
@@ -94,7 +72,7 @@
       password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores,
       static_cast<int>(
           password_manager::prefs::UseUpmLocalAndSeparateStoresState::kOff));
-  prefs->SetBoolean(password_manager::prefs::kEmptyProfileStoreLoginDatabase,
+  prefs->SetBoolean(password_manager::prefs::kUpmUnmigratedPasswordsExported,
                     false);
   EXPECT_TRUE(
       LoginDbDeprecationRunnerFactory::GetForProfile(&testing_profile_));
@@ -109,7 +87,7 @@
       static_cast<int>(
           password_manager::prefs::UseUpmLocalAndSeparateStoresState::
               kOffAndMigrationPending));
-  prefs->SetBoolean(password_manager::prefs::kEmptyProfileStoreLoginDatabase,
+  prefs->SetBoolean(password_manager::prefs::kUpmUnmigratedPasswordsExported,
                     false);
   EXPECT_TRUE(
       LoginDbDeprecationRunnerFactory::GetForProfile(&testing_profile_));
diff --git a/chrome/browser/password_manager/android/password_manager_android_util.cc b/chrome/browser/password_manager/android/password_manager_android_util.cc
index a037226..4511fb5 100644
--- a/chrome/browser/password_manager/android/password_manager_android_util.cc
+++ b/chrome/browser/password_manager/android/password_manager_android_util.cc
@@ -390,6 +390,36 @@
                                      : UseUpmLocalAndSeparateStoresState::kOff);
 }
 
+void InitializeUpmUnmigratedPasswordsExportPref(
+    PrefService* prefs,
+    const base::FilePath& login_db_directory) {
+  // The umigrated passwords export pref should only be set for users who aren't
+  // already part of UPM.
+  if (password_manager::UsesSplitStoresAndUPMForLocal(prefs)) {
+    return;
+  }
+
+  if (!base::FeatureList::IsEnabled(
+          password_manager::features::kLoginDbDeprecationAndroid)) {
+    // Reset the pref if the flag is off, to ensure that if a client switches
+    // from the "Enabled" to the "Disabled" group, they redo the export once
+    // the feature is eventually enabled for them.
+    prefs->SetBoolean(password_manager::prefs::kUpmUnmigratedPasswordsExported,
+                      false);
+    return;
+  }
+
+  // If there are no passwords saved, there is nothing to export prior to
+  // deprecation, so mark the export as done already.
+  if (prefs->GetBoolean(
+          password_manager::prefs::kEmptyProfileStoreLoginDatabase) ||
+      !base::PathExists(login_db_directory.Append(
+          password_manager::kLoginDataForProfileFileName))) {
+    prefs->SetBoolean(password_manager::prefs::kUpmUnmigratedPasswordsExported,
+                      true);
+  }
+}
+
 }  // namespace
 
 bool IsPasswordManagerAvailable(
@@ -480,6 +510,11 @@
     PrefService* pref_service,
     const base::FilePath& login_db_directory,
     std::unique_ptr<PasswordManagerUtilBridgeInterface> util_bridge) {
+  // For fresh installs in particular, it's important to do this before
+  // the backend creation, so that the Android backends are directly wired
+  // without requiring another restart.
+  password_manager_android_util::InitializeUpmUnmigratedPasswordsExportPref(
+      pref_service, login_db_directory);
   if (base::FeatureList::IsEnabled(
           password_manager::features::kLoginDbDeprecationAndroid)) {
     // If the login DB is being deprecated, only record metrics and do not
diff --git a/chrome/browser/password_manager/android/password_manager_android_util_unittest.cc b/chrome/browser/password_manager/android/password_manager_android_util_unittest.cc
index dd76d7d8..863fc256c 100644
--- a/chrome/browser/password_manager/android/password_manager_android_util_unittest.cc
+++ b/chrome/browser/password_manager/android/password_manager_android_util_unittest.cc
@@ -533,6 +533,57 @@
       "PasswordManager.LocalUpmActivationStatus", kOn, 1);
 }
 
+TEST_F(PasswordManagerAndroidUtilTest,
+       InitUnmigratedExportUnchangedIfMigrated) {
+  base::test::ScopedFeatureList feature_list{
+      password_manager::features::kLoginDbDeprecationAndroid};
+  pref_service()->SetInteger(
+      password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores,
+      static_cast<int>(
+          password_manager::prefs::UseUpmLocalAndSeparateStoresState::kOn));
+  SetUsesSplitStoresAndUPMForLocal(pref_service(), login_db_directory(),
+                                   GetMockBridgeWithBackendPresent());
+  EXPECT_TRUE(pref_service()
+                  ->FindPreference(
+                      password_manager::prefs::kUpmUnmigratedPasswordsExported)
+                  ->IsDefaultValue());
+}
+
+TEST_F(PasswordManagerAndroidUtilTest, InitUnmigratedExportPrefTrueEmptyDb) {
+  base::test::ScopedFeatureList feature_list{
+      password_manager::features::kLoginDbDeprecationAndroid};
+  pref_service()->SetInteger(
+      password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores,
+      static_cast<int>(
+          password_manager::prefs::UseUpmLocalAndSeparateStoresState::kOff));
+  pref_service()->SetBoolean(
+      password_manager::prefs::kEmptyProfileStoreLoginDatabase, true);
+  pref_service()->SetBoolean(
+      password_manager::prefs::kUpmUnmigratedPasswordsExported, false);
+  SetUsesSplitStoresAndUPMForLocal(pref_service(), login_db_directory(),
+                                   GetMockBridgeWithBackendPresent());
+  EXPECT_TRUE(pref_service()->GetBoolean(
+      password_manager::prefs::kUpmUnmigratedPasswordsExported));
+}
+
+TEST_F(PasswordManagerAndroidUtilTest, InitUnmigratedExportPrefFalseFlagOff) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndDisableFeature(
+      password_manager::features::kLoginDbDeprecationAndroid);
+  pref_service()->SetInteger(
+      password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores,
+      static_cast<int>(
+          password_manager::prefs::UseUpmLocalAndSeparateStoresState::kOff));
+  pref_service()->SetBoolean(
+      password_manager::prefs::kEmptyProfileStoreLoginDatabase, false);
+  pref_service()->SetBoolean(
+      password_manager::prefs::kUpmUnmigratedPasswordsExported, true);
+  SetUsesSplitStoresAndUPMForLocal(pref_service(), login_db_directory(),
+                                   GetMockBridgeWithBackendPresent());
+  EXPECT_FALSE(pref_service()->GetBoolean(
+      password_manager::prefs::kUpmUnmigratedPasswordsExported));
+}
+
 // Unit tests for the activation algorithm. No longer relevant after the login
 // db deprecation.
 class PasswordManagerUpmActivationTest : public PasswordManagerAndroidUtilTest {
diff --git a/chrome/browser/policy/test/autofill_ai_policy_browsertest.cc b/chrome/browser/policy/test/autofill_ai_policy_browsertest.cc
index 6234fee..cceb5d24 100644
--- a/chrome/browser/policy/test/autofill_ai_policy_browsertest.cc
+++ b/chrome/browser/policy/test/autofill_ai_policy_browsertest.cc
@@ -130,6 +130,7 @@
   ASSERT_TRUE(ui_test_utils::NavigateToURL(
       browser(),
       GURL(base::StrCat({"chrome://settings/", chrome::kAutofillAiSubPage}))));
+  EXPECT_TRUE(content::WaitForLoadStop(GetWebContents()));
   EXPECT_EQ(
       GetWebContents()->GetURL().path(),
       base::StrCat({"/", disabled_by_policy() ? chrome::kAutofillSubPage
diff --git a/chrome/browser/preloading/prefetch/zero_suggest_prefetch/zero_suggest_prefetch_tab_helper_browsertest.cc b/chrome/browser/preloading/prefetch/zero_suggest_prefetch/zero_suggest_prefetch_tab_helper_browsertest.cc
index 6600f435..77d3703 100644
--- a/chrome/browser/preloading/prefetch/zero_suggest_prefetch/zero_suggest_prefetch_tab_helper_browsertest.cc
+++ b/chrome/browser/preloading/prefetch/zero_suggest_prefetch/zero_suggest_prefetch_tab_helper_browsertest.cc
@@ -22,6 +22,7 @@
 #include "components/omnibox/browser/mock_autocomplete_provider_client.h"
 #include "components/omnibox/browser/omnibox_controller.h"
 #include "components/omnibox/browser/omnibox_view.h"
+#include "components/omnibox/common/omnibox_feature_configs.h"
 #include "components/omnibox/common/omnibox_features.h"
 #include "components/search_engines/template_url_service.h"
 #include "components/search_engines/template_url_service_client.h"
@@ -59,6 +60,8 @@
     auto client_ = std::make_unique<MockAutocompleteProviderClient>();
     client_->set_template_url_service(template_url_service);
 
+    most_visited_prefetch_scoped_config_.Get().enabled = false;
+
     auto controller =
         std::make_unique<testing::NiceMock<MockAutocompleteController>>(
             std::move(client_), 0);
@@ -72,6 +75,9 @@
   }
 
   base::test::ScopedFeatureList feature_list_;
+  omnibox_feature_configs::ScopedConfigForTesting<
+      omnibox_feature_configs::OmniboxUrlSuggestionsOnFocus>
+      most_visited_prefetch_scoped_config_;
   raw_ptr<testing::NiceMock<MockAutocompleteController>,
           AcrossTasksDanglingUntriaged>
       controller_;
diff --git a/chrome/browser/profiles/profile_manager_unittest.cc b/chrome/browser/profiles/profile_manager_unittest.cc
index 6653faf..04695c08 100644
--- a/chrome/browser/profiles/profile_manager_unittest.cc
+++ b/chrome/browser/profiles/profile_manager_unittest.cc
@@ -302,7 +302,7 @@
 
     // Add user for testing.
     {
-      user_manager::TestHelper test_helper(*user_manager);
+      user_manager::TestHelper test_helper(user_manager);
       if (account_id == user_manager::GuestAccountId()) {
         ASSERT_TRUE(test_helper.AddGuestUser());
       } else {
@@ -337,7 +337,7 @@
         profile_helper->GetProfilePathByUserIdHash(user_id_hash);
 
     {
-      user_manager::TestHelper test_helper(*user_manager);
+      user_manager::TestHelper test_helper(user_manager);
       if (user_is_child) {
         CHECK(test_helper.AddChildUser(account_id));
       } else {
@@ -473,7 +473,7 @@
       user_manager::TestHelper::GetFakeUsernameHash(account_id);
   auto* user_manager = user_manager::UserManager::Get();
   ASSERT_TRUE(
-      user_manager::TestHelper(*user_manager).AddRegularUser(account_id));
+      user_manager::TestHelper(user_manager).AddRegularUser(account_id));
   user_manager->UserLoggedIn(account_id, user_id_hash);
 
   // Sign-in profile should be returned at this stage. Otherwise, login code
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn
index bcd463e..dc603ec1 100644
--- a/chrome/browser/resources/BUILD.gn
+++ b/chrome/browser/resources/BUILD.gn
@@ -108,6 +108,7 @@
       "app_settings:resources",
       "browser_switch:resources",
       "on_device_translation_internals:resources",
+      "signin/history_sync_optin:resources",
       "tts_engine:resources",
     ]
   }
diff --git a/chrome/browser/resources/settings/autofill_page/autofill_ai_add_or_edit_dialog.html b/chrome/browser/resources/settings/autofill_page/autofill_ai_add_or_edit_dialog.html
index eb5816a..42134f6 100644
--- a/chrome/browser/resources/settings/autofill_page/autofill_ai_add_or_edit_dialog.html
+++ b/chrome/browser/resources/settings/autofill_page/autofill_ai_add_or_edit_dialog.html
@@ -89,7 +89,9 @@
               aria-label="[[i18n('autofillAiAccessibilityLabelMonthDropdown',
                   attributeInstanceItem.type.typeNameAsString)]]"
               on-change="onMonthSelectChange_">
-            <option value="">$i18n{autofillDropdownNoOptionSelected}</option>
+            <option value="">
+              $i18n{autofillAiMonthDropdownNoOptionSelected}
+            </option>
             <template is="dom-repeat" items="[[months_]]" as="month">
               <option value="[[month]]"
                   selected="[[isMonthSelected_(attributeInstanceItem, month)]]">
@@ -102,7 +104,9 @@
               aria-label="[[i18n('autofillAiAccessibilityLabelDayDropdown',
                   attributeInstanceItem.type.typeNameAsString)]]"
               on-change="onDaySelectChange_">
-            <option value="">$i18n{autofillDropdownNoOptionSelected}</option>
+            <option value="">
+              $i18n{autofillAiDayDropdownNoOptionSelected}
+            </option>
             <template is="dom-repeat" items="[[days_]]" as="day">
               <option value="[[day]]"
                   selected="[[isDaySelected_(attributeInstanceItem, day)]]">
@@ -117,7 +121,9 @@
               on-change="onYearSelectChange_">
             <!-- TODO(crbug.com/393318914): Add another option for the existing
                 year, if the existing year is out of bounds. -->
-            <option value="">$i18n{autofillDropdownNoOptionSelected}</option>
+            <option value="">
+              $i18n{autofillAiYearDropdownNoOptionSelected}
+            </option>
             <template is="dom-repeat" items="[[years_]]" as="year">
               <option value="[[year]]"
                   selected="[[isYearSelected_(attributeInstanceItem, year)]]">
diff --git a/chrome/browser/resources/signin/history_sync_optin/BUILD.gn b/chrome/browser/resources/signin/history_sync_optin/BUILD.gn
new file mode 100644
index 0000000..7560c19
--- /dev/null
+++ b/chrome/browser/resources/signin/history_sync_optin/BUILD.gn
@@ -0,0 +1,29 @@
+# Copyright 2025 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//ui/webui/resources/tools/build_webui.gni")
+
+assert(is_win || is_mac || is_linux)
+
+build_webui("build") {
+  grd_prefix = "signin_history_sync_optin"
+
+  static_files = [ "history_sync_optin.html" ]
+
+  non_web_component_files = [
+    "history_sync_optin.ts",
+    "history_sync_optin_app.ts",
+    "history_sync_optin_app.html.ts",
+  ]
+
+  mojo_files_deps = [ "//chrome/browser/ui/webui/signin/history_sync_optin:mojo_bindings_ts__generator" ]
+  mojo_files = [ "$root_gen_dir/chrome/browser/ui/webui/signin/history_sync_optin/history_sync_optin.mojom-webui.ts" ]
+
+  webui_context_type = "trusted"
+
+  ts_deps = [
+    "//third_party/lit/v3_0:build_ts",
+    "//ui/webui/resources/mojo:build_ts",
+  ]
+}
diff --git a/chrome/browser/resources/signin/history_sync_optin/history_sync_optin.html b/chrome/browser/resources/signin/history_sync_optin/history_sync_optin.html
new file mode 100644
index 0000000..bc7cad7
--- /dev/null
+++ b/chrome/browser/resources/signin/history_sync_optin/history_sync_optin.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<html dir="$i18n{textdirection}" lang="$i18n{language}">
+  <head>
+    <meta charset="utf-8">
+    <link rel="stylesheet" href="chrome://resources/css/md_colors.css">
+    <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
+    <style>
+      body {
+        margin: 0;
+      }
+
+      @media (prefers-color-scheme: dark) {
+        html {
+          background: var(--md-background-color);
+        }
+      }
+    </style>
+  </head>
+  <body>
+    <history-sync-optin-app></history-sync-optin-app>
+    <script type="module" src="history_sync_optin.js"></script>
+  </body>
+</html>
diff --git a/chrome/browser/resources/signin/history_sync_optin/history_sync_optin.ts b/chrome/browser/resources/signin/history_sync_optin/history_sync_optin.ts
new file mode 100644
index 0000000..8b3027c9
--- /dev/null
+++ b/chrome/browser/resources/signin/history_sync_optin/history_sync_optin.ts
@@ -0,0 +1,8 @@
+/* Copyright 2025 The Chromium Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+import './history_sync_optin_app.js';
+
+export {PageCallbackRouter, PageHandlerInterface, PageRemote} from './history_sync_optin.mojom-webui.js';
+export {HistorySyncOptinAppElement} from './history_sync_optin_app.js';
diff --git a/chrome/browser/resources/signin/history_sync_optin/history_sync_optin_app.html.ts b/chrome/browser/resources/signin/history_sync_optin/history_sync_optin_app.html.ts
new file mode 100644
index 0000000..485f6d0
--- /dev/null
+++ b/chrome/browser/resources/signin/history_sync_optin/history_sync_optin_app.html.ts
@@ -0,0 +1,13 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {html} from '//resources/lit/v3_0/lit.rollup.js';
+
+import type {HistorySyncOptinAppElement} from './history_sync_optin_app.js';
+
+export function getHtml(this: HistorySyncOptinAppElement) {
+  return html`
+<div>
+</div>`;
+}
diff --git a/chrome/browser/resources/signin/history_sync_optin/history_sync_optin_app.ts b/chrome/browser/resources/signin/history_sync_optin/history_sync_optin_app.ts
new file mode 100644
index 0000000..b8bf8f7
--- /dev/null
+++ b/chrome/browser/resources/signin/history_sync_optin/history_sync_optin_app.ts
@@ -0,0 +1,28 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import '/strings.m.js';
+
+import {CrLitElement} from '//resources/lit/v3_0/lit.rollup.js';
+
+import {getHtml} from './history_sync_optin_app.html.js';
+
+export class HistorySyncOptinAppElement extends CrLitElement {
+  static get is() {
+    return 'history-sync-optin-app';
+  }
+
+  override render() {
+    return getHtml.bind(this)();
+  }
+}
+
+declare global {
+  interface HTMLElementTagNameMap {
+    'history-sync-optin-app': HistorySyncOptinAppElement;
+  }
+}
+
+customElements.define(
+    HistorySyncOptinAppElement.is, HistorySyncOptinAppElement);
diff --git a/chrome/browser/safety_check/android/BUILD.gn b/chrome/browser/safety_check/android/BUILD.gn
index 3737424..1a854747 100644
--- a/chrome/browser/safety_check/android/BUILD.gn
+++ b/chrome/browser/safety_check/android/BUILD.gn
@@ -90,8 +90,11 @@
     "//base:base_java_test_support",
     "//base/test:test_support_java",
     "//chrome/android:chrome_java",
+    "//chrome/browser/flags:java",
     "//chrome/browser/password_check:public_java",
     "//chrome/browser/password_manager/android:java",
+    "//chrome/browser/password_manager/android:settings_interface_java",
+    "//chrome/browser/password_manager/android:test_support_java",
     "//chrome/browser/preferences:java",
     "//chrome/browser/settings:test_support_java",
     "//chrome/browser/sync/android:java",
diff --git a/chrome/browser/safety_check/android/java/src/org/chromium/chrome/browser/safety_check/SafetyCheckCoordinator.java b/chrome/browser/safety_check/android/java/src/org/chromium/chrome/browser/safety_check/SafetyCheckCoordinator.java
index 8dc9be2..9950e2e 100644
--- a/chrome/browser/safety_check/android/java/src/org/chromium/chrome/browser/safety_check/SafetyCheckCoordinator.java
+++ b/chrome/browser/safety_check/android/java/src/org/chromium/chrome/browser/safety_check/SafetyCheckCoordinator.java
@@ -13,6 +13,7 @@
 import androidx.lifecycle.Observer;
 
 import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.password_manager.PasswordManagerHelper;
 import org.chromium.chrome.browser.password_manager.PasswordStoreBridge;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -185,7 +186,7 @@
             SafetyCheckSettingsFragment settingsFragment, PropertyModel safetyCheckModel) {
         if (isAccountPasswordStorageUsed()) {
             String title =
-                    usesSplitStoresAndUPMForLocal(mPrefService)
+                    usesFullUpm()
                             ? mSettingsFragment.getString(
                                     R.string.safety_check_passwords_account_title,
                                     CoreAccountInfo.getEmailFrom(mSyncService.getAccountInfo()))
@@ -199,7 +200,7 @@
         }
         if (isLocalPasswordStorageUsed()) {
             String title =
-                    usesSplitStoresAndUPMForLocal(mPrefService)
+                    usesFullUpm()
                             ? mSettingsFragment.getString(
                                     R.string.safety_check_passwords_local_title)
                             : mSettingsFragment.getString(R.string.safety_check_passwords_title);
@@ -247,7 +248,7 @@
     @Override
     public boolean isLocalPasswordStorageUsed() {
         if (!PasswordManagerHelper.hasChosenToSyncPasswords(mSyncService)) return true;
-        if (usesSplitStoresAndUPMForLocal(mPrefService)) return true;
+        if (usesFullUpm()) return true;
         return false;
     }
 
@@ -256,4 +257,14 @@
         if (PasswordManagerHelper.hasChosenToSyncPasswords(mSyncService)) return true;
         return false;
     }
+
+    private boolean usesFullUpm() {
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.LOGIN_DB_DEPRECATION_ANDROID)) {
+            // In this case, Safety Check is only used from the PhishGuard dialog if
+            // a phished credential is in both local and account stores, so UPM is definitely
+            // available.
+            return true;
+        }
+        return usesSplitStoresAndUPMForLocal(mPrefService);
+    }
 }
diff --git a/chrome/browser/safety_check/android/javatests/src/org/chromium/chrome/browser/safety_check/SafetyCheckSettingsFragmentTest.java b/chrome/browser/safety_check/android/javatests/src/org/chromium/chrome/browser/safety_check/SafetyCheckSettingsFragmentTest.java
index b04f9d6..717d11ac 100644
--- a/chrome/browser/safety_check/android/javatests/src/org/chromium/chrome/browser/safety_check/SafetyCheckSettingsFragmentTest.java
+++ b/chrome/browser/safety_check/android/javatests/src/org/chromium/chrome/browser/safety_check/SafetyCheckSettingsFragmentTest.java
@@ -6,6 +6,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
@@ -24,16 +25,26 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import org.chromium.base.FeatureOverrides;
 import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.params.ParameterAnnotations;
+import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate;
+import org.chromium.base.test.params.ParameterProvider;
+import org.chromium.base.test.params.ParameterSet;
+import org.chromium.base.test.params.ParameterizedRunner;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.Criteria;
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.DoNotBatch;
+import org.chromium.base.test.util.Features.DisableFeatures;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.password_check.PasswordCheck;
 import org.chromium.chrome.browser.password_check.PasswordCheckFactory;
+import org.chromium.chrome.browser.password_manager.PasswordManagerBackendSupportHelper;
 import org.chromium.chrome.browser.password_manager.PasswordManagerHelper;
 import org.chromium.chrome.browser.password_manager.PasswordManagerHelperJni;
+import org.chromium.chrome.browser.password_manager.PasswordManagerTestHelper;
 import org.chromium.chrome.browser.password_manager.PasswordManagerUtilBridge;
 import org.chromium.chrome.browser.password_manager.PasswordManagerUtilBridgeJni;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
@@ -42,18 +53,21 @@
 import org.chromium.chrome.browser.safety_check.SafetyCheckProperties.UpdatesState;
 import org.chromium.chrome.browser.settings.SettingsActivityTestRule;
 import org.chromium.chrome.browser.sync.SyncServiceFactory;
-import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate;
+import org.chromium.components.prefs.PrefService;
 import org.chromium.components.signin.base.CoreAccountInfo;
 import org.chromium.components.signin.base.GaiaId;
 import org.chromium.components.sync.SyncService;
 import org.chromium.components.sync.UserSelectableType;
 import org.chromium.ui.modelutil.PropertyModel;
 
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Set;
 
 /** Tests {@link SafetyCheckSettingsFragment} together with {@link SafetyCheckViewBinder}. */
-@RunWith(ChromeJUnit4ClassRunner.class)
+@RunWith(ParameterizedRunner.class)
+@UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class)
 @DoNotBatch(
         reason =
                 "The activity should be restarted for each test to not share saved user preferences"
@@ -76,12 +90,25 @@
     @Mock private PasswordCheck mPasswordCheck;
     @Mock private SyncService mSyncService;
     @Mock private PasswordManagerUtilBridge.Natives mPasswordManagerUtilBridgeNativeMock;
+    @Mock private PasswordManagerBackendSupportHelper mBackendSupportHelperMock;
     @Mock private PasswordManagerHelper.Natives mPasswordManagerHelperNativeMock;
 
     private PropertyModel mSafetyCheckModel;
     private PropertyModel mPasswordCheckPreferenceLocalModel;
     private SafetyCheckSettingsFragment mFragment;
 
+    // Set only if the test is parameterized.
+    private Boolean mIsLoginDbDeprecationEnabled;
+
+    public static class LoginDbDeprecationParams implements ParameterProvider {
+        @Override
+        public Iterable<ParameterSet> getParameters() {
+            return Arrays.asList(
+                    new ParameterSet().value(true).name("LoginDbDeprecationEnabled"),
+                    new ParameterSet().value(false).name("LoginDbDeprecationDisabled"));
+        }
+    }
+
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
@@ -89,11 +116,16 @@
         SyncServiceFactory.setInstanceForTesting(mSyncService);
         PasswordManagerUtilBridgeJni.setInstanceForTesting(mPasswordManagerUtilBridgeNativeMock);
         PasswordManagerHelperJni.setInstanceForTesting(mPasswordManagerHelperNativeMock);
+        PasswordManagerBackendSupportHelper.setInstanceForTesting(mBackendSupportHelperMock);
+        // Make sure that if requests to the UPM backends are made, they hit the fake backends.
+        PasswordManagerTestHelper.setUpGmsCoreFakeBackends();
     }
 
     @Test
     @SmallTest
-    public void testLastRunTimestampStrings() {
+    @ParameterAnnotations.UseMethodParameter(LoginDbDeprecationParams.class)
+    public void testLastRunTimestampStrings(boolean loginDbDeprecationEnabled) {
+        setUpLoginDbDeprecation(loginDbDeprecationEnabled);
         long t0 = 12345;
         Context context = ApplicationProvider.getApplicationContext();
         // Start time not set - returns an empty string.
@@ -177,8 +209,14 @@
     }
 
     private void configurePasswordManagerUtilBridge(boolean usesSplitStores) {
-        when(mPasswordManagerUtilBridgeNativeMock.usesSplitStoresAndUPMForLocal(any()))
-                .thenReturn(usesSplitStores);
+        if (mIsLoginDbDeprecationEnabled == null || !mIsLoginDbDeprecationEnabled) {
+            when(mPasswordManagerUtilBridgeNativeMock.usesSplitStoresAndUPMForLocal(any()))
+                    .thenReturn(usesSplitStores);
+        } else {
+            when(mPasswordManagerUtilBridgeNativeMock.isPasswordManagerAvailable(
+                            any(PrefService.class), eq(true)))
+                    .thenReturn(usesSplitStores);
+        }
     }
 
     private void verifyNullStateDisplayedCorrectly(
@@ -209,8 +247,10 @@
         assertEquals("", updates.getSummary());
     }
 
+    // After login db deprecation, safety check is only displayed if split stores are used.
     @Test
     @MediumTest
+    @DisableFeatures(ChromeFeatureList.LOGIN_DB_DEPRECATION_ANDROID)
     public void testNullStateDisplayedCorrectlySyncOffNoUsingSplitStores() {
         verifyNullStateDisplayedCorrectly(
                 /* isPasswordSyncEnabled= */ false, /* usesSplitStores= */ false);
@@ -218,14 +258,19 @@
 
     @Test
     @MediumTest
-    public void testNullStateDisplayedCorrectlySyncOffUsingSplitStores() {
+    @ParameterAnnotations.UseMethodParameter(LoginDbDeprecationParams.class)
+    public void testNullStateDisplayedCorrectlySyncOffUsingSplitStores(
+            boolean isLoginDbDeprecationEnabled) {
+        setUpLoginDbDeprecation(isLoginDbDeprecationEnabled);
         verifyNullStateDisplayedCorrectly(
                 /* isPasswordSyncEnabled= */ false, /* usesSplitStores= */ true);
     }
 
+    // After login db deprecation, safety check is only displayed if split stores are used.
     @Test
     @MediumTest
     @DisableIf.Build(sdk_equals = Build.VERSION_CODES.S_V2, message = "crbug.com/41496704")
+    @DisableFeatures(ChromeFeatureList.LOGIN_DB_DEPRECATION_ANDROID)
     public void testNullStateDisplayedCorrectlySyncOnNoUsingSplitStores() {
         verifyNullStateDisplayedCorrectly(
                 /* isPasswordSyncEnabled= */ true, /* usesSplitStores= */ false);
@@ -233,13 +278,18 @@
 
     @Test
     @MediumTest
-    public void testNullStateDisplayedCorrectlySyncOnUsingSplitStores() {
+    @ParameterAnnotations.UseMethodParameter(LoginDbDeprecationParams.class)
+    public void testNullStateDisplayedCorrectlySyncOnUsingSplitStores(
+            boolean isLoginDbDeprecationEnabled) {
+        setUpLoginDbDeprecation(isLoginDbDeprecationEnabled);
         verifyNullStateDisplayedCorrectly(true, true);
     }
 
     @Test
     @MediumTest
-    public void testPasswordsCheckTitlesAreCorrect() {
+    @ParameterAnnotations.UseMethodParameter(LoginDbDeprecationParams.class)
+    public void testPasswordsCheckTitlesAreCorrect(boolean isLoginDbDeprecationEnabled) {
+        setUpLoginDbDeprecation(isLoginDbDeprecationEnabled);
         configureMockSyncService(true);
         configurePasswordManagerUtilBridge(true);
         mSettingsActivityTestRule.startSettingsActivity();
@@ -259,7 +309,9 @@
 
     @Test
     @MediumTest
-    public void testStateChangeDisplayedCorrectly() {
+    @ParameterAnnotations.UseMethodParameter(LoginDbDeprecationParams.class)
+    public void testStateChangeDisplayedCorrectly(boolean isLoginDbDeprecationEnabled) {
+        setUpLoginDbDeprecation(isLoginDbDeprecationEnabled);
         createFragmentAndModel();
 
         Preference passwordsLocal = mFragment.findPreference(PASSWORDS_LOCAL);
@@ -289,7 +341,9 @@
 
     @Test
     @MediumTest
-    public void testSafetyCheckElementsOnClick() {
+    @ParameterAnnotations.UseMethodParameter(LoginDbDeprecationParams.class)
+    public void testSafetyCheckElementsOnClick(boolean isLoginDbDeprecationEnabled) {
+        setUpLoginDbDeprecation(isLoginDbDeprecationEnabled);
         createFragmentAndModel();
         CallbackHelper passwordsLocalClicked = new CallbackHelper();
         CallbackHelper safeBrowsingClicked = new CallbackHelper();
@@ -346,7 +400,9 @@
 
     @Test
     @MediumTest
-    public void testSafetyCheckDoNotImmediatelyRunByDefault() {
+    @ParameterAnnotations.UseMethodParameter(LoginDbDeprecationParams.class)
+    public void testSafetyCheckDoNotImmediatelyRunByDefault(boolean isLoginDbDeprecationEnabled) {
+        setUpLoginDbDeprecation(isLoginDbDeprecationEnabled);
         createFragmentAndModelByBundle(/* safetyCheckImmediateRun= */ false);
         assertEquals(false, mFragment.shouldRunSafetyCheckImmediately());
         assertEquals(
@@ -358,7 +414,9 @@
 
     @Test
     @MediumTest
-    public void testSafetyCheckImmediatelyRunByBundle() {
+    @ParameterAnnotations.UseMethodParameter(LoginDbDeprecationParams.class)
+    public void testSafetyCheckImmediatelyRunByBundle(boolean isLoginDbDeprecationEnabled) {
+        setUpLoginDbDeprecation(isLoginDbDeprecationEnabled);
         createFragmentAndModelByBundle(/* safetyCheckImmediateRun= */ true);
 
         // Make sure the safety check was ran.
@@ -373,4 +431,16 @@
                             Matchers.not(0));
                 });
     }
+
+    private void setUpLoginDbDeprecation(boolean isLoginDbDeprecationEnabled) {
+        mIsLoginDbDeprecationEnabled = isLoginDbDeprecationEnabled;
+        if (isLoginDbDeprecationEnabled) {
+            FeatureOverrides.enable(ChromeFeatureList.LOGIN_DB_DEPRECATION_ANDROID);
+            when(mBackendSupportHelperMock.isBackendPresent()).thenReturn(true);
+            // The password manger is always available in Safety Check after login db deprecation.
+            configurePasswordManagerUtilBridge(true);
+        } else {
+            FeatureOverrides.disable(ChromeFeatureList.LOGIN_DB_DEPRECATION_ANDROID);
+        }
+    }
 }
diff --git a/chrome/browser/signin/signin_promo_unittest.cc b/chrome/browser/signin/signin_promo_unittest.cc
index 57d9d69..b9730bb 100644
--- a/chrome/browser/signin/signin_promo_unittest.cc
+++ b/chrome/browser/signin/signin_promo_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "build/build_config.h"
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
+#include "chrome/browser/extensions/extension_sync_util.h"
 #include "chrome/browser/signin/chrome_signin_client_factory.h"
 #include "chrome/browser/signin/chrome_signin_client_test_util.h"
 #include "chrome/browser/signin/chrome_signin_pref_names.h"
@@ -33,6 +34,7 @@
 #include "components/sync/test/mock_sync_service.h"
 #include "components/sync_bookmarks/switches.h"
 #include "content/public/test/browser_task_environment.h"
+#include "extensions/common/extension_builder.h"
 #include "google_apis/gaia/gaia_id.h"
 #include "services/network/test/test_url_loader_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -160,11 +162,26 @@
 
   TestingProfile* profile() { return profile_.get(); }
 
+  const extensions::Extension* CreateExtension(
+      extensions::mojom::ManifestLocation location =
+          extensions::mojom::ManifestLocation::kInternal) {
+    extension_ = extensions::ExtensionBuilder()
+                     .SetManifest(base::Value::Dict()
+                                      .Set("name", "test")
+                                      .Set("manifest_version", 2)
+                                      .Set("version", "1.0.0"))
+                     .SetLocation(location)
+                     .Build();
+
+    return extension_.get();
+  }
+
  private:
   content::BrowserTaskEnvironment task_environment_;
   std::unique_ptr<TestingProfile> profile_;
   std::unique_ptr<IdentityTestEnvironmentProfileAdaptor>
       identity_test_env_adaptor_;
+  scoped_refptr<const extensions::Extension> extension_;
 };
 
 TEST_F(ShowPromoTest, DoNotShowAddressSignInPromoWithoutImprovedBrowserSignin) {
@@ -196,6 +213,15 @@
   EXPECT_FALSE(ShouldShowBookmarkSignInPromo(*profile()));
 }
 
+TEST_F(ShowPromoTest, DoNotShowExtensionSignInPromoWithoutExplicitSignIn) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{},
+      /*disabled_features=*/{switches::kEnableExtensionsExplicitBrowserSignin});
+
+  EXPECT_FALSE(ShouldShowExtensionSignInPromo(*profile(), *CreateExtension()));
+}
+
 #if !BUILDFLAG(IS_ANDROID)
 class ShowSyncPromoTest : public ShowPromoTest {
  protected:
@@ -223,6 +249,54 @@
 }
 #endif  // !BUILDFLAG(IS_ANDROID)
 
+#if BUILDFLAG(ENABLE_DICE_SUPPORT)
+TEST_F(ShowSyncPromoTest, ShowExtensionSyncPromoWithoutFeatureFlag) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{},
+      /*disabled_features=*/{switches::kEnableExtensionsExplicitBrowserSignin});
+
+  EXPECT_TRUE(ShouldShowExtensionSyncPromo(*profile(), *CreateExtension()));
+}
+
+TEST_F(ShowSyncPromoTest, DoNotShowExtensionSyncPromoWithSyncDisabled) {
+  DisableSync();
+  ASSERT_FALSE(ShouldShowSyncPromo(*profile()));
+
+  EXPECT_FALSE(ShouldShowExtensionSyncPromo(*profile(), *CreateExtension()));
+}
+
+TEST_F(ShowSyncPromoTest, DoNotShowExtensionSyncPromoWithUnpackedExtension) {
+  const extensions::Extension* unpacked_extension =
+      CreateExtension(extensions::mojom::ManifestLocation::kUnpacked);
+
+  // Unpacked extensions cannot be synced so the sync promo is not shown.
+  ASSERT_TRUE(unpacked_extension);
+  ASSERT_FALSE(
+      extensions::sync_util::ShouldSync(profile(), unpacked_extension));
+
+  EXPECT_FALSE(ShouldShowExtensionSyncPromo(*profile(), *unpacked_extension));
+}
+
+TEST_F(ShowSyncPromoTest,
+       DoNotShowExtensionSyncPromoWithSyncingExtensionsEnabled) {
+  ON_CALL(*sync_service()->GetMockUserSettings(), GetSelectedTypes())
+      .WillByDefault(testing::Return(syncer::UserSelectableTypeSet::All()));
+  ASSERT_TRUE(extensions::sync_util::IsSyncingExtensionsEnabled(profile()));
+
+  EXPECT_FALSE(ShouldShowExtensionSyncPromo(*profile(), *CreateExtension()));
+}
+
+TEST_F(ShowSyncPromoTest,
+       DoNotShowExtensionSyncPromoWithExplicitBrowserSigninPref) {
+  profile()->GetPrefs()->SetBoolean(prefs::kExplicitBrowserSignin, true);
+  ASSERT_TRUE(profile()->GetPrefs()->GetBoolean(prefs::kExplicitBrowserSignin));
+
+  EXPECT_FALSE(ShouldShowExtensionSyncPromo(*profile(), *CreateExtension()));
+}
+
+#endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)
+
 #if !BUILDFLAG(IS_CHROMEOS)
 TEST_F(ShowSyncPromoTest, ShowPromoWithSignedInAccount) {
   MakePrimaryAccountAvailable(identity_manager(), "test@email.com",
@@ -242,11 +316,12 @@
  public:
   void SetUp() override {
     ShowPromoTest::SetUp();
-    feature_list.InitWithFeatures(
+    feature_list_.InitWithFeatures(
         /*enabled_features=*/
         {switches::kImprovedSigninUIOnDesktop,
          switches::kSyncEnableBookmarksInTransportMode,
-         switches::kSyncMinimizeDeletionsDuringBookmarkBatchUpload},
+         switches::kSyncMinimizeDeletionsDuringBookmarkBatchUpload,
+         switches::kEnableExtensionsExplicitBrowserSignin},
         /*disabled_features=*/{});
     ON_CALL(*sync_service(), GetDataTypesForTransportOnlyMode())
         .WillByDefault(testing::Return(syncer::DataTypeSet::All()));
@@ -264,7 +339,7 @@
   }
 
  private:
-  base::test::ScopedFeatureList feature_list;
+  base::test::ScopedFeatureList feature_list_;
 };
 
 TEST_F(ShowSigninPromoTestWithFeatureFlags, ShowPromoWithNoAccount) {
@@ -354,6 +429,22 @@
   EXPECT_FALSE(ShouldShowBookmarkSignInPromo(*profile()));
 }
 
+TEST_F(ShowSigninPromoTestWithFeatureFlags, ShowExtensionsPromoWithNoAccount) {
+  EXPECT_TRUE(ShouldShowExtensionSignInPromo(*profile(), *CreateExtension()));
+}
+
+TEST_F(ShowSigninPromoTestWithFeatureFlags,
+       DoNotShowExtensionPromoWithUnpackedExtension) {
+  const extensions::Extension* unpacked_extension =
+      CreateExtension(extensions::mojom::ManifestLocation::kUnpacked);
+
+  // Unpacked extensions cannot be synced so the sign in promo is not shown.
+  ASSERT_TRUE(unpacked_extension);
+  ASSERT_FALSE(
+      extensions::sync_util::ShouldSync(profile(), unpacked_extension));
+  EXPECT_FALSE(ShouldShowExtensionSignInPromo(*profile(), *unpacked_extension));
+}
+
 TEST_F(ShowSigninPromoTestWithFeatureFlags,
        DoNotShowPasswordPromoAfterFiveTimesShown) {
   ASSERT_TRUE(ShouldShowPasswordSignInPromo(*profile()));
diff --git a/chrome/browser/signin/signin_promo_util.cc b/chrome/browser/signin/signin_promo_util.cc
index 83533271..cd19b3b 100644
--- a/chrome/browser/signin/signin_promo_util.cc
+++ b/chrome/browser/signin/signin_promo_util.cc
@@ -25,6 +25,10 @@
 #include "components/sync/service/sync_prefs.h"
 #endif  // !BUILDFLAG(IS_ANDROID)
 
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+#include "chrome/browser/extensions/extension_sync_util.h"
+#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
+
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
 #include "chrome/browser/signin/chrome_signin_pref_names.h"
@@ -54,7 +58,7 @@
     case SignInPromoType::kBookmark:
       return syncer::BOOKMARKS;
     case SignInPromoType::kExtension:
-      NOTREACHED();
+      return syncer::EXTENSIONS;
   }
 }
 
@@ -209,6 +213,57 @@
 }
 #endif  // !BUILDFLAG(IS_ANDROID)
 
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+bool ShouldShowExtensionSyncPromo(Profile& profile,
+                                  const extensions::Extension& extension) {
+#if BUILDFLAG(ENABLE_DICE_SUPPORT)
+  // Don't show the promo if it does not pass the sync base checks.
+  if (!signin::ShouldShowSyncPromo(profile)) {
+    return false;
+  }
+
+  if (!extensions::sync_util::ShouldSync(&profile, &extension)) {
+    return false;
+  }
+
+  // `ShouldShowSyncPromo()` does not check if extensions are syncing in
+  // transport mode. That's why `IsSyncingExtensionsEnabled()` is added so the
+  // sign in promo is not shown in that case.
+  if (extensions::sync_util::IsSyncingExtensionsEnabled(&profile)) {
+    return false;
+  }
+
+  // The promo is not shown to users that have explicitly signed in through the
+  // browser (even if extensions are not syncing).
+  if (profile.GetPrefs()->GetBoolean(prefs::kExplicitBrowserSignin)) {
+    return false;
+  }
+
+  return true;
+#else
+  return false;
+#endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)
+}
+
+bool ShouldShowExtensionSignInPromo(Profile& profile,
+                                    const extensions::Extension& extension) {
+#if BUILDFLAG(ENABLE_DICE_SUPPORT)
+  if (!base::FeatureList::IsEnabled(
+          switches::kEnableExtensionsExplicitBrowserSignin)) {
+    return false;
+  }
+
+  if (!ShouldShowExtensionSyncPromo(profile, extension)) {
+    return false;
+  }
+
+  return ShouldShowSignInPromoCommon(profile, SignInPromoType::kExtension);
+#else
+  return false;
+#endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)
+}
+#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
+
 bool ShouldShowPasswordSignInPromo(Profile& profile) {
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
   return ShouldShowSignInPromoCommon(profile, SignInPromoType::kPassword);
diff --git a/chrome/browser/signin/signin_promo_util.h b/chrome/browser/signin/signin_promo_util.h
index fd34aa73..71a8d76 100644
--- a/chrome/browser/signin/signin_promo_util.h
+++ b/chrome/browser/signin/signin_promo_util.h
@@ -5,7 +5,9 @@
 #ifndef CHROME_BROWSER_SIGNIN_SIGNIN_PROMO_UTIL_H_
 #define CHROME_BROWSER_SIGNIN_SIGNIN_PROMO_UTIL_H_
 
+#include "build/build_config.h"
 #include "components/signin/public/base/signin_buildflags.h"
+#include "extensions/buildflags/buildflags.h"
 
 class Profile;
 
@@ -17,12 +19,30 @@
 class AutofillProfile;
 }
 
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+namespace extensions {
+class Extension;
+}
+#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
+
 namespace signin {
 
 enum class SignInPromoType;
 
+#if !BUILDFLAG(IS_ANDROID)
 // Whether we should show the sync promo.
 bool ShouldShowSyncPromo(Profile& profile);
+#endif  // !BUILDFLAG(IS_ANDROID)
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+// Whether we should show the sync promo after an extension was installed.
+bool ShouldShowExtensionSyncPromo(Profile& profile,
+                                  const extensions::Extension& extension);
+
+// Whether we should show the sign in promo after an extension was installed.
+bool ShouldShowExtensionSignInPromo(Profile& profile,
+                                    const extensions::Extension& extension);
+#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
 
 // Whether we should show the sign in promo after a password was saved.
 bool ShouldShowPasswordSignInPromo(Profile& profile);
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index fe76d8c..51c55cb 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -3038,10 +3038,19 @@
 
   if (is_win || is_mac || is_linux) {
     sources += [
+      "profiles/profile_customization_bubble_sync_controller.h",
+      "profiles/profile_customization_synced_theme_waiter.cc",
+      "profiles/profile_customization_synced_theme_waiter.h",
+      "profiles/profile_customization_util.cc",
+      "profiles/profile_customization_util.h",
+      "profiles/profile_picker.cc",
+      "profiles/profile_picker.h",
       "shortcuts/desktop_shortcuts_utils.cc",
       "shortcuts/desktop_shortcuts_utils.h",
       "startup/default_browser_prompt/default_browser_prompt.cc",
       "startup/default_browser_prompt/default_browser_prompt.h",
+      "startup/first_run_service.cc",
+      "startup/first_run_service.h",
       "startup/web_app_info_recorder_utils.cc",
       "startup/web_app_info_recorder_utils.h",
       "views/media_preview/active_devices_media_coordinator.cc",
@@ -3086,87 +3095,6 @@
       "views/media_preview/permission_prompt_previews_coordinator.h",
       "views/media_preview/scroll_media_preview.cc",
       "views/media_preview/scroll_media_preview.h",
-      "views/web_apps/deprecated_apps_dialog_view.cc",
-      "views/web_apps/deprecated_apps_dialog_view.h",
-      "views/web_apps/force_installed_deprecated_apps_dialog_view.cc",
-      "views/web_apps/force_installed_deprecated_apps_dialog_view.h",
-      "views/web_apps/force_installed_preinstalled_deprecated_app_dialog_view.cc",
-      "views/web_apps/force_installed_preinstalled_deprecated_app_dialog_view.h",
-      "webui/app_home/app_home_page_handler.cc",
-      "webui/app_home/app_home_page_handler.h",
-      "webui/app_home/app_home_ui.cc",
-      "webui/app_home/app_home_ui.h",
-      "webui/app_management/web_app_settings_page_handler.cc",
-      "webui/app_management/web_app_settings_page_handler.h",
-      "webui/app_settings/web_app_settings_navigation_throttle.cc",
-      "webui/app_settings/web_app_settings_navigation_throttle.h",
-      "webui/app_settings/web_app_settings_ui.cc",
-      "webui/app_settings/web_app_settings_ui.h",
-      "webui/browser_switch/browser_switch_ui.cc",
-      "webui/browser_switch/browser_switch_ui.h",
-      "webui/on_device_translation_internals/on_device_translation_internals_page_handler_impl.cc",
-      "webui/on_device_translation_internals/on_device_translation_internals_page_handler_impl.h",
-      "webui/on_device_translation_internals/on_device_translation_internals_ui.cc",
-      "webui/on_device_translation_internals/on_device_translation_internals_ui.h",
-    ]
-
-    if (enable_video_effects) {
-      sources += [
-        "views/media_preview/camera_preview/blur_switch_view_controller.cc",
-        "views/media_preview/camera_preview/blur_switch_view_controller.h",
-      ]
-    }
-
-    deps += [
-      "//chrome/app:generated_resources",
-      "//chrome/browser/on_device_translation",
-      "//chrome/browser/on_device_translation:language_pack_util",
-      "//chrome/browser/shortcuts",
-      "//components/capture_mode",
-      "//services/audio/public/mojom",
-      "//services/video_capture/public/mojom",
-      "//services/video_effects/buildflags",
-    ]
-  }
-
-  if (is_win || is_mac || is_linux || is_chromeos) {
-    sources += [
-      "passwords/password_cross_domain_confirmation_popup_view.h",
-      "webui/app_management/app_management_page_handler_base.cc",
-      "webui/app_management/app_management_page_handler_base.h",
-      "webui/app_management/app_management_page_handler_factory.cc",
-      "webui/app_management/app_management_page_handler_factory.h",
-      "webui/connectors_internals/connectors_internals_page_handler.cc",
-      "webui/connectors_internals/connectors_internals_page_handler.h",
-      "webui/connectors_internals/connectors_internals_ui.cc",
-      "webui/connectors_internals/connectors_internals_ui.h",
-      "webui/connectors_internals/device_trust_utils.cc",
-      "webui/connectors_internals/device_trust_utils.h",
-    ]
-
-    deps += [
-      "//chrome/browser/enterprise/connectors/device_trust:features",
-      "//chrome/browser/enterprise/connectors/device_trust/attestation/common:types",
-      "//chrome/browser/enterprise/connectors/device_trust/common",
-      "//components/device_signals/core/browser",
-    ]
-
-    if (enterprise_client_certificates) {
-      deps += [ "//components/enterprise/client_certificates/core" ]
-    }
-  }
-
-  if (is_win || is_mac || is_linux) {
-    sources += [
-      "profiles/profile_customization_bubble_sync_controller.h",
-      "profiles/profile_customization_synced_theme_waiter.cc",
-      "profiles/profile_customization_synced_theme_waiter.h",
-      "profiles/profile_customization_util.cc",
-      "profiles/profile_customization_util.h",
-      "profiles/profile_picker.cc",
-      "profiles/profile_picker.h",
-      "startup/first_run_service.cc",
-      "startup/first_run_service.h",
       "views/profiles/badged_profile_photo.cc",
       "views/profiles/badged_profile_photo.h",
       "views/profiles/profile_customization_bubble_sync_controller.cc",
@@ -3192,10 +3120,32 @@
       "views/profiles/profile_picker_view.cc",
       "views/profiles/profile_picker_view.h",
       "views/profiles/profile_picker_web_contents_host.h",
+      "views/web_apps/deprecated_apps_dialog_view.cc",
+      "views/web_apps/deprecated_apps_dialog_view.h",
+      "views/web_apps/force_installed_deprecated_apps_dialog_view.cc",
+      "views/web_apps/force_installed_deprecated_apps_dialog_view.h",
+      "views/web_apps/force_installed_preinstalled_deprecated_app_dialog_view.cc",
+      "views/web_apps/force_installed_preinstalled_deprecated_app_dialog_view.h",
+      "webui/app_home/app_home_page_handler.cc",
+      "webui/app_home/app_home_page_handler.h",
+      "webui/app_home/app_home_ui.cc",
+      "webui/app_home/app_home_ui.h",
+      "webui/app_management/web_app_settings_page_handler.cc",
+      "webui/app_management/web_app_settings_page_handler.h",
+      "webui/app_settings/web_app_settings_navigation_throttle.cc",
+      "webui/app_settings/web_app_settings_navigation_throttle.h",
+      "webui/app_settings/web_app_settings_ui.cc",
+      "webui/app_settings/web_app_settings_ui.h",
+      "webui/browser_switch/browser_switch_ui.cc",
+      "webui/browser_switch/browser_switch_ui.h",
       "webui/intro/intro_handler.cc",
       "webui/intro/intro_handler.h",
       "webui/intro/intro_ui.cc",
       "webui/intro/intro_ui.h",
+      "webui/on_device_translation_internals/on_device_translation_internals_page_handler_impl.cc",
+      "webui/on_device_translation_internals/on_device_translation_internals_page_handler_impl.h",
+      "webui/on_device_translation_internals/on_device_translation_internals_ui.cc",
+      "webui/on_device_translation_internals/on_device_translation_internals_ui.h",
       "webui/profile_helper.cc",
       "webui/profile_helper.h",
       "webui/settings/settings_default_browser_handler.cc",
@@ -3206,10 +3156,25 @@
       "webui/settings/system_handler.h",
     ]
 
+    if (enable_video_effects) {
+      sources += [
+        "views/media_preview/camera_preview/blur_switch_view_controller.cc",
+        "views/media_preview/camera_preview/blur_switch_view_controller.h",
+      ]
+    }
+
     deps += [
+      "//chrome/app:generated_resources",
+      "//chrome/browser/on_device_translation",
+      "//chrome/browser/on_device_translation:language_pack_util",
+      "//chrome/browser/shortcuts",
       "//chrome/browser/ui/webui/signin:profile",
       "//chrome/browser/ui/webui/signin:profile_impl",
+      "//components/capture_mode",
       "//components/country_codes",
+      "//services/audio/public/mojom",
+      "//services/video_capture/public/mojom",
+      "//services/video_effects/buildflags",
     ]
 
     # Any circular includes must depend on the target "//chrome/browser:browser_public_dependencies".
@@ -3253,6 +3218,33 @@
     }
   }
 
+  if (is_win || is_mac || is_linux || is_chromeos) {
+    sources += [
+      "passwords/password_cross_domain_confirmation_popup_view.h",
+      "webui/app_management/app_management_page_handler_base.cc",
+      "webui/app_management/app_management_page_handler_base.h",
+      "webui/app_management/app_management_page_handler_factory.cc",
+      "webui/app_management/app_management_page_handler_factory.h",
+      "webui/connectors_internals/connectors_internals_page_handler.cc",
+      "webui/connectors_internals/connectors_internals_page_handler.h",
+      "webui/connectors_internals/connectors_internals_ui.cc",
+      "webui/connectors_internals/connectors_internals_ui.h",
+      "webui/connectors_internals/device_trust_utils.cc",
+      "webui/connectors_internals/device_trust_utils.h",
+    ]
+
+    deps += [
+      "//chrome/browser/enterprise/connectors/device_trust:features",
+      "//chrome/browser/enterprise/connectors/device_trust/attestation/common:types",
+      "//chrome/browser/enterprise/connectors/device_trust/common",
+      "//components/device_signals/core/browser",
+    ]
+
+    if (enterprise_client_certificates) {
+      deps += [ "//components/enterprise/client_certificates/core" ]
+    }
+  }
+
   if (enable_dice_support || is_chromeos) {
     sources += [
       "webui/signin/inline_login_ui.cc",
diff --git a/chrome/browser/ui/android/digital_credentials/java/src/org/chromium/chrome/browser/ui/android/digital_credentials/DigitalIdentitySafetyInterstitialIntegrationTest.java b/chrome/browser/ui/android/digital_credentials/java/src/org/chromium/chrome/browser/ui/android/digital_credentials/DigitalIdentitySafetyInterstitialIntegrationTest.java
index 82ceeda..2d9f260 100644
--- a/chrome/browser/ui/android/digital_credentials/java/src/org/chromium/chrome/browser/ui/android/digital_credentials/DigitalIdentitySafetyInterstitialIntegrationTest.java
+++ b/chrome/browser/ui/android/digital_credentials/java/src/org/chromium/chrome/browser/ui/android/digital_credentials/DigitalIdentitySafetyInterstitialIntegrationTest.java
@@ -102,7 +102,8 @@
             extends IdentityCredentialsDelegate {
         @Override
         public Promise<DigitalCredential> get(Activity activity, String origin, String request) {
-            return Promise.fulfilled(new DigitalCredential("protocol", "token".getBytes()));
+            return Promise.fulfilled(
+                    new DigitalCredential("protocol", "{\"token\" : \"test_token\"}".getBytes()));
         }
     }
 
@@ -198,7 +199,7 @@
 
         DOMUtils.clickNode(mActivityTestRule.getWebContents(), nodeIdToClick);
 
-        waitTillLogTextAreaHasTextContent("\"token\"");
+        waitTillLogTextAreaHasTextContent("\"test_token\"");
 
         if (expectedInterstitialParagraph1ResourceId >= 0) {
             assertTrue(mModalDialogObserver.wasDialogShown());
diff --git a/chrome/browser/ui/extensions/extension_installed_bubble_model.cc b/chrome/browser/ui/extensions/extension_installed_bubble_model.cc
index ebd7ae2e..bf28978b 100644
--- a/chrome/browser/ui/extensions/extension_installed_bubble_model.cc
+++ b/chrome/browser/ui/extensions/extension_installed_bubble_model.cc
@@ -106,17 +106,6 @@
   show_how_to_manage_ = !command.has_value() || anchor_to_omnibox_;
   show_key_binding_ = command.has_value();
 
-  // Note: `ShouldShowSyncPromo` does not check if extensions are syncing in
-  // transport mode. That's why `IsSyncingEnabled` is added so the sign in promo
-  // is not shown in that case.
-  // Finally, make sure the promo is not shown to users that have explicitly
-  // signed in through the browser (even if extensions are not syncing).
-  show_sign_in_promo_ =
-      extensions::sync_util::ShouldSync(profile, extension) &&
-      !extensions::sync_util::IsSyncingExtensionsEnabled(profile) &&
-      signin::ShouldShowSyncPromo(*profile) &&
-      !profile->GetPrefs()->GetBoolean(prefs::kExplicitBrowserSignin);
-
   if (show_how_to_use_) {
     how_to_use_text_ = MakeHowToUseText(action_info, command, keyword);
 
diff --git a/chrome/browser/ui/extensions/extension_installed_bubble_model.h b/chrome/browser/ui/extensions/extension_installed_bubble_model.h
index 6b0f231..9a0e7da 100644
--- a/chrome/browser/ui/extensions/extension_installed_bubble_model.h
+++ b/chrome/browser/ui/extensions/extension_installed_bubble_model.h
@@ -37,7 +37,6 @@
   bool show_how_to_use() const { return show_how_to_use_; }
   bool show_how_to_manage() const { return show_how_to_manage_; }
   bool show_key_binding() const { return show_key_binding_; }
-  bool show_sign_in_promo() const { return show_sign_in_promo_; }
 
   std::u16string GetHowToUseText() const;
 
@@ -60,9 +59,6 @@
   // Whether to show the extension's key binding in the install bubble.
   bool show_key_binding_ = false;
 
-  // Whether to show a signin promo in the install bubble.
-  bool show_sign_in_promo_ = false;
-
   std::u16string how_to_use_text_;
 
   const SkBitmap icon_;
diff --git a/chrome/browser/ui/extensions/extension_installed_bubble_model_unittest.cc b/chrome/browser/ui/extensions/extension_installed_bubble_model_unittest.cc
index cec9ac8..4e9fa84e 100644
--- a/chrome/browser/ui/extensions/extension_installed_bubble_model_unittest.cc
+++ b/chrome/browser/ui/extensions/extension_installed_bubble_model_unittest.cc
@@ -10,14 +10,8 @@
 #include "chrome/browser/extensions/chrome_test_extension_loader.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_service_test_with_install.h"
-#include "chrome/browser/extensions/extension_sync_util.h"
-#include "chrome/browser/extensions/signin_test_util.h"
-#include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
 #include "chrome/common/extensions/api/omnibox.h"
-#include "components/signin/public/base/signin_pref_names.h"
 #include "components/signin/public/base/signin_switches.h"
-#include "components/signin/public/identity_manager/identity_test_environment.h"
-#include "components/signin/public/identity_manager/identity_test_utils.h"
 #include "content/public/test/browser_task_environment.h"
 #include "extensions/common/api/extension_action/action_info.h"
 #include "extensions/common/extension_builder.h"
@@ -67,15 +61,6 @@
                 .Set("description", "Invoke the page action")));
   }
 
-  scoped_refptr<const Extension> LoadExtension(
-      const std::string& extension_path,
-      bool packed) {
-    extensions::ChromeTestExtensionLoader extension_loader(profile());
-    extension_loader.set_pack_extension(packed);
-    return extension_loader.LoadExtension(
-        data_dir().AppendASCII(extension_path));
-  }
-
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
 };
@@ -205,135 +190,3 @@
   EXPECT_TRUE(model.show_how_to_use());
   EXPECT_TRUE(model.anchor_to_action());
 }
-
-TEST_F(ExtensionInstalledBubbleModelTest, ShowSigninPromo) {
-  // Returns whether the sign in promo is shown for the model based on the given
-  // `extension`.
-  auto should_show_signin_promo = [this](const Extension* extension) {
-    ExtensionInstalledBubbleModel model(profile(), extension, SkBitmap());
-    return model.show_sign_in_promo();
-  };
-
-  // Unpacked extensions cannot be synced so the sign in promo is not shown.
-  auto unpacked_extension =
-      LoadExtension("simple_with_popup", /*packed=*/false);
-  ASSERT_TRUE(unpacked_extension);
-  EXPECT_FALSE(should_show_signin_promo(unpacked_extension.get()));
-
-  // Show a sign in promo for a syncable extension installed while the user is
-  // not signed in.
-  auto extension_before_sign_in =
-      LoadExtension("simple_with_file", /*packed=*/true);
-  ASSERT_TRUE(extension_before_sign_in);
-
-#if BUILDFLAG(IS_CHROMEOS)
-  // Note: User is always signed in for ChromeOS, so the sign in promo should
-  // never be shown.
-  EXPECT_FALSE(should_show_signin_promo(extension_before_sign_in.get()));
-#else
-  EXPECT_TRUE(should_show_signin_promo(extension_before_sign_in.get()));
-#endif  // BUILDFLAG(IS_CHROMEOS)
-
-  // Use a test identity environment to mimic signing in a user with sync
-  // enabled.
-  auto identity_test_env_profile_adaptor =
-      std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile());
-  identity_test_env_profile_adaptor->identity_test_env()
-      ->MakePrimaryAccountAvailable("testy@mctestface.com",
-                                    signin::ConsentLevel::kSync);
-
-  // Don't show a sign in promo if the user is currently signed in and syncing.
-  auto extension_after_sign_in =
-      LoadExtension("simple_with_icon", /*packed=*/true);
-  ASSERT_TRUE(extension_after_sign_in);
-  EXPECT_FALSE(should_show_signin_promo(extension_after_sign_in.get()));
-}
-
-class ExtensionInstalledBubbleModelTransportModeTest
-    : public ExtensionInstalledBubbleModelTest {
- public:
-  ExtensionInstalledBubbleModelTransportModeTest() {
-    scoped_feature_list_.InitAndEnableFeature(
-        switches::kEnableExtensionsExplicitBrowserSignin);
-  }
-
- protected:
-  // Returns whether the sign in promo is shown for the model based on the given
-  // `extension`.
-  bool ShouldShowSigninPromo(const Extension* extension) {
-    ExtensionInstalledBubbleModel model(profile(), extension, SkBitmap());
-    return model.show_sign_in_promo();
-  }
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-TEST_F(ExtensionInstalledBubbleModelTransportModeTest, ShowSigninPromo) {
-  // Show a sign in promo for a syncable extension installed while the user is
-  // not signed in.
-  auto extension_before_sign_in =
-      LoadExtension("simple_with_file", /*packed=*/true);
-  ASSERT_TRUE(extension_before_sign_in);
-
-#if BUILDFLAG(IS_CHROMEOS)
-  // Note: User is always signed in for ChromeOS, so the sign in promo should
-  // never be shown.
-  EXPECT_FALSE(ShouldShowSigninPromo(extension_before_sign_in.get()));
-#else
-  EXPECT_TRUE(ShouldShowSigninPromo(extension_before_sign_in.get()));
-#endif  // BUILDFLAG(IS_CHROMEOS)
-
-  // Use a test identity environment to mimic signing a user in with sync
-  // disabled (transport mode).
-  auto identity_test_env_profile_adaptor =
-      std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile());
-  extensions::signin_test_util::SimulateExplicitSignIn(
-      profile(), identity_test_env_profile_adaptor->identity_test_env());
-
-  // Don't show a sign in promo if the user is currently syncing in transport
-  // mode.
-  auto extension_after_sign_in =
-      LoadExtension("simple_with_icon", /*packed=*/true);
-  ASSERT_TRUE(extension_after_sign_in);
-  EXPECT_FALSE(ShouldShowSigninPromo(extension_after_sign_in.get()));
-
-  EXPECT_TRUE(
-      extensions::sync_util::IsSyncingExtensionsInTransportMode(profile()));
-}
-
-TEST_F(ExtensionInstalledBubbleModelTransportModeTest,
-       ShowSigninPromo_NonExtensionsExplicitSignin) {
-  // Show a sign in promo for a syncable extension installed while the user is
-  // not signed in.
-  auto extension_before_sign_in =
-      LoadExtension("simple_with_file", /*packed=*/true);
-  ASSERT_TRUE(extension_before_sign_in);
-
-#if BUILDFLAG(IS_CHROMEOS)
-  // Note: User is always signed in for ChromeOS, so the sign in promo should
-  // never be shown.
-  EXPECT_FALSE(ShouldShowSigninPromo(extension_before_sign_in.get()));
-#else
-  EXPECT_TRUE(ShouldShowSigninPromo(extension_before_sign_in.get()));
-#endif  // BUILDFLAG(IS_CHROMEOS)
-
-  // Use a test identity environment to mimic an explicit signin but not for
-  // extensions.
-  auto identity_test_env_profile_adaptor =
-      std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile());
-  identity_test_env_profile_adaptor->identity_test_env()
-      ->MakePrimaryAccountAvailable("testy@mctestface.com",
-                                    signin::ConsentLevel::kSignin);
-  profile()->GetPrefs()->SetBoolean(prefs::kExplicitBrowserSignin, true);
-
-  // Don't show a sign in promo if the user has explicitly signed in but not
-  // through extensions.
-  auto extension_after_sign_in =
-      LoadExtension("simple_with_icon", /*packed=*/true);
-  ASSERT_TRUE(extension_after_sign_in);
-  EXPECT_FALSE(ShouldShowSigninPromo(extension_after_sign_in.get()));
-
-  EXPECT_FALSE(
-      extensions::sync_util::IsSyncingExtensionsInTransportMode(profile()));
-}
diff --git a/chrome/browser/ui/hats/survey_config.cc b/chrome/browser/ui/hats/survey_config.cc
index 809bdece..8c4774a 100644
--- a/chrome/browser/ui/hats/survey_config.cc
+++ b/chrome/browser/ui/hats/survey_config.cc
@@ -490,8 +490,10 @@
       kHatsSurveyTriggerPerformanceControlsPPM,
       /*presupplied_trigger_id=*/std::nullopt,
       std::vector<std::string>{"Memory Saver Mode Enabled",
-                               "Battery Saver Mode Enabled"},
+                               "Battery Saver Mode Enabled",
+                               "Selected for Uniform Sample"},
       std::vector<std::string>{
+          "Channel",
           // Note memory is reported as a range, eg. "Windows, 4 to 8 GB".
           "Performance Characteristics (OS and Total Memory)"},
       /*log_responses_to_uma=*/true,
diff --git a/chrome/browser/ui/performance_controls/performance_controls_hats_service.cc b/chrome/browser/ui/performance_controls/performance_controls_hats_service.cc
index d429950..6537b8a 100644
--- a/chrome/browser/ui/performance_controls/performance_controls_hats_service.cc
+++ b/chrome/browser/ui/performance_controls/performance_controls_hats_service.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/hats/hats_service.h"
 #include "chrome/browser/ui/hats/hats_service_factory.h"
+#include "chrome/common/channel_info.h"
 #include "components/performance_manager/public/features.h"
 
 using performance_manager::features::kPerformanceControlsPPMSurvey;
@@ -32,6 +33,8 @@
 using performance_manager::features::kPerformanceControlsPPMSurveySegmentName1;
 using performance_manager::features::kPerformanceControlsPPMSurveySegmentName2;
 using performance_manager::features::kPerformanceControlsPPMSurveySegmentName3;
+using performance_manager::features::
+    kPerformanceControlsPPMSurveyUniformSampleValue;
 
 PerformanceControlsHatsService::PerformanceControlsHatsService(Profile* profile)
     : profile_(profile),
@@ -89,13 +92,18 @@
   auto launch_survey_if_enabled =
       [hats_service, battery_saver_mode, memory_saver_mode](
           const base::Feature& feature, const std::string& trigger,
+          const SurveyBitsData& extra_data = {},
           const SurveyStringData& string_data = {}) {
         if (base::FeatureList::IsEnabled(feature)) {
-          hats_service->LaunchSurvey(
-              trigger, base::DoNothing(), base::DoNothing(),
-              {{kMemorySaverPSDName, memory_saver_mode},
-               {kBatterySaverPSDName, battery_saver_mode}},
-              string_data);
+          SurveyBitsData bits_data = {
+              {kMemorySaverPSDName, memory_saver_mode},
+              {kBatterySaverPSDName, battery_saver_mode}};
+          for (const auto& [key, value] : extra_data) {
+            auto [_, inserted] = bits_data.try_emplace(key, value);
+            CHECK(inserted);
+          }
+          hats_service->LaunchSurvey(trigger, base::DoNothing(),
+                                     base::DoNothing(), bits_data, string_data);
         }
       };
 
@@ -107,9 +115,14 @@
   // Survey to correlate UMA metrics with Poor Performance Moments.
   if (auto ppm_segment_name = GetPPMSurveySegmentName();
       !ppm_segment_name.empty() && MayLaunchPPMSurvey()) {
-    launch_survey_if_enabled(kPerformanceControlsPPMSurvey,
-                             kHatsSurveyTriggerPerformanceControlsPPM,
-                             {{kPerformanceSegmentPSDName, ppm_segment_name}});
+    const std::string channel =
+        chrome::GetChannelName(chrome::WithExtendedStable(false));
+    launch_survey_if_enabled(
+        kPerformanceControlsPPMSurvey, kHatsSurveyTriggerPerformanceControlsPPM,
+        {{kUniformSamplePSDName,
+          kPerformanceControlsPPMSurveyUniformSampleValue.Get()}},
+        {{kPerformanceSegmentPSDName, ppm_segment_name},
+         {kChannelPSDName, channel.empty() ? "stable" : channel}});
   }
 
 #if BUILDFLAG(IS_CHROMEOS)
diff --git a/chrome/browser/ui/performance_controls/performance_controls_hats_service.h b/chrome/browser/ui/performance_controls/performance_controls_hats_service.h
index 55d185437..c9e8af2f 100644
--- a/chrome/browser/ui/performance_controls/performance_controls_hats_service.h
+++ b/chrome/browser/ui/performance_controls/performance_controls_hats_service.h
@@ -21,8 +21,13 @@
       public performance_manager::user_tuning::BatterySaverModeManager::
           Observer {
  public:
+  // Names of Product Specific Data bit entries.
   static constexpr char kBatterySaverPSDName[] = "Battery Saver Mode Enabled";
   static constexpr char kMemorySaverPSDName[] = "Memory Saver Mode Enabled";
+  static constexpr char kUniformSamplePSDName[] = "Selected for Uniform Sample";
+
+  // Names of Product Specific Data string entries.
+  static constexpr char kChannelPSDName[] = "Channel";
   static constexpr char kPerformanceSegmentPSDName[] =
       "Performance Characteristics (OS and Total Memory)";
 
diff --git a/chrome/browser/ui/performance_controls/performance_controls_hats_service_unittest.cc b/chrome/browser/ui/performance_controls/performance_controls_hats_service_unittest.cc
index cbacaf5..f0c69d1 100644
--- a/chrome/browser/ui/performance_controls/performance_controls_hats_service_unittest.cc
+++ b/chrome/browser/ui/performance_controls/performance_controls_hats_service_unittest.cc
@@ -33,14 +33,24 @@
 using performance_manager::features::kPerformanceControlsPPMSurveyMaxDelay;
 using performance_manager::features::kPerformanceControlsPPMSurveyMinDelay;
 using ::testing::_;
-using ::testing::ContainerEq;
+using ::testing::Pair;
+using ::testing::UnorderedElementsAre;
 
 const char* kBatterySaverPSDName =
     PerformanceControlsHatsService::kBatterySaverPSDName;
+const char* kChannelPSDName = PerformanceControlsHatsService::kChannelPSDName;
 const char* kMemorySaverPSDName =
     PerformanceControlsHatsService::kMemorySaverPSDName;
 const char* kPerformanceSegmentPSDName =
     PerformanceControlsHatsService::kPerformanceSegmentPSDName;
+const char* kUniformSamplePSDName =
+    PerformanceControlsHatsService::kUniformSamplePSDName;
+
+// GMock matcher for any expected "channel" string
+auto MatchesAnyChannel() {
+  // Channel can be "unknown" in some test configs.
+  return ::testing::AnyOf("canary", "dev", "beta", "stable", "unknown");
+}
 
 }  // namespace
 
@@ -269,7 +279,13 @@
 TEST_F(PerformanceControlsHatsServicePPMTest, LaunchesPPMSurveyAfterDelay) {
   EXPECT_CALL(
       *mock_hats_service(),
-      LaunchSurvey(kHatsSurveyTriggerPerformanceControlsPPM, _, _, _, _));
+      LaunchSurvey(
+          kHatsSurveyTriggerPerformanceControlsPPM, _, _,
+          UnorderedElementsAre(Pair(kMemorySaverPSDName, _),
+                               Pair(kBatterySaverPSDName, _),
+                               Pair(kUniformSamplePSDName, true)),
+          UnorderedElementsAre(Pair(kPerformanceSegmentPSDName, _),
+                               Pair(kChannelPSDName, MatchesAnyChannel()))));
   task_env().FastForwardBy(
       performance_controls_hats_service()->delay_before_ppm_survey());
   performance_controls_hats_service()->OpenedNewTabPage();
@@ -314,10 +330,15 @@
 };
 
 TEST_F(PerformanceControlsHatsServicePPM2SegmentTest, LowMemorySegment) {
-  EXPECT_CALL(*mock_hats_service(),
-              LaunchSurvey(kHatsSurveyTriggerPerformanceControlsPPM, _, _, _,
-                           ContainerEq(SurveyStringData{
-                               {kPerformanceSegmentPSDName, "Low Memory"}})));
+  EXPECT_CALL(
+      *mock_hats_service(),
+      LaunchSurvey(
+          kHatsSurveyTriggerPerformanceControlsPPM, _, _,
+          UnorderedElementsAre(Pair(kMemorySaverPSDName, _),
+                               Pair(kBatterySaverPSDName, _),
+                               Pair(kUniformSamplePSDName, true)),
+          UnorderedElementsAre(Pair(kPerformanceSegmentPSDName, "Low Memory"),
+                               Pair(kChannelPSDName, MatchesAnyChannel()))));
   performance_controls_hats_service()->SetAmountOfPhysicalMemoryMBForTesting(
       8192);
   task_env().FastForwardBy(
@@ -326,10 +347,15 @@
 }
 
 TEST_F(PerformanceControlsHatsServicePPM2SegmentTest, HighMemorySegment) {
-  EXPECT_CALL(*mock_hats_service(),
-              LaunchSurvey(kHatsSurveyTriggerPerformanceControlsPPM, _, _, _,
-                           ContainerEq(SurveyStringData{
-                               {kPerformanceSegmentPSDName, "High Memory"}})));
+  EXPECT_CALL(
+      *mock_hats_service(),
+      LaunchSurvey(
+          kHatsSurveyTriggerPerformanceControlsPPM, _, _,
+          UnorderedElementsAre(Pair(kMemorySaverPSDName, _),
+                               Pair(kBatterySaverPSDName, _),
+                               Pair(kUniformSamplePSDName, true)),
+          UnorderedElementsAre(Pair(kPerformanceSegmentPSDName, "High Memory"),
+                               Pair(kChannelPSDName, MatchesAnyChannel()))));
   performance_controls_hats_service()->SetAmountOfPhysicalMemoryMBForTesting(
       12288);
   task_env().FastForwardBy(
@@ -355,10 +381,15 @@
 };
 
 TEST_F(PerformanceControlsHatsServicePPM3SegmentTest, LowMemorySegment) {
-  EXPECT_CALL(*mock_hats_service(),
-              LaunchSurvey(kHatsSurveyTriggerPerformanceControlsPPM, _, _, _,
-                           ContainerEq(SurveyStringData{
-                               {kPerformanceSegmentPSDName, "Low Memory"}})));
+  EXPECT_CALL(
+      *mock_hats_service(),
+      LaunchSurvey(
+          kHatsSurveyTriggerPerformanceControlsPPM, _, _,
+          UnorderedElementsAre(Pair(kMemorySaverPSDName, _),
+                               Pair(kBatterySaverPSDName, _),
+                               Pair(kUniformSamplePSDName, true)),
+          UnorderedElementsAre(Pair(kPerformanceSegmentPSDName, "Low Memory"),
+                               Pair(kChannelPSDName, MatchesAnyChannel()))));
   performance_controls_hats_service()->SetAmountOfPhysicalMemoryMBForTesting(
       4096);
   task_env().FastForwardBy(
@@ -369,9 +400,13 @@
 TEST_F(PerformanceControlsHatsServicePPM3SegmentTest, MediumMemorySegment) {
   EXPECT_CALL(
       *mock_hats_service(),
-      LaunchSurvey(kHatsSurveyTriggerPerformanceControlsPPM, _, _, _,
-                   ContainerEq(SurveyStringData{
-                       {kPerformanceSegmentPSDName, "Medium Memory"}})));
+      LaunchSurvey(kHatsSurveyTriggerPerformanceControlsPPM, _, _,
+                   UnorderedElementsAre(Pair(kMemorySaverPSDName, _),
+                                        Pair(kBatterySaverPSDName, _),
+                                        Pair(kUniformSamplePSDName, true)),
+                   UnorderedElementsAre(
+                       Pair(kPerformanceSegmentPSDName, "Medium Memory"),
+                       Pair(kChannelPSDName, MatchesAnyChannel()))));
   performance_controls_hats_service()->SetAmountOfPhysicalMemoryMBForTesting(
       8192);
   task_env().FastForwardBy(
@@ -380,10 +415,15 @@
 }
 
 TEST_F(PerformanceControlsHatsServicePPM3SegmentTest, HighMemorySegment) {
-  EXPECT_CALL(*mock_hats_service(),
-              LaunchSurvey(kHatsSurveyTriggerPerformanceControlsPPM, _, _, _,
-                           ContainerEq(SurveyStringData{
-                               {kPerformanceSegmentPSDName, "High Memory"}})));
+  EXPECT_CALL(
+      *mock_hats_service(),
+      LaunchSurvey(
+          kHatsSurveyTriggerPerformanceControlsPPM, _, _,
+          UnorderedElementsAre(Pair(kMemorySaverPSDName, _),
+                               Pair(kBatterySaverPSDName, _),
+                               Pair(kUniformSamplePSDName, true)),
+          UnorderedElementsAre(Pair(kPerformanceSegmentPSDName, "High Memory"),
+                               Pair(kChannelPSDName, MatchesAnyChannel()))));
   performance_controls_hats_service()->SetAmountOfPhysicalMemoryMBForTesting(
       16384);
   task_env().FastForwardBy(
@@ -396,6 +436,9 @@
  protected:
   base::FieldTrialParams GetFieldTrialParams() const override {
     return {
+        // uniform_sample should be disabled before a segment is finished, since
+        // the weight of each segment no longer reflects the general population.
+        {"ppm_survey_uniform_sample", "false"},
         // <= 4 GB
         {"ppm_survey_segment_name1", "Low Memory"},
         {"ppm_survey_segment_max_memory_gb1", "4"},
@@ -409,10 +452,15 @@
 };
 
 TEST_F(PerformanceControlsHatsServicePPMFinishedSegmentTest, LowMemorySegment) {
-  EXPECT_CALL(*mock_hats_service(),
-              LaunchSurvey(kHatsSurveyTriggerPerformanceControlsPPM, _, _, _,
-                           ContainerEq(SurveyStringData{
-                               {kPerformanceSegmentPSDName, "Low Memory"}})));
+  EXPECT_CALL(
+      *mock_hats_service(),
+      LaunchSurvey(
+          kHatsSurveyTriggerPerformanceControlsPPM, _, _,
+          UnorderedElementsAre(Pair(kMemorySaverPSDName, _),
+                               Pair(kBatterySaverPSDName, _),
+                               Pair(kUniformSamplePSDName, false)),
+          UnorderedElementsAre(Pair(kPerformanceSegmentPSDName, "Low Memory"),
+                               Pair(kChannelPSDName, MatchesAnyChannel()))));
   performance_controls_hats_service()->SetAmountOfPhysicalMemoryMBForTesting(
       4096);
   task_env().FastForwardBy(
@@ -435,10 +483,15 @@
 
 TEST_F(PerformanceControlsHatsServicePPMFinishedSegmentTest,
        HighMemorySegment) {
-  EXPECT_CALL(*mock_hats_service(),
-              LaunchSurvey(kHatsSurveyTriggerPerformanceControlsPPM, _, _, _,
-                           ContainerEq(SurveyStringData{
-                               {kPerformanceSegmentPSDName, "High Memory"}})));
+  EXPECT_CALL(
+      *mock_hats_service(),
+      LaunchSurvey(
+          kHatsSurveyTriggerPerformanceControlsPPM, _, _,
+          UnorderedElementsAre(Pair(kMemorySaverPSDName, _),
+                               Pair(kBatterySaverPSDName, _),
+                               Pair(kUniformSamplePSDName, false)),
+          UnorderedElementsAre(Pair(kPerformanceSegmentPSDName, "High Memory"),
+                               Pair(kChannelPSDName, MatchesAnyChannel()))));
   performance_controls_hats_service()->SetAmountOfPhysicalMemoryMBForTesting(
       16384);
   task_env().FastForwardBy(
diff --git a/chrome/browser/ui/views/digital_credentials/digital_identity_integration_test.cc b/chrome/browser/ui/views/digital_credentials/digital_identity_integration_test.cc
index 90eb40cc..08c63ce 100644
--- a/chrome/browser/ui/views/digital_credentials/digital_identity_integration_test.cc
+++ b/chrome/browser/ui/views/digital_credentials/digital_identity_integration_test.cc
@@ -7,6 +7,7 @@
 
 #include "base/files/file_path.h"
 #include "base/functional/callback.h"
+#include "base/json/json_reader.h"
 #include "base/memory/weak_ptr.h"
 #include "base/run_loop.h"
 #include "base/test/scoped_feature_list.h"
@@ -60,8 +61,9 @@
 
     base::OnceClosure observer = std::move(credential_request_observer_);
     // Calling the callback might destroy `this`.
-    std::move(callback).Run(
-        DigitalCredential(/*protocol=*/std::nullopt, "token"));
+    std::move(callback).Run(DigitalCredential(
+        /*protocol=*/std::nullopt,
+        base::JSONReader::Read(R"({"token" : "test token"})")));
     if (observer) {
       std::move(observer).Run();
     }
diff --git a/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc b/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc
index a0ac0b13..96d9060 100644
--- a/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc
+++ b/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/platform_util.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/signin_promo_util.h"
 #include "chrome/browser/signin/signin_ui_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_navigator.h"
@@ -66,11 +67,11 @@
 
 std::unique_ptr<views::Label> CreateLabel(const std::u16string& text) {
   return views::Builder<views::Label>()
-    .SetText(text)
-    .SetHorizontalAlignment(gfx::ALIGN_LEFT)
-    .SetMultiLine(true)
-    .SizeToFit(GetRightColumnWidth())
-    .Build();
+      .SetText(text)
+      .SetHorizontalAlignment(gfx::ALIGN_LEFT)
+      .SetMultiLine(true)
+      .SizeToFit(GetRightColumnWidth())
+      .Build();
 }
 
 views::View* AnchorViewForBrowser(const ExtensionInstalledBubbleModel* model,
@@ -105,7 +106,7 @@
       web_contents, signin_metrics::AccessPoint::kExtensionInstallBubble,
       syncer::LocalDataItemModel::DataId(extension_id));
 }
-#endif
+#endif  // !BUILDFLAG(IS_CHROMEOS)
 
 }  // namespace
 
@@ -142,13 +143,6 @@
       browser_(browser),
       model_(std::move(model)) {
   SetButtons(static_cast<int>(ui::mojom::DialogButton::kNone));
-  if (model_->show_sign_in_promo()) {
-#if !BUILDFLAG(IS_CHROMEOS)
-    SetFootnoteView(CreateSigninPromoView(
-        browser->tab_strip_model()->GetActiveWebContents(),
-        model_->extension_id()));
-#endif
-  }
   SetIcon(ui::ImageModel::FromImageSkia(model_->MakeIconOfSize(kMaxIconSize)));
   SetShowIcon(true);
   SetShowCloseButton(true);
@@ -159,6 +153,23 @@
   base::i18n::AdjustStringForLocaleDirection(&extension_name);
   SetTitle(l10n_util::GetStringFUTF16(IDS_EXTENSION_INSTALLED_HEADING,
                                       extension_name));
+
+#if !BUILDFLAG(IS_CHROMEOS)
+  // Add a sync or sign in promo in the footer if it should be shown.
+  extensions::ExtensionRegistry* registry =
+      extensions::ExtensionRegistry::Get(browser->profile());
+  const extensions::Extension* extension =
+      registry->enabled_extensions().GetByID(model_->extension_id());
+
+  if (signin::ShouldShowExtensionSignInPromo(*browser->profile(), *extension) ||
+      (signin::ShouldShowExtensionSyncPromo(*browser->profile(), *extension) &&
+       !base::FeatureList::IsEnabled(
+           switches::kEnableExtensionsExplicitBrowserSignin))) {
+    SetFootnoteView(CreateSigninPromoView(
+        browser->tab_strip_model()->GetActiveWebContents(),
+        model_->extension_id()));
+  }
+#endif  // !BUILDFLAG(IS_CHROMEOS)
 }
 
 ExtensionInstalledBubbleView::~ExtensionInstalledBubbleView() = default;
diff --git a/chrome/browser/ui/views/extensions/extension_installed_bubble_view_signin_browsertest.cc b/chrome/browser/ui/views/extensions/extension_installed_bubble_view_signin_browsertest.cc
index 4fa13d1..0fc2e60 100644
--- a/chrome/browser/ui/views/extensions/extension_installed_bubble_view_signin_browsertest.cc
+++ b/chrome/browser/ui/views/extensions/extension_installed_bubble_view_signin_browsertest.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/extensions/extension_sync_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
+#include "chrome/browser/signin/signin_promo_util.h"
 #include "chrome/browser/ui/extensions/extension_install_ui_desktop.h"
 #include "chrome/browser/ui/signin/promos/bubble_signin_promo_delegate.h"
 #include "chrome/browser/ui/singleton_tabs.h"
@@ -93,8 +94,9 @@
       bubble_view_widget->widget_delegate());
   ASSERT_TRUE(view_delegate);
 
-  // The sign in promo should be shown for a syncable extension.
-  EXPECT_TRUE(view_delegate->model()->show_sign_in_promo());
+  // The sync promo should be shown for a syncable extension.
+  EXPECT_TRUE(
+      signin::ShouldShowExtensionSyncPromo(*browser()->profile(), *extension));
 
   // Simulate a user signing in from the promo. This should open up a new tab
   // with the sign in page.
@@ -145,7 +147,8 @@
     ASSERT_TRUE(view_delegate);
 
     // The sign in promo should be shown for a syncable extension.
-    EXPECT_TRUE(view_delegate->model()->show_sign_in_promo());
+    EXPECT_TRUE(signin::ShouldShowExtensionSignInPromo(*browser()->profile(),
+                                                       *extension));
 
     // Initiate a sign in from the promo.
     BubbleSignInPromoDelegate delegate(
diff --git a/chrome/browser/ui/webui/ash/settings/pages/people/account_manager_ui_handler_browsertest.cc b/chrome/browser/ui/webui/ash/settings/pages/people/account_manager_ui_handler_browsertest.cc
index 5360dcd7..41c8c0ba 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/people/account_manager_ui_handler_browsertest.cc
+++ b/chrome/browser/ui/webui/ash/settings/pages/people/account_manager_ui_handler_browsertest.cc
@@ -179,7 +179,7 @@
         GetDeviceAccountInfo().email, GaiaId(GetDeviceAccountInfo().id));
     const user_manager::User* user;
     {
-      user_manager::TestHelper test_helper(*user_manager::UserManager::Get());
+      user_manager::TestHelper test_helper(user_manager::UserManager::Get());
       if (GetDeviceAccountInfo().user_type == user_manager::UserType::kChild) {
         user = test_helper.AddChildUser(account_id);
       } else {
diff --git a/chrome/browser/ui/webui/chrome_web_ui_configs.cc b/chrome/browser/ui/webui/chrome_web_ui_configs.cc
index f688a2e..184e3a58 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_configs.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_configs.cc
@@ -140,6 +140,7 @@
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
 #include "chrome/browser/ui/webui/app_settings/web_app_settings_ui.h"
 #include "chrome/browser/ui/webui/browser_switch/browser_switch_ui.h"
+#include "chrome/browser/ui/webui/signin/history_sync_optin/history_sync_optin_ui.h"
 #include "chrome/browser/ui/webui/whats_new/whats_new_ui.h"
 #endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
 
@@ -349,9 +350,10 @@
 
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
   map.AddWebUIConfig(std::make_unique<BrowserSwitchUIConfig>());
+  map.AddWebUIConfig(std::make_unique<HistorySyncOptinUIConfig>());
+  map.AddWebUIConfig(std::make_unique<OnDeviceTranslationInternalsUIConfig>());
   map.AddWebUIConfig(std::make_unique<WebAppSettingsUIConfig>());
   map.AddWebUIConfig(std::make_unique<WhatsNewUIConfig>());
-  map.AddWebUIConfig(std::make_unique<OnDeviceTranslationInternalsUIConfig>());
 #endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
 
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
index 2fa37fe..b4dcb3a 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -1375,6 +1375,12 @@
        IDS_SETTINGS_AUTOFILL_AI_ACCESSIBILITY_LABEL_DAY_DROPDOWN},
       {"autofillAiAccessibilityLabelYearDropdown",
        IDS_SETTINGS_AUTOFILL_AI_ACCESSIBILITY_LABEL_YEAR_DROPDOWN},
+      {"autofillAiMonthDropdownNoOptionSelected",
+       IDS_SETTINGS_AUTOFILL_AI_MONTH_DROPDOWN_NO_OPTION_SELECTED},
+      {"autofillAiDayDropdownNoOptionSelected",
+       IDS_SETTINGS_AUTOFILL_AI_DAY_DROPDOWN_NO_OPTION_SELECTED},
+      {"autofillAiYearDropdownNoOptionSelected",
+       IDS_SETTINGS_AUTOFILL_AI_YEAR_DROPDOWN_NO_OPTION_SELECTED},
       {"autofillAiAddOrEditDialogDateValidationError",
        IDS_SETTINGS_AUTOFILL_AI_ADD_OR_EDIT_DIALOG_DATE_VALIDATION_ERROR},
       {"autofillAiAddOrEditDialogValidationError",
diff --git a/chrome/browser/ui/webui/signin/BUILD.gn b/chrome/browser/ui/webui/signin/BUILD.gn
index d35757e4..06abaee 100644
--- a/chrome/browser/ui/webui/signin/BUILD.gn
+++ b/chrome/browser/ui/webui/signin/BUILD.gn
@@ -122,6 +122,17 @@
       "//chrome/browser/ui/webui",
     ]
   }
+
+  if (is_win || is_mac || is_linux) {
+    sources += [
+      "history_sync_optin/history_sync_optin_handler.h",
+      "history_sync_optin/history_sync_optin_ui.h",
+    ]
+    public_deps += [
+      "history_sync_optin:mojo_bindings",
+      "//ui/webui",
+    ]
+  }
 }
 
 source_set("signin_impl") {
@@ -185,6 +196,16 @@
       "//ui/webui",
     ]
   }
+
+  if (is_win || is_mac || is_linux) {
+    sources += [
+      "history_sync_optin/history_sync_optin_handler.cc",
+      "history_sync_optin/history_sync_optin_ui.cc",
+    ]
+    deps += [
+      "//chrome/browser/resources/signin/history_sync_optin:resources_grit",
+    ]
+  }
 }
 
 source_set("login") {
diff --git a/chrome/browser/ui/webui/signin/history_sync_optin/BUILD.gn b/chrome/browser/ui/webui/signin/history_sync_optin/BUILD.gn
new file mode 100644
index 0000000..6602e2a
--- /dev/null
+++ b/chrome/browser/ui/webui/signin/history_sync_optin/BUILD.gn
@@ -0,0 +1,12 @@
+# Copyright 2025 The Chromium Authors
+# 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")
+
+assert(is_win || is_mac || is_linux)
+
+mojom("mojo_bindings") {
+  sources = [ "history_sync_optin.mojom" ]
+  webui_module_path = "/"
+}
diff --git a/chrome/browser/ui/webui/signin/history_sync_optin/OWNERS b/chrome/browser/ui/webui/signin/history_sync_optin/OWNERS
new file mode 100644
index 0000000..08850f4
--- /dev/null
+++ b/chrome/browser/ui/webui/signin/history_sync_optin/OWNERS
@@ -0,0 +1,2 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chrome/browser/ui/webui/signin/history_sync_optin/history_sync_optin.mojom b/chrome/browser/ui/webui/signin/history_sync_optin/history_sync_optin.mojom
new file mode 100644
index 0000000..a4ec78a
--- /dev/null
+++ b/chrome/browser/ui/webui/signin/history_sync_optin/history_sync_optin.mojom
@@ -0,0 +1,21 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module history_sync_optin.mojom;
+
+// Factory ensures that the Page and Handler interfaces
+// are always created together without requiring an initialization call from the
+// WebUI to the handler.
+interface PageHandlerFactory {
+  // Creates both the `page `and `handler` to be used for communication between
+  // the Browser and the Renderer.
+  CreateHistorySyncOptinHandler(
+      pending_remote<Page> page, pending_receiver<PageHandler> handler);
+};
+
+// Called from TS side of chrome://history-sync-optin (Renderer -> Browser)
+interface PageHandler {};
+
+// Called from C++ side of chrome://history-sync-optin (Browser -> Renderer)
+interface Page {};
diff --git a/chrome/browser/ui/webui/signin/history_sync_optin/history_sync_optin_handler.cc b/chrome/browser/ui/webui/signin/history_sync_optin/history_sync_optin_handler.cc
new file mode 100644
index 0000000..83667fcf
--- /dev/null
+++ b/chrome/browser/ui/webui/signin/history_sync_optin/history_sync_optin_handler.cc
@@ -0,0 +1,16 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/signin/history_sync_optin/history_sync_optin_handler.h"
+
+#include "base/functional/bind.h"
+#include "base/functional/callback_forward.h"
+#include "chrome/browser/ui/browser.h"
+
+HistorySyncOptinHandler::HistorySyncOptinHandler(
+    mojo::PendingReceiver<history_sync_optin::mojom::PageHandler> receiver,
+    mojo::PendingRemote<history_sync_optin::mojom::Page> page)
+    : receiver_(this, std::move(receiver)), page_(std::move(page)) {}
+
+HistorySyncOptinHandler::~HistorySyncOptinHandler() = default;
diff --git a/chrome/browser/ui/webui/signin/history_sync_optin/history_sync_optin_handler.h b/chrome/browser/ui/webui/signin/history_sync_optin/history_sync_optin_handler.h
new file mode 100644
index 0000000..c5f1f0e
--- /dev/null
+++ b/chrome/browser/ui/webui/signin/history_sync_optin/history_sync_optin_handler.h
@@ -0,0 +1,33 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_SIGNIN_HISTORY_SYNC_OPTIN_HISTORY_SYNC_OPTIN_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_SIGNIN_HISTORY_SYNC_OPTIN_HISTORY_SYNC_OPTIN_HANDLER_H_
+
+#include "base/functional/callback.h"
+#include "base/functional/callback_forward.h"
+#include "chrome/browser/ui/webui/signin/history_sync_optin/history_sync_optin.mojom.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
+
+class HistorySyncOptinHandler : public history_sync_optin::mojom::PageHandler {
+ public:
+  // Initializes the handler with the mojo handlers and the needed information
+  // to be displayed as well as callbacks to the main native view.
+  HistorySyncOptinHandler(
+      mojo::PendingReceiver<history_sync_optin::mojom::PageHandler> receiver,
+      mojo::PendingRemote<history_sync_optin::mojom::Page> page);
+  ~HistorySyncOptinHandler() override;
+
+  HistorySyncOptinHandler(const HistorySyncOptinHandler&) = delete;
+  HistorySyncOptinHandler& operator=(const HistorySyncOptinHandler&) = delete;
+
+ private:
+  // Allows handling received messages from the web ui page.
+  mojo::Receiver<history_sync_optin::mojom::PageHandler> receiver_;
+  // Interface to send information to the web ui page.
+  mojo::Remote<history_sync_optin::mojom::Page> page_;
+};
+
+#endif  // CHROME_BROWSER_UI_WEBUI_SIGNIN_HISTORY_SYNC_OPTIN_HISTORY_SYNC_OPTIN_HANDLER_H_
diff --git a/chrome/browser/ui/webui/signin/history_sync_optin/history_sync_optin_ui.cc b/chrome/browser/ui/webui/signin/history_sync_optin/history_sync_optin_ui.cc
new file mode 100644
index 0000000..7c31cb7
--- /dev/null
+++ b/chrome/browser/ui/webui/signin/history_sync_optin/history_sync_optin_ui.cc
@@ -0,0 +1,53 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/signin/history_sync_optin/history_sync_optin_ui.h"
+
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/webui/signin/history_sync_optin/history_sync_optin_handler.h"
+#include "chrome/common/webui_url_constants.h"
+#include "chrome/grit/signin_history_sync_optin_resources.h"
+#include "chrome/grit/signin_history_sync_optin_resources_map.h"
+#include "components/signin/public/base/signin_switches.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_ui.h"
+#include "content/public/browser/web_ui_data_source.h"
+#include "ui/webui/webui_util.h"
+
+bool HistorySyncOptinUIConfig::IsWebUIEnabled(
+    content::BrowserContext* browser_context) {
+  return base::FeatureList::IsEnabled(switches::kEnableHistorySyncOptin);
+}
+
+HistorySyncOptinUI::HistorySyncOptinUI(content::WebUI* web_ui)
+    : ui::MojoWebUIController(web_ui, true) {
+  // Set up the chrome://history-sync-optin source.
+  content::WebUIDataSource* source = content::WebUIDataSource::CreateAndAdd(
+      Profile::FromWebUI(web_ui), chrome::kChromeUIHistorySyncOptinHost);
+
+  // Add required resources.
+  webui::SetupWebUIDataSource(
+      source, base::span(kSigninHistorySyncOptinResources),
+      IDR_SIGNIN_HISTORY_SYNC_OPTIN_HISTORY_SYNC_OPTIN_HTML);
+}
+
+HistorySyncOptinUI::~HistorySyncOptinUI() = default;
+
+WEB_UI_CONTROLLER_TYPE_IMPL(HistorySyncOptinUI)
+
+void HistorySyncOptinUI::BindInterface(
+    mojo::PendingReceiver<history_sync_optin::mojom::PageHandlerFactory>
+        receiver) {
+  page_factory_receiver_.reset();
+  page_factory_receiver_.Bind(std::move(receiver));
+}
+
+void HistorySyncOptinUI::CreateHistorySyncOptinHandler(
+    mojo::PendingRemote<history_sync_optin::mojom::Page> page,
+    mojo::PendingReceiver<history_sync_optin::mojom::PageHandler> receiver) {
+  DCHECK(page);
+  page_handler_ = std::make_unique<HistorySyncOptinHandler>(std::move(receiver),
+                                                            std::move(page));
+}
diff --git a/chrome/browser/ui/webui/signin/history_sync_optin/history_sync_optin_ui.h b/chrome/browser/ui/webui/signin/history_sync_optin/history_sync_optin_ui.h
new file mode 100644
index 0000000..05d9fe6
--- /dev/null
+++ b/chrome/browser/ui/webui/signin/history_sync_optin/history_sync_optin_ui.h
@@ -0,0 +1,61 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_SIGNIN_HISTORY_SYNC_OPTIN_HISTORY_SYNC_OPTIN_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_SIGNIN_HISTORY_SYNC_OPTIN_HISTORY_SYNC_OPTIN_UI_H_
+
+#include "base/functional/callback.h"
+#include "chrome/browser/ui/webui/signin/history_sync_optin/history_sync_optin.mojom.h"
+#include "chrome/common/webui_url_constants.h"
+#include "content/public/browser/webui_config.h"
+#include "content/public/common/url_constants.h"
+#include "ui/webui/mojo_web_ui_controller.h"
+
+class HistorySyncOptinHandler;
+class HistorySyncOptinUI;
+
+class HistorySyncOptinUIConfig
+    : public content::DefaultWebUIConfig<HistorySyncOptinUI> {
+ public:
+  HistorySyncOptinUIConfig()
+      : DefaultWebUIConfig(content::kChromeUIScheme,
+                           chrome::kChromeUIHistorySyncOptinHost) {}
+
+  // content::WebUIConfig:
+  bool IsWebUIEnabled(content::BrowserContext* browser_context) override;
+};
+
+class HistorySyncOptinUI
+    : public ui::MojoWebUIController,
+      public history_sync_optin::mojom::PageHandlerFactory {
+ public:
+  explicit HistorySyncOptinUI(content::WebUI* web_ui);
+  ~HistorySyncOptinUI() override;
+
+  HistorySyncOptinUI(const HistorySyncOptinUI&) = delete;
+  HistorySyncOptinUI& operator=(const HistorySyncOptinUI&) = delete;
+
+  // Instantiates the implementor of the
+  // history_sync_optin::mojom::PageHandlerFactory mojo interface passing the
+  // pending receiver that will be internally bound.
+  void BindInterface(
+      mojo::PendingReceiver<history_sync_optin::mojom::PageHandlerFactory>
+          receiver);
+
+ private:
+  // history_sync_optin::mojom::PageHandlerFactory:
+  void CreateHistorySyncOptinHandler(
+      mojo::PendingRemote<history_sync_optin::mojom::Page> page,
+      mojo::PendingReceiver<history_sync_optin::mojom::PageHandler> receiver)
+      override;
+
+  std::unique_ptr<HistorySyncOptinHandler> page_handler_;
+
+  mojo::Receiver<history_sync_optin::mojom::PageHandlerFactory>
+      page_factory_receiver_{this};
+
+  WEB_UI_CONTROLLER_TYPE_DECL();
+};
+
+#endif  // CHROME_BROWSER_UI_WEBUI_SIGNIN_HISTORY_SYNC_OPTIN_HISTORY_SYNC_OPTIN_UI_H_
diff --git a/chrome/browser_exposed_mojom_targets.gni b/chrome/browser_exposed_mojom_targets.gni
index 430bca2..f0fccafa 100644
--- a/chrome/browser_exposed_mojom_targets.gni
+++ b/chrome/browser_exposed_mojom_targets.gni
@@ -45,6 +45,7 @@
   "//chrome/browser/ui/webui/side_panel/customize_chrome:mojo_bindings",
   "//chrome/browser/ui/webui/side_panel/reading_list:mojo_bindings",
   "//chrome/browser/ui/webui/signin/batch_upload:mojo_bindings",
+  "//chrome/browser/ui/webui/signin/history_sync_optin:mojo_bindings",
   "//chrome/browser/ui/webui/signin/signout_confirmation:mojo_bindings",
   "//chrome/browser/ui/webui/suggest_internals:mojo_bindings",
   "//chrome/browser/ui/webui/tab_search:mojo_bindings",
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt
index 7dc4cd4..b4499e6d 100644
--- a/chrome/build/android-arm32.pgo.txt
+++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@
-chrome-android32-main-1743119993-fda61bf0739c5b57ba23fd4101bc549b7e963549-12675a1bd6baf9e3dd5dc22e5648eed739ee9f8e.profdata
+chrome-android32-main-1743141430-a351944415b9638c5910cf7f12bead08688c89c6-c7d3961fea2dbe7f372a97af8e5a7983e2578923.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt
index e953ef6..4b2997da 100644
--- a/chrome/build/android-arm64.pgo.txt
+++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@
-chrome-android64-main-1743127723-09756b10b0373033d0ff88d9a42350352a980db2-c84dd4a9a98a46edd500f23a6ed08fa142318820.profdata
+chrome-android64-main-1743156228-75c38707a0631e3cca736dda2d02b02dc0ca1355-ba20f47a33f5b2dead1a3a99b47ffc4a57b496a2.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 0003168..93503a6 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1743127192-cb914a27442741f000fb4efaea6d331a130d930d-46e73fc3c7efc3045d2fe279d74b0e46a88e81d6.profdata
+chrome-mac-arm-main-1743155829-721e5a7e450249bb768848b6cf4d3ed1964fbc55-b38478b26702c0e587dbff78aea62059fdf1940b.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index d3472ac2..f8166a9 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1743119993-6cd1d3d3c8e9e3a7527293b5214a5d3398306fd1-12675a1bd6baf9e3dd5dc22e5648eed739ee9f8e.profdata
+chrome-mac-main-1743141430-01d488f71b08eb34afdeb9aa5fd1983ee28829c7-c7d3961fea2dbe7f372a97af8e5a7983e2578923.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt
index 783997c..bb18a3a 100644
--- a/chrome/build/win-arm64.pgo.txt
+++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@
-chrome-win-arm64-main-1743119993-6613d90a9315c94902f8445e0cafb503d505f015-12675a1bd6baf9e3dd5dc22e5648eed739ee9f8e.profdata
+chrome-win-arm64-main-1743141430-e3779677109599b10aa99f2c6dcea18022af6d94-c7d3961fea2dbe7f372a97af8e5a7983e2578923.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 95740523..c65c347 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1743098392-f0ffd2eb786d82b8a9f0952eadb93303b8d78b40-0037ffbe9f73bf38e6839fe513e7f804a1e8a88c.profdata
+chrome-win32-main-1743141430-0b5daf72362555863e596d43455d89d6149c5fce-c7d3961fea2dbe7f372a97af8e5a7983e2578923.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index a3195259..dfbb1d6e 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1743098392-43441f55d92d41e1751a243bf99c881fc64bdaee-0037ffbe9f73bf38e6839fe513e7f804a1e8a88c.profdata
+chrome-win64-main-1743141430-54754b30ff3e6af4da39624638e0f1da43e78bc4-c7d3961fea2dbe7f372a97af8e5a7983e2578923.profdata
diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni
index 1ce932b..f974169 100644
--- a/chrome/chrome_paks.gni
+++ b/chrome/chrome_paks.gni
@@ -528,6 +528,13 @@
       ]
     }
 
+    if (is_win || is_mac || is_linux) {
+      sources +=
+          [ "$root_gen_dir/chrome/signin_history_sync_optin_resources.pak" ]
+      deps +=
+          [ "//chrome/browser/resources/signin/history_sync_optin:resources" ]
+    }
+
     if (enable_dice_support) {
       sources += [
         "$root_gen_dir/chrome/batch_upload_resources.pak",
diff --git a/chrome/common/webui_url_constants.h b/chrome/common/webui_url_constants.h
index a71af2a..aa2c595 100644
--- a/chrome/common/webui_url_constants.h
+++ b/chrome/common/webui_url_constants.h
@@ -560,6 +560,9 @@
 inline constexpr char kChromeUIProfilePickerStartupQuery[] = "startup";
 inline constexpr char kChromeUIProfilePickerGlicQuery[] = "glic";
 inline constexpr char kChromeUIProfilePickerUrl[] = "chrome://profile-picker/";
+inline constexpr char kChromeUIHistorySyncOptinHost[] = "history-sync-optin";
+inline constexpr char kChromeUIHistorySyncOptinURL[] =
+    "chrome://history-sync-optin/";
 #endif
 
 #if ((BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && \
diff --git a/chrome/release_scripts b/chrome/release_scripts
index 68cf7f7..b1c7bf0 160000
--- a/chrome/release_scripts
+++ b/chrome/release_scripts
@@ -1 +1 @@
-Subproject commit 68cf7f7a742a11fd5cf852234ca7da522e5030cd
+Subproject commit b1c7bf06c3daeac7c9d718ae5d64d1a46ac002f4
diff --git a/chrome/test/data/android/dc_mdocs.html b/chrome/test/data/android/dc_mdocs.html
index 30730b1..37a3dd7f 100644
--- a/chrome/test/data/android/dc_mdocs.html
+++ b/chrome/test/data/android/dc_mdocs.html
@@ -23,7 +23,7 @@
         }]
       }
     });
-   const token = mdoc.data;
+   const token = mdoc.data.token;
    document.getElementById("log").textContent += `${token}`;
   }
 
@@ -59,7 +59,7 @@
           }
       }
     });
-   const token = response.data;
+   const token = response.data.token;
    document.getElementById("log").textContent += `${token}`;
   }
 
diff --git a/chrome/test/data/webui/settings/autofill_ai_add_or_edit_dialog_test.ts b/chrome/test/data/webui/settings/autofill_ai_add_or_edit_dialog_test.ts
index 1e8495b..9291ec73 100644
--- a/chrome/test/data/webui/settings/autofill_ai_add_or_edit_dialog_test.ts
+++ b/chrome/test/data/webui/settings/autofill_ai_add_or_edit_dialog_test.ts
@@ -502,9 +502,9 @@
           assertEquals('', monthSelect.value);
           assertEquals('', daySelect.value);
           assertEquals('', yearSelect.value);
-          assertTrue(monthSelect.textContent!.includes('Select'));
-          assertTrue(daySelect.textContent!.includes('Select'));
-          assertTrue(yearSelect.textContent!.includes('Select'));
+          assertTrue(monthSelect.textContent!.includes('MM'));
+          assertTrue(daySelect.textContent!.includes('DD'));
+          assertTrue(yearSelect.textContent!.includes('YYYY'));
         } else {
           assertEquals(oldDate.month, monthSelect.value);
           assertEquals(oldDate.day, daySelect.value);
diff --git a/chromeos/ash/experiences/arc/arc_util_unittest.cc b/chromeos/ash/experiences/arc/arc_util_unittest.cc
index e91cf6a..6dfbf40 100644
--- a/chromeos/ash/experiences/arc/arc_util_unittest.cc
+++ b/chromeos/ash/experiences/arc/arc_util_unittest.cc
@@ -341,7 +341,7 @@
       fake_user_manager->AddPublicAccountUser(AccountId::FromUserEmailGaiaId(
           "user3@test.com", GaiaId("1234567890-3")))));
   EXPECT_FALSE(IsArcAllowedForUser(
-      user_manager::TestHelper(*fake_user_manager)
+      user_manager::TestHelper(fake_user_manager.Get())
           .AddKioskAppUser("user4@kiosk-apps.device-local.localhost")));
   EXPECT_TRUE(IsArcAllowedForUser(fake_user_manager->AddGaiaUser(
       AccountId::FromUserEmailGaiaId("user5@test.com", GaiaId("1234567890-5")),
diff --git a/chromeos/ash/services/bluetooth_config/bluetooth_power_controller_impl_unittest.cc b/chromeos/ash/services/bluetooth_config/bluetooth_power_controller_impl_unittest.cc
index bdbd007..0d02bf7 100644
--- a/chromeos/ash/services/bluetooth_config/bluetooth_power_controller_impl_unittest.cc
+++ b/chromeos/ash/services/bluetooth_config/bluetooth_power_controller_impl_unittest.cc
@@ -71,7 +71,7 @@
                       bool is_new_profile = false) {
     const user_manager::User* user;
     if (is_user_kiosk) {
-      user = user_manager::TestHelper(*fake_user_manager_)
+      user = user_manager::TestHelper(fake_user_manager_.Get())
                  .AddKioskAppUser(display_email);
     } else {
       user = fake_user_manager_->AddGaiaUser(
diff --git a/chromeos/components/kiosk/kiosk_test_utils.cc b/chromeos/components/kiosk/kiosk_test_utils.cc
index 69a9e7c..3f5318a 100644
--- a/chromeos/components/kiosk/kiosk_test_utils.cc
+++ b/chromeos/components/kiosk/kiosk_test_utils.cc
@@ -18,7 +18,7 @@
       << "UserManager instance needs to be set up to start Kiosk session.";
 
   auto* user_manager = user_manager::UserManager::Get();
-  auto* user = user_manager::TestHelper(*user_manager).AddKioskAppUser(email);
+  auto* user = user_manager::TestHelper(user_manager).AddKioskAppUser(email);
   CHECK_EQ(user_manager->GetLoggedInUsers().size(), 0u);
   user_manager->UserLoggedIn(
       user->GetAccountId(),
diff --git a/chromeos/recorder_strings.grdp b/chromeos/recorder_strings.grdp
index 31c9602..de60a0e 100644
--- a/chromeos/recorder_strings.grdp
+++ b/chromeos/recorder_strings.grdp
@@ -45,7 +45,7 @@
     Good suggestion
   </message>
   <message desc="Disclaimer under generative AI features." name="IDS_RECORDER_GEN_AI_DISCLAIMER_TEXT">
-    Generative AI is experimental and content may be inaccurate, misleading, or offensive.
+    Generative AI can make mistakes, including about people, so double-check it.
   </message>
   <message desc="Status message for screen reader to update that the summary and title creation model fails to download. The [deviceType] will be replaced by an untranslatable product name." name="IDS_RECORDER_GEN_AI_DOWNLOAD_ERROR_STATUS_MESSAGE">
     Can't download model for summary and title creation. Try again or restart your <ph name="DEVICE_TYPE">[deviceType]</ph>.
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_GEN_AI_DISCLAIMER_TEXT.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_GEN_AI_DISCLAIMER_TEXT.png.sha1
index 688f5d4b..bac1778 100644
--- a/chromeos/recorder_strings_grdp/IDS_RECORDER_GEN_AI_DISCLAIMER_TEXT.png.sha1
+++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_GEN_AI_DISCLAIMER_TEXT.png.sha1
@@ -1 +1 @@
-69a562b50ccfeaa04e316a82ff57f11d4fcad092
\ No newline at end of file
+b07ef7d497cb90a6f25c7af83500f28b584b8127
\ No newline at end of file
diff --git a/clank b/clank
index 308cc67..98a170b 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit 308cc67f3ac6f1b4fdff05ecad102362b3821320
+Subproject commit 98a170bfb1752b85a4786f27a326a076c86344dd
diff --git a/components/affiliations/core/browser/BUILD.gn b/components/affiliations/core/browser/BUILD.gn
index 4d2fc28..f4fd98eb 100644
--- a/components/affiliations/core/browser/BUILD.gn
+++ b/components/affiliations/core/browser/BUILD.gn
@@ -34,7 +34,10 @@
     "affiliation_fetcher_factory.h",
     "affiliation_fetcher_factory_impl.cc",
     "affiliation_fetcher_factory_impl.h",
+    "affiliation_fetcher_interface.cc",
     "affiliation_fetcher_interface.h",
+    "affiliation_fetcher_manager.cc",
+    "affiliation_fetcher_manager.h",
     "affiliation_prefetcher.cc",
     "affiliation_prefetcher.h",
     "affiliation_service.h",
@@ -105,6 +108,7 @@
     "affiliation_backend_unittest.cc",
     "affiliation_database_unittest.cc",
     "affiliation_fetch_throttler_unittest.cc",
+    "affiliation_fetcher_manager_unittest.cc",
     "affiliation_prefetcher_unittest.cc",
     "affiliation_service_impl_unittest.cc",
     "affiliation_utils_unittest.cc",
diff --git a/components/affiliations/core/browser/affiliation_backend.cc b/components/affiliations/core/browser/affiliation_backend.cc
index d492776e..1caf4905 100644
--- a/components/affiliations/core/browser/affiliation_backend.cc
+++ b/components/affiliations/core/browser/affiliation_backend.cc
@@ -419,7 +419,8 @@
   // TODO(crbug.com/40858918): There is no need to request psl extension every
   // time, find a better way of caching it.
   fetcher_->StartRequest(requested_facet_uris,
-                         {.branding_info = true, .psl_extension_list = true});
+                         {.branding_info = true, .psl_extension_list = true},
+                         base::DoNothing());
   ReportStatistics(requested_facet_uris.size());
   return true;
 }
diff --git a/components/affiliations/core/browser/affiliation_fetcher_delegate.h b/components/affiliations/core/browser/affiliation_fetcher_delegate.h
index 21719acb..bc818912 100644
--- a/components/affiliations/core/browser/affiliation_fetcher_delegate.h
+++ b/components/affiliations/core/browser/affiliation_fetcher_delegate.h
@@ -25,6 +25,7 @@
     Result& operator=(const Result& other);
     Result& operator=(Result&& other);
     ~Result();
+    bool operator==(const Result& other) const = default;
 
     std::vector<AffiliatedFacets> affiliations;
     std::vector<GroupedFacets> groupings;
diff --git a/components/affiliations/core/browser/affiliation_fetcher_interface.cc b/components/affiliations/core/browser/affiliation_fetcher_interface.cc
new file mode 100644
index 0000000..bc825e1
--- /dev/null
+++ b/components/affiliations/core/browser/affiliation_fetcher_interface.cc
@@ -0,0 +1,25 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/affiliations/core/browser/affiliation_fetcher_interface.h"
+
+namespace affiliations {
+AffiliationFetcherInterface::FetchResult::FetchResult() = default;
+
+AffiliationFetcherInterface::FetchResult::FetchResult(
+    const FetchResult& other) = default;
+
+AffiliationFetcherInterface::FetchResult::FetchResult(FetchResult&& other) =
+    default;
+
+AffiliationFetcherInterface::FetchResult&
+AffiliationFetcherInterface::FetchResult::operator=(const FetchResult& other) =
+    default;
+
+AffiliationFetcherInterface::FetchResult&
+AffiliationFetcherInterface::FetchResult::operator=(FetchResult&& other) =
+    default;
+
+AffiliationFetcherInterface::FetchResult::~FetchResult() = default;
+}  // namespace affiliations
diff --git a/components/affiliations/core/browser/affiliation_fetcher_interface.h b/components/affiliations/core/browser/affiliation_fetcher_interface.h
index a78a2ab..93d5040 100644
--- a/components/affiliations/core/browser/affiliation_fetcher_interface.h
+++ b/components/affiliations/core/browser/affiliation_fetcher_interface.h
@@ -7,13 +7,28 @@
 
 #include <vector>
 
+#include "base/functional/callback_forward.h"
 #include "components/affiliations/core/browser/affiliation_fetcher_delegate.h"
 #include "components/affiliations/core/browser/affiliation_utils.h"
+#include "net/http/http_status_code.h"
 
 namespace affiliations {
 
 class AffiliationFetcherInterface {
  public:
+  using ParsedFetchResponse = AffiliationFetcherDelegate::Result;
+  struct FetchResult {
+    FetchResult();
+    FetchResult(const FetchResult& other);
+    FetchResult(FetchResult&& other);
+    FetchResult& operator=(const FetchResult& other);
+    FetchResult& operator=(FetchResult&& other);
+    ~FetchResult();
+
+    std::optional<ParsedFetchResponse> data;
+    int network_status;
+    std::optional<net::HttpStatusCode> http_status_code;
+  };
   // A struct that enables to set Affiliation Fetcher request mask.
   struct RequestInfo {
     bool branding_info = false;
@@ -35,8 +50,12 @@
 
   // Starts the request to retrieve affiliations for each facet in
   // |facet_uris|.
-  virtual void StartRequest(const std::vector<FacetURI>& facet_uris,
-                            RequestInfo request_info) = 0;
+  // This will run |result_callback| on a successful or a failed fetch,
+  // including if the fetcher had been destroyed before its fetch finished.
+  virtual void StartRequest(
+      const std::vector<FacetURI>& facet_uris,
+      RequestInfo request_info,
+      base::OnceCallback<void(FetchResult)> result_callback) = 0;
 
   // Returns requested facet uris.
   virtual const std::vector<FacetURI>& GetRequestedFacetURIs() const = 0;
diff --git a/components/affiliations/core/browser/affiliation_fetcher_manager.cc b/components/affiliations/core/browser/affiliation_fetcher_manager.cc
new file mode 100644
index 0000000..1f86d729ec
--- /dev/null
+++ b/components/affiliations/core/browser/affiliation_fetcher_manager.cc
@@ -0,0 +1,72 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/affiliations/core/browser/affiliation_fetcher_manager.h"
+
+#include <memory>
+
+#include "base/containers/span.h"
+#include "base/functional/callback.h"
+#include "base/functional/callback_forward.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "components/affiliations/core/browser/affiliation_fetcher_factory_impl.h"
+#include "components/affiliations/core/browser/affiliation_fetcher_interface.h"
+#include "components/affiliations/core/browser/affiliation_utils.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+
+namespace affiliations {
+
+AffiliationFetcherManager::AffiliationFetcherManager(
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+    AffiliationFetcherDelegate* delegate)
+    : url_loader_factory_(url_loader_factory),
+      fetcher_factory_(std::make_unique<AffiliationFetcherFactoryImpl>()),
+      delegate_(delegate) {}
+
+AffiliationFetcherManager::~AffiliationFetcherManager() = default;
+
+bool AffiliationFetcherManager::Fetch(
+    const std::vector<FacetURI>& facet_uris,
+    AffiliationFetcherInterface::RequestInfo request_info,
+    base::OnceCallback<void(AffiliationFetcherInterface::FetchResult)>
+        completion_callback) {
+  std::unique_ptr<AffiliationFetcherInterface> fetcher =
+      fetcher_factory_->CreateInstance(url_loader_factory_, delegate_);
+  if (!fetcher) {
+    std::move(completion_callback)
+        .Run(AffiliationFetcherInterface::FetchResult());
+    return false;
+  }
+
+  auto cleanup_callback =
+      std::move(completion_callback)
+          .Then(base::BindOnce(&AffiliationFetcherManager::CleanUpFetcher,
+                               weak_ptr_factory_.GetWeakPtr(), fetcher.get()));
+  fetcher->StartRequest(facet_uris, request_info, std::move(cleanup_callback));
+  fetchers_.push_back(std::move(fetcher));
+  return true;
+}
+
+void AffiliationFetcherManager::CleanUpFetcher(
+    AffiliationFetcherInterface* fetcher) {
+  auto fetcher_it = std::find_if(fetchers_.begin(), fetchers_.end(),
+                                 [fetcher](const auto& stored_fetcher) {
+                                   return stored_fetcher.get() == fetcher;
+                                 });
+  if (fetcher_it != fetchers_.end()) {
+    fetchers_.erase(fetcher_it);
+  }
+}
+
+std::vector<FacetURI> AffiliationFetcherManager::GetRequestedFacetURIs() const {
+  std::vector<FacetURI> requested_facet_uris;
+  for (const auto& fetcher : fetchers_) {
+    auto facets = fetcher->GetRequestedFacetURIs();
+    requested_facet_uris.insert(requested_facet_uris.end(), facets.begin(),
+                                facets.end());
+  }
+  return requested_facet_uris;
+}
+}  // namespace affiliations
diff --git a/components/affiliations/core/browser/affiliation_fetcher_manager.h b/components/affiliations/core/browser/affiliation_fetcher_manager.h
new file mode 100644
index 0000000..70671926
--- /dev/null
+++ b/components/affiliations/core/browser/affiliation_fetcher_manager.h
@@ -0,0 +1,73 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AFFILIATIONS_CORE_BROWSER_AFFILIATION_FETCHER_MANAGER_H_
+#define COMPONENTS_AFFILIATIONS_CORE_BROWSER_AFFILIATION_FETCHER_MANAGER_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/functional/callback.h"
+#include "base/functional/callback_forward.h"
+#include "base/memory/ref_counted.h"
+#include "components/affiliations/core/browser/affiliation_fetcher_delegate.h"
+#include "components/affiliations/core/browser/affiliation_fetcher_factory.h"
+#include "components/affiliations/core/browser/affiliation_fetcher_interface.h"
+#include "components/affiliations/core/browser/affiliation_utils.h"
+
+namespace affiliations {
+// Class for managing instances of |AffiliationFetcherInterface| created for
+// individual requests. Each fetcher will live between a call to |Fetch| and a
+// completion of the started fetch.
+class AffiliationFetcherManager {
+ public:
+  AffiliationFetcherManager(
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+      AffiliationFetcherDelegate* delegate);
+  AffiliationFetcherManager(const AffiliationFetcherManager&) = delete;
+  AffiliationFetcherManager& operator=(const AffiliationFetcherManager&) =
+      delete;
+  ~AffiliationFetcherManager();
+
+  // Starts a fetch for the given facet_uris and request_info.
+  // Returns true if the fetch was started and false if the fetch is not
+  // possible, e.g. because the required API keys are not available. See
+  // |HashAffiliationFetcher::IsFetchPossible| for details. Internally this will
+  // create a new |AffiliationFetcherInterface|, store it in |fetchers_| and
+  // clean in up once the fetch is completed.
+  bool Fetch(const std::vector<FacetURI>& facet_uris,
+             AffiliationFetcherInterface::RequestInfo request_info,
+             base::OnceCallback<void(AffiliationFetcherInterface::FetchResult)>
+                 completion_callback);
+
+  // Returns all the |FacetURI|s that are currently being fetched.
+  std::vector<FacetURI> GetRequestedFacetURIs() const;
+
+#if defined(UNIT_TEST)
+  // Only for use in tests.
+  std::vector<std::unique_ptr<AffiliationFetcherInterface>>*
+  GetFetchersForTesting() {
+    return &fetchers_;
+  }
+
+  void SetFetcherFactoryForTesting(
+      std::unique_ptr<AffiliationFetcherFactory> fetcher_factory) {
+    fetcher_factory_ = std::move(fetcher_factory);
+  }
+#endif
+
+ private:
+  // Erases |fetcher| from |fetchers_| after receiving the result and forwards
+  // the result to the caller of |Fetch|.
+  void CleanUpFetcher(AffiliationFetcherInterface* fetcher);
+
+  std::vector<std::unique_ptr<AffiliationFetcherInterface>> fetchers_;
+  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
+  std::unique_ptr<AffiliationFetcherFactory> fetcher_factory_;
+  raw_ptr<AffiliationFetcherDelegate> delegate_;
+
+  base::WeakPtrFactory<AffiliationFetcherManager> weak_ptr_factory_{this};
+};
+}  // namespace affiliations
+#endif  // COMPONENTS_AFFILIATIONS_CORE_BROWSER_AFFILIATION_FETCHER_MANAGER_H_
diff --git a/components/affiliations/core/browser/affiliation_fetcher_manager_unittest.cc b/components/affiliations/core/browser/affiliation_fetcher_manager_unittest.cc
new file mode 100644
index 0000000..05012067
--- /dev/null
+++ b/components/affiliations/core/browser/affiliation_fetcher_manager_unittest.cc
@@ -0,0 +1,426 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/affiliations/core/browser/affiliation_fetcher_manager.h"
+
+#include <stddef.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/functional/bind.h"
+#include "base/functional/callback.h"
+#include "base/functional/callback_helpers.h"
+#include "base/test/gmock_move_support.h"
+#include "base/test/task_environment.h"
+#include "base/test/test_future.h"
+#include "components/affiliations/core/browser/affiliation_api.pb.h"
+#include "components/affiliations/core/browser/affiliation_fetcher_delegate.h"
+#include "components/affiliations/core/browser/affiliation_fetcher_factory_impl.h"
+#include "components/affiliations/core/browser/fake_affiliation_api.h"
+#include "components/affiliations/core/browser/hash_affiliation_fetcher.h"
+#include "components/affiliations/core/browser/mock_affiliation_fetcher_delegate.h"
+#include "components/variations/scoped_variations_ids_provider.h"
+#include "net/base/net_errors.h"
+#include "net/http/http_status_code.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace affiliations {
+
+namespace {
+constexpr char kNotExampleAndroidFacetURI[] =
+    "android://hash1234@com.example.not";
+constexpr char kNotExampleWebFacetURI[] = "https://not.example.com";
+constexpr char kExampleWebFacet1URI[] = "https://www.example.com";
+constexpr char kExampleWebFacet2URI[] = "https://www.example.org";
+constexpr char kExampleAndroidFacetURI[] = "android://hash@com.example";
+constexpr AffiliationFetcherInterface::RequestInfo kRequestInfo{
+    .branding_info = true,
+    .change_password_info = true};
+
+// Fetcher factory that will create |HashAffiliationFetcher| but avoid checking
+// API keys since they aren't always available in unit tests. Instead, to test
+// failed fetcher creation, this class allows setting a bool that will disallow
+// fetcher creation.
+class KeylessFetcherFactory : public AffiliationFetcherFactory {
+ public:
+  KeylessFetcherFactory();
+  ~KeylessFetcherFactory() override;
+
+  std::unique_ptr<AffiliationFetcherInterface> CreateInstance(
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+      AffiliationFetcherDelegate* delegate) override;
+
+  void SetCanCreateFetcher(bool can_create_fetcher) {
+    can_create_fetcher_ = can_create_fetcher;
+  }
+
+ private:
+  bool can_create_fetcher_ = true;
+};
+
+KeylessFetcherFactory::KeylessFetcherFactory() = default;
+KeylessFetcherFactory::~KeylessFetcherFactory() = default;
+
+std::unique_ptr<AffiliationFetcherInterface>
+KeylessFetcherFactory::CreateInstance(
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+    AffiliationFetcherDelegate* delegate) {
+  if (can_create_fetcher_) {
+    return std::make_unique<HashAffiliationFetcher>(
+        std::move(url_loader_factory), delegate);
+  }
+  return nullptr;
+}
+}  // namespace
+
+class AffiliationFetcherManagerTest : public testing::Test {
+ public:
+  AffiliationFetcherManagerTest() = default;
+
+ protected:
+  MockAffiliationFetcherDelegate* mock_delegate() { return &mock_delegate_; }
+
+  GURL interception_url() const {
+    return HashAffiliationFetcher::BuildQueryURL();
+  }
+
+  // Setup a complex response from Affiliation Server to make sure it is passed
+  // down to |AffiliationFetcherManager|.
+  std::string GetSuccessfulAffiliationResponse() const {
+    affiliation_pb::LookupAffiliationByHashPrefixResponse test_response;
+    affiliation_pb::Affiliation* eq_class1 = test_response.add_affiliations();
+    eq_class1->add_facet()->set_id(kExampleWebFacet1URI);
+    eq_class1->add_facet()->set_id(kExampleWebFacet2URI);
+    eq_class1->add_facet()->set_id(kExampleAndroidFacetURI);
+    affiliation_pb::Affiliation* eq_class2 = test_response.add_affiliations();
+    eq_class2->add_facet()->set_id(kNotExampleWebFacetURI);
+    eq_class2->add_facet()->set_id(kNotExampleAndroidFacetURI);
+
+    return test_response.SerializeAsString();
+  }
+
+  void SetupSuccessfulResponse(const std::string& response) {
+    test_url_loader_factory_.ClearResponses();
+    test_url_loader_factory_.AddResponse(interception_url().spec(), response,
+                                         net::HTTP_OK);
+  }
+
+  void SetupServerErrorResponse() {
+    test_url_loader_factory_.ClearResponses();
+    test_url_loader_factory_.AddResponse(interception_url().spec(), "",
+                                         net::HTTP_INTERNAL_SERVER_ERROR);
+  }
+
+  int GetNumPendingRequests() { return test_url_loader_factory_.NumPending(); }
+
+  AffiliationFetcherManager* manager() { return manager_.get(); }
+
+  void DisallowFetcherCreation() {
+    keyless_fetcher_factory_->SetCanCreateFetcher(false);
+  }
+
+  void DestroyManager() {
+    keyless_fetcher_factory_ = nullptr;
+    manager_.reset();
+  }
+
+ private:
+  // testing::Test:
+  void SetUp() override {
+    manager_ = std::make_unique<AffiliationFetcherManager>(
+        test_shared_loader_factory_, &mock_delegate_);
+    auto fetcher_factory = std::make_unique<KeylessFetcherFactory>();
+    keyless_fetcher_factory_ = fetcher_factory.get();
+
+    manager_->SetFetcherFactoryForTesting(std::move(fetcher_factory));
+  }
+
+  base::test::SingleThreadTaskEnvironment task_environment_;
+  variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{
+      variations::VariationsIdsProvider::Mode::kUseSignedInState};
+
+  network::TestURLLoaderFactory test_url_loader_factory_;
+  scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_ =
+      base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+          &test_url_loader_factory_);
+  MockAffiliationFetcherDelegate mock_delegate_;
+  std::unique_ptr<AffiliationFetcherManager> manager_;
+  // Owned by |manager_|.
+  raw_ptr<KeylessFetcherFactory> keyless_fetcher_factory_ = nullptr;
+};
+
+TEST_F(AffiliationFetcherManagerTest, OneFetchCallCreatesOneFetcher) {
+  std::vector<FacetURI> requested_uris;
+  requested_uris.push_back(FacetURI::FromCanonicalSpec(kExampleWebFacet1URI));
+  requested_uris.push_back(
+      FacetURI::FromCanonicalSpec(kNotExampleAndroidFacetURI));
+
+  bool fetch_started =
+      manager()->Fetch(requested_uris, kRequestInfo, base::DoNothing());
+
+  EXPECT_TRUE(fetch_started);
+  EXPECT_EQ(1u, manager()->GetFetchersForTesting()->size());
+  EXPECT_EQ(1, GetNumPendingRequests());
+}
+
+TEST_F(AffiliationFetcherManagerTest,
+       MultipleFetchCallsCreateMultipleFetchers) {
+  std::vector<FacetURI> requested_uris;
+  requested_uris.push_back(FacetURI::FromCanonicalSpec(kExampleWebFacet1URI));
+  requested_uris.push_back(
+      FacetURI::FromCanonicalSpec(kNotExampleAndroidFacetURI));
+
+  bool fetch_started_1 =
+      manager()->Fetch(requested_uris, kRequestInfo, base::DoNothing());
+  bool fetch_started_2 =
+      manager()->Fetch(requested_uris, kRequestInfo, base::DoNothing());
+  bool fetch_started_3 =
+      manager()->Fetch(requested_uris, kRequestInfo, base::DoNothing());
+
+  EXPECT_TRUE(fetch_started_1);
+  EXPECT_TRUE(fetch_started_2);
+  EXPECT_TRUE(fetch_started_3);
+  EXPECT_EQ(3u, manager()->GetFetchersForTesting()->size());
+  EXPECT_EQ(3, GetNumPendingRequests());
+}
+
+TEST_F(AffiliationFetcherManagerTest,
+       ImmediatelyInvokeCallbackIfFetcherCreationFailed) {
+  std::vector<FacetURI> requested_uris;
+  requested_uris.push_back(FacetURI::FromCanonicalSpec(kExampleWebFacet1URI));
+  requested_uris.push_back(
+      FacetURI::FromCanonicalSpec(kNotExampleAndroidFacetURI));
+  base::test::TestFuture<HashAffiliationFetcher::FetchResult>
+      completion_callback;
+  DisallowFetcherCreation();
+
+  bool fetch_started = manager()->Fetch(requested_uris, kRequestInfo,
+                                        completion_callback.GetCallback());
+
+  EXPECT_FALSE(fetch_started);
+  EXPECT_EQ(0u, manager()->GetFetchersForTesting()->size());
+  EXPECT_EQ(0, GetNumPendingRequests());
+  EXPECT_TRUE(completion_callback.IsReady());
+}
+
+TEST_F(AffiliationFetcherManagerTest,
+       CompletionClosureInvokedOnFetchCompletion) {
+  std::vector<FacetURI> requested_uris;
+  requested_uris.push_back(FacetURI::FromCanonicalSpec(kExampleWebFacet1URI));
+  requested_uris.push_back(
+      FacetURI::FromCanonicalSpec(kNotExampleAndroidFacetURI));
+  base::test::TestFuture<HashAffiliationFetcher::FetchResult>
+      completion_callback;
+
+  bool fetch_started = manager()->Fetch(requested_uris, kRequestInfo,
+                                        completion_callback.GetCallback());
+  SetupSuccessfulResponse(GetSuccessfulAffiliationResponse());
+
+  ASSERT_TRUE(fetch_started);
+  EXPECT_EQ(0, GetNumPendingRequests());
+  EXPECT_TRUE(completion_callback.Take().data);
+  EXPECT_EQ(0u, manager()->GetFetchersForTesting()->size());
+}
+
+TEST_F(AffiliationFetcherManagerTest,
+       CompletionClosureInvokedOnMultipleFetchCompletions) {
+  std::vector<FacetURI> requested_uris;
+  requested_uris.push_back(FacetURI::FromCanonicalSpec(kExampleWebFacet1URI));
+  requested_uris.push_back(
+      FacetURI::FromCanonicalSpec(kNotExampleAndroidFacetURI));
+  base::test::TestFuture<HashAffiliationFetcher::FetchResult>
+      completion_callback_1;
+  base::test::TestFuture<HashAffiliationFetcher::FetchResult>
+      completion_callback_2;
+  base::test::TestFuture<HashAffiliationFetcher::FetchResult>
+      completion_callback_3;
+
+  bool fetch_started_1 = manager()->Fetch(requested_uris, kRequestInfo,
+                                          completion_callback_1.GetCallback());
+  bool fetch_started_2 = manager()->Fetch(requested_uris, kRequestInfo,
+                                          completion_callback_2.GetCallback());
+  bool fetch_started_3 = manager()->Fetch(requested_uris, kRequestInfo,
+                                          completion_callback_3.GetCallback());
+  // All requests have the same URL, so this will serve all of them
+  SetupSuccessfulResponse(GetSuccessfulAffiliationResponse());
+
+  ASSERT_TRUE(fetch_started_1);
+  ASSERT_TRUE(fetch_started_2);
+  ASSERT_TRUE(fetch_started_3);
+  EXPECT_EQ(0, GetNumPendingRequests());
+  EXPECT_TRUE(completion_callback_1.Take().data);
+  EXPECT_TRUE(completion_callback_2.Take().data);
+  EXPECT_TRUE(completion_callback_3.Take().data);
+  EXPECT_EQ(0u, manager()->GetFetchersForTesting()->size());
+}
+
+// This test mimics |HashAffiliationFetcherTest::BasicRequestAndResponse| to
+// makes sure that the response from |HashAffiliationFetcher| is passed down to
+// |AffiliationFetcherManger|.
+TEST_F(AffiliationFetcherManagerTest, DelegateInvokedOnFetchSuccess) {
+  std::vector<FacetURI> requested_uris;
+  requested_uris.push_back(FacetURI::FromCanonicalSpec(kExampleWebFacet1URI));
+  requested_uris.push_back(
+      FacetURI::FromCanonicalSpec(kNotExampleAndroidFacetURI));
+  base::test::TestFuture<HashAffiliationFetcher::FetchResult>
+      completion_callback;
+  std::unique_ptr<AffiliationFetcherDelegate::Result> result_for_delegate;
+  EXPECT_CALL(*mock_delegate(), OnFetchSucceeded)
+      .WillOnce(MoveArg<1>(&result_for_delegate));
+  SetupSuccessfulResponse(GetSuccessfulAffiliationResponse());
+
+  bool fetch_started = manager()->Fetch(requested_uris, kRequestInfo,
+                                        completion_callback.GetCallback());
+
+  ASSERT_TRUE(fetch_started);
+  EXPECT_EQ(0, GetNumPendingRequests());
+  EXPECT_TRUE(result_for_delegate);
+  ASSERT_EQ(2u, result_for_delegate->affiliations.size());
+  EXPECT_THAT(result_for_delegate->affiliations[0],
+              testing::UnorderedElementsAre(
+                  Facet{FacetURI::FromCanonicalSpec(kExampleWebFacet1URI)},
+                  Facet{FacetURI::FromCanonicalSpec(kExampleWebFacet2URI)},
+                  Facet{FacetURI::FromCanonicalSpec(kExampleAndroidFacetURI)}));
+  EXPECT_THAT(
+      result_for_delegate->affiliations[1],
+      testing::UnorderedElementsAre(
+          Facet{FacetURI::FromCanonicalSpec(kNotExampleWebFacetURI)},
+          Facet{FacetURI::FromCanonicalSpec(kNotExampleAndroidFacetURI)}));
+  // Confirm that the result passed to delegate is the same as the one in the
+  // callback.
+  auto affiliation_response = completion_callback.Take().data;
+  EXPECT_EQ(affiliation_response, *result_for_delegate);
+  EXPECT_EQ(0u, manager()->GetFetchersForTesting()->size());
+}
+
+TEST_F(AffiliationFetcherManagerTest, DelegateInvokedOnFetchFailed) {
+  std::vector<FacetURI> requested_uris;
+  requested_uris.push_back(FacetURI::FromCanonicalSpec(kExampleWebFacet1URI));
+  requested_uris.push_back(
+      FacetURI::FromCanonicalSpec(kNotExampleAndroidFacetURI));
+  base::test::TestFuture<HashAffiliationFetcher::FetchResult>
+      completion_callback;
+  EXPECT_CALL(*mock_delegate(), OnFetchFailed(testing::_));
+  SetupServerErrorResponse();
+
+  bool fetch_started = manager()->Fetch(requested_uris, kRequestInfo,
+                                        completion_callback.GetCallback());
+
+  ASSERT_TRUE(fetch_started);
+  EXPECT_EQ(0, GetNumPendingRequests());
+  EXPECT_TRUE(completion_callback.IsReady());
+  EXPECT_EQ(0u, manager()->GetFetchersForTesting()->size());
+}
+
+TEST_F(AffiliationFetcherManagerTest, DelegateInvokedOnMalformedResponse) {
+  std::vector<FacetURI> requested_uris;
+  requested_uris.push_back(FacetURI::FromCanonicalSpec(kExampleWebFacet1URI));
+  requested_uris.push_back(
+      FacetURI::FromCanonicalSpec(kNotExampleAndroidFacetURI));
+  base::test::TestFuture<HashAffiliationFetcher::FetchResult>
+      completion_callback;
+  EXPECT_CALL(*mock_delegate(), OnMalformedResponse(testing::_));
+  SetupSuccessfulResponse("gibberish");
+
+  bool fetch_started = manager()->Fetch(requested_uris, kRequestInfo,
+                                        completion_callback.GetCallback());
+
+  ASSERT_TRUE(fetch_started);
+  EXPECT_EQ(0, GetNumPendingRequests());
+  EXPECT_TRUE(completion_callback.IsReady());
+  EXPECT_EQ(0u, manager()->GetFetchersForTesting()->size());
+}
+
+// The structure of this test is awkward because:
+//  1. It uses mock delegate, meaning the EXPECT_CALL has to be called before
+//  serving the responses. It would be better to implement a fake delegate but
+//  it would be even better to move the delegate logic in the completion
+//  callback.
+//  2. |TestURLLoaderFactory| seeds responses per URL, not per ResourceRequest.
+//  Since all URLs that we request are the same, we can't seed different
+//  responses for different requests. In this test we seed and serve the
+//  responses one-by-one to work around this, which is not perfect.
+// However the test case is still valuable to check that consecutive calls can
+// produce different results.
+TEST_F(AffiliationFetcherManagerTest, DelegateInvokedOnAllPossibleResponses) {
+  std::vector<FacetURI> requested_uris;
+  requested_uris.push_back(FacetURI::FromCanonicalSpec(kExampleWebFacet1URI));
+  requested_uris.push_back(
+      FacetURI::FromCanonicalSpec(kNotExampleAndroidFacetURI));
+  base::test::TestFuture<HashAffiliationFetcher::FetchResult>
+      completion_callback_1;
+  base::test::TestFuture<HashAffiliationFetcher::FetchResult>
+      completion_callback_2;
+  base::test::TestFuture<HashAffiliationFetcher::FetchResult>
+      completion_callback_3;
+
+  // Successful response
+  EXPECT_CALL(*mock_delegate(), OnFetchSucceeded(testing::_, testing::_));
+  SetupSuccessfulResponse(GetSuccessfulAffiliationResponse());
+  bool fetch_started_1 = manager()->Fetch(requested_uris, kRequestInfo,
+                                          completion_callback_1.GetCallback());
+  // Failing response
+  EXPECT_CALL(*mock_delegate(), OnFetchFailed(testing::_));
+  SetupServerErrorResponse();
+  bool fetch_started_2 = manager()->Fetch(requested_uris, kRequestInfo,
+                                          completion_callback_2.GetCallback());
+  // Malformed response
+  EXPECT_CALL(*mock_delegate(), OnMalformedResponse(testing::_));
+  SetupSuccessfulResponse("gibberish");
+  bool fetch_started_3 = manager()->Fetch(requested_uris, kRequestInfo,
+                                          completion_callback_3.GetCallback());
+
+  ASSERT_TRUE(fetch_started_1);
+  ASSERT_TRUE(fetch_started_2);
+  ASSERT_TRUE(fetch_started_3);
+  EXPECT_EQ(0, GetNumPendingRequests());
+  EXPECT_EQ(0u, manager()->GetFetchersForTesting()->size());
+  // First response
+  auto result_1 = completion_callback_1.Take().data;
+  ASSERT_TRUE(result_1);
+  EXPECT_EQ(2u, result_1->affiliations.size());
+  // Second response
+  auto result_2 = completion_callback_2.Take();
+  EXPECT_FALSE(result_2.data);
+  EXPECT_EQ(net::HTTP_INTERNAL_SERVER_ERROR, result_2.http_status_code);
+  // Third response
+  auto result_3 = completion_callback_3.Take();
+  EXPECT_FALSE(result_3.data);
+  EXPECT_EQ(net::HTTP_OK, result_3.http_status_code);
+  EXPECT_EQ(0, result_3.network_status);
+}
+
+TEST_F(AffiliationFetcherManagerTest, CallbackIsCalledOnManagerDestruction) {
+  std::vector<FacetURI> requested_uris;
+  requested_uris.push_back(FacetURI::FromCanonicalSpec(kExampleWebFacet1URI));
+  requested_uris.push_back(
+      FacetURI::FromCanonicalSpec(kNotExampleAndroidFacetURI));
+  base::test::TestFuture<HashAffiliationFetcher::FetchResult>
+      completion_callback_1;
+  base::test::TestFuture<HashAffiliationFetcher::FetchResult>
+      completion_callback_2;
+  base::test::TestFuture<HashAffiliationFetcher::FetchResult>
+      completion_callback_3;
+
+  bool fetch_started_1 = manager()->Fetch(requested_uris, kRequestInfo,
+                                          completion_callback_1.GetCallback());
+  bool fetch_started_2 = manager()->Fetch(requested_uris, kRequestInfo,
+                                          completion_callback_2.GetCallback());
+  bool fetch_started_3 = manager()->Fetch(requested_uris, kRequestInfo,
+                                          completion_callback_3.GetCallback());
+  DestroyManager();
+
+  ASSERT_TRUE(fetch_started_1);
+  ASSERT_TRUE(fetch_started_2);
+  ASSERT_TRUE(fetch_started_3);
+  EXPECT_TRUE(completion_callback_1.IsReady());
+  EXPECT_TRUE(completion_callback_2.IsReady());
+  EXPECT_TRUE(completion_callback_3.IsReady());
+  EXPECT_EQ(0, GetNumPendingRequests());
+}
+
+}  // namespace affiliations
diff --git a/components/affiliations/core/browser/affiliation_service_impl.cc b/components/affiliations/core/browser/affiliation_service_impl.cc
index 593899c..a7e4154 100644
--- a/components/affiliations/core/browser/affiliation_service_impl.cc
+++ b/components/affiliations/core/browser/affiliation_service_impl.cc
@@ -127,7 +127,8 @@
       facets_to_request.push_back(top_level_domain);
     }
 
-    fetcher->StartRequest(facets_to_request, kChangePasswordUrlRequestInfo);
+    fetcher->StartRequest(facets_to_request, kChangePasswordUrlRequestInfo,
+                          base::DoNothing());
   }
 
   FetchInfo(FetchInfo&& other) = default;
diff --git a/components/affiliations/core/browser/affiliation_service_impl_unittest.cc b/components/affiliations/core/browser/affiliation_service_impl_unittest.cc
index 5d4c17e..774bf5ef7 100644
--- a/components/affiliations/core/browser/affiliation_service_impl_unittest.cc
+++ b/components/affiliations/core/browser/affiliation_service_impl_unittest.cc
@@ -193,8 +193,9 @@
 TEST_F(AffiliationServiceImplTest, FetchRequestIsStarted) {
   auto mock_fetcher = std::make_unique<MockAffiliationFetcher>();
 
-  EXPECT_CALL(*mock_fetcher, StartRequest(ToFacetsURIs(GURL(k1ExampleURL)),
-                                          kChangePasswordUrlRequestInfo));
+  EXPECT_CALL(*mock_fetcher,
+              StartRequest(ToFacetsURIs(GURL(k1ExampleURL)),
+                           kChangePasswordUrlRequestInfo, testing::_));
   EXPECT_CALL(mock_fetcher_factory(), CreateInstance)
       .WillOnce(Return(ByMove(std::move(mock_fetcher))));
 
@@ -207,8 +208,9 @@
   auto mock_fetcher = std::make_unique<MockAffiliationFetcher>();
   auto* raw_mock_fetcher = mock_fetcher.get();
 
-  EXPECT_CALL(*mock_fetcher, StartRequest(ToFacetsURIs(origin),
-                                          kChangePasswordUrlRequestInfo));
+  EXPECT_CALL(*mock_fetcher,
+              StartRequest(ToFacetsURIs(origin), kChangePasswordUrlRequestInfo,
+                           testing::_));
   EXPECT_CALL(mock_fetcher_factory(), CreateInstance)
       .WillOnce(Return(ByMove(std::move(mock_fetcher))));
 
@@ -237,8 +239,9 @@
   auto mock_fetcher = std::make_unique<MockAffiliationFetcher>();
   auto* raw_mock_fetcher = mock_fetcher.get();
 
-  EXPECT_CALL(*mock_fetcher, StartRequest(ToFacetsURIs(origin),
-                                          kChangePasswordUrlRequestInfo));
+  EXPECT_CALL(*mock_fetcher,
+              StartRequest(ToFacetsURIs(origin), kChangePasswordUrlRequestInfo,
+                           testing::_));
   EXPECT_CALL(mock_fetcher_factory(), CreateInstance)
       .WillOnce(Return(ByMove(std::move(mock_fetcher))));
 
@@ -264,8 +267,9 @@
   auto mock_fetcher = std::make_unique<MockAffiliationFetcher>();
   auto* raw_mock_fetcher = mock_fetcher.get();
 
-  EXPECT_CALL(*mock_fetcher, StartRequest(ToFacetsURIs(origin),
-                                          kChangePasswordUrlRequestInfo));
+  EXPECT_CALL(*mock_fetcher,
+              StartRequest(ToFacetsURIs(origin), kChangePasswordUrlRequestInfo,
+                           testing::_));
   EXPECT_CALL(mock_fetcher_factory(), CreateInstance)
       .WillOnce(Return(ByMove(std::move(mock_fetcher))));
 
@@ -287,8 +291,9 @@
   auto mock_fetcher = std::make_unique<MockAffiliationFetcher>();
   auto* raw_mock_fetcher = mock_fetcher.get();
 
-  EXPECT_CALL(*mock_fetcher, StartRequest(ToFacetsURIs(GURL(k1ExampleURL)),
-                                          kChangePasswordUrlRequestInfo));
+  EXPECT_CALL(*mock_fetcher,
+              StartRequest(ToFacetsURIs(GURL(k1ExampleURL)),
+                           kChangePasswordUrlRequestInfo, testing::_));
   EXPECT_CALL(mock_fetcher_factory(), CreateInstance)
       .WillOnce(Return(ByMove(std::move(mock_fetcher))));
 
@@ -304,8 +309,9 @@
   auto mock_fetcher = std::make_unique<MockAffiliationFetcher>();
   auto* raw_mock_fetcher = mock_fetcher.get();
 
-  EXPECT_CALL(*mock_fetcher, StartRequest(ToFacetsURIs(GURL(k1ExampleURL)),
-                                          kChangePasswordUrlRequestInfo));
+  EXPECT_CALL(*mock_fetcher,
+              StartRequest(ToFacetsURIs(GURL(k1ExampleURL)),
+                           kChangePasswordUrlRequestInfo, testing::_));
   EXPECT_CALL(mock_fetcher_factory(), CreateInstance)
       .WillOnce(Return(ByMove(std::move(mock_fetcher))));
 
@@ -338,10 +344,12 @@
   auto mock_fetcher = std::make_unique<MockAffiliationFetcher>();
   auto new_mock_fetcher = std::make_unique<MockAffiliationFetcher>();
 
-  EXPECT_CALL(*mock_fetcher, StartRequest(ToFacetsURIs(origin1),
-                                          kChangePasswordUrlRequestInfo));
-  EXPECT_CALL(*new_mock_fetcher, StartRequest(ToFacetsURIs(origin2),
-                                              kChangePasswordUrlRequestInfo));
+  EXPECT_CALL(*mock_fetcher,
+              StartRequest(ToFacetsURIs(origin1), kChangePasswordUrlRequestInfo,
+                           testing::_));
+  EXPECT_CALL(*new_mock_fetcher,
+              StartRequest(ToFacetsURIs(origin2), kChangePasswordUrlRequestInfo,
+                           testing::_));
   EXPECT_CALL(mock_fetcher_factory(), CreateInstance)
       .WillOnce(Return(ByMove(std::move(mock_fetcher))))
       .WillOnce(Return(ByMove(std::move(new_mock_fetcher))));
@@ -357,8 +365,9 @@
   const GURL origin(k1ExampleURL);
   auto mock_fetcher = std::make_unique<MockAffiliationFetcher>();
 
-  EXPECT_CALL(*mock_fetcher, StartRequest(ToFacetsURIs(origin),
-                                          kChangePasswordUrlRequestInfo));
+  EXPECT_CALL(*mock_fetcher,
+              StartRequest(ToFacetsURIs(origin), kChangePasswordUrlRequestInfo,
+                           testing::_));
   EXPECT_CALL(mock_fetcher_factory(), CreateInstance)
       .WillOnce(Return(ByMove(std::move(mock_fetcher))));
 
@@ -383,8 +392,9 @@
   auto mock_fetcher = std::make_unique<MockAffiliationFetcher>();
   auto* raw_mock_fetcher = mock_fetcher.get();
 
-  EXPECT_CALL(*mock_fetcher, StartRequest(ToFacetsURIs(origin),
-                                          kChangePasswordUrlRequestInfo));
+  EXPECT_CALL(*mock_fetcher,
+              StartRequest(ToFacetsURIs(origin), kChangePasswordUrlRequestInfo,
+                           testing::_));
   EXPECT_CALL(mock_fetcher_factory(), CreateInstance)
       .WillOnce(Return(ByMove(std::move(mock_fetcher))));
 
@@ -413,8 +423,9 @@
   auto mock_fetcher = std::make_unique<MockAffiliationFetcher>();
   auto* raw_mock_fetcher = mock_fetcher.get();
 
-  EXPECT_CALL(*mock_fetcher, StartRequest(ToFacetsURIs(origin),
-                                          kChangePasswordUrlRequestInfo));
+  EXPECT_CALL(*mock_fetcher,
+              StartRequest(ToFacetsURIs(origin), kChangePasswordUrlRequestInfo,
+                           testing::_));
   EXPECT_CALL(mock_fetcher_factory(), CreateInstance)
       .WillOnce(Return(ByMove(std::move(mock_fetcher))));
 
@@ -441,8 +452,9 @@
   auto mock_fetcher = std::make_unique<MockAffiliationFetcher>();
   auto* raw_mock_fetcher = mock_fetcher.get();
 
-  EXPECT_CALL(*mock_fetcher, StartRequest(ToFacetsURIs(origin),
-                                          kChangePasswordUrlRequestInfo));
+  EXPECT_CALL(*mock_fetcher,
+              StartRequest(ToFacetsURIs(origin), kChangePasswordUrlRequestInfo,
+                           testing::_));
   EXPECT_CALL(mock_fetcher_factory(), CreateInstance)
       .WillOnce(Return(ByMove(std::move(mock_fetcher))));
 
@@ -473,8 +485,9 @@
   auto mock_fetcher = std::make_unique<MockAffiliationFetcher>();
   auto* raw_mock_fetcher = mock_fetcher.get();
 
-  EXPECT_CALL(*mock_fetcher, StartRequest(ToFacetsURIs(origin),
-                                          kChangePasswordUrlRequestInfo));
+  EXPECT_CALL(*mock_fetcher,
+              StartRequest(ToFacetsURIs(origin), kChangePasswordUrlRequestInfo,
+                           testing::_));
   EXPECT_CALL(mock_fetcher_factory(), CreateInstance)
       .WillOnce(Return(ByMove(std::move(mock_fetcher))));
 
@@ -495,10 +508,12 @@
   auto new_mock_fetcher = std::make_unique<MockAffiliationFetcher>();
   auto* new_raw_mock_fetcher = new_mock_fetcher.get();
 
-  EXPECT_CALL(*mock_fetcher, StartRequest(ToFacetsURIs(origin1),
-                                          kChangePasswordUrlRequestInfo));
-  EXPECT_CALL(*new_mock_fetcher, StartRequest(ToFacetsURIs(origin2),
-                                              kChangePasswordUrlRequestInfo));
+  EXPECT_CALL(*mock_fetcher,
+              StartRequest(ToFacetsURIs(origin1), kChangePasswordUrlRequestInfo,
+                           testing::_));
+  EXPECT_CALL(*new_mock_fetcher,
+              StartRequest(ToFacetsURIs(origin2), kChangePasswordUrlRequestInfo,
+                           testing::_));
   EXPECT_CALL(mock_fetcher_factory(), CreateInstance)
       .WillOnce(Return(ByMove(std::move(mock_fetcher))))
       .WillOnce(Return(ByMove(std::move(new_mock_fetcher))));
@@ -645,8 +660,9 @@
   auto mock_fetcher = std::make_unique<MockAffiliationFetcher>();
   auto* raw_mock_fetcher = mock_fetcher.get();
 
-  EXPECT_CALL(*mock_fetcher, StartRequest(ElementsAre(android_facet),
-                                          kChangePasswordUrlRequestInfo));
+  EXPECT_CALL(*mock_fetcher,
+              StartRequest(ElementsAre(android_facet),
+                           kChangePasswordUrlRequestInfo, testing::_));
   EXPECT_CALL(mock_fetcher_factory(), CreateInstance)
       .WillOnce(Return(ByMove(std::move(mock_fetcher))));
 
diff --git a/components/affiliations/core/browser/fake_affiliation_api.cc b/components/affiliations/core/browser/fake_affiliation_api.cc
index d50b4009..df5fae9b 100644
--- a/components/affiliations/core/browser/fake_affiliation_api.cc
+++ b/components/affiliations/core/browser/fake_affiliation_api.cc
@@ -41,15 +41,14 @@
     return;
 
   FakeAffiliationFetcher* fetcher = fake_fetcher_factory_->PopNextFetcher();
-  std::unique_ptr<AffiliationFetcherDelegate::Result> fake_response(
-      new AffiliationFetcherDelegate::Result);
+  AffiliationFetcherDelegate::Result fake_response;
   for (const auto& facets : preset_equivalence_relation_) {
     bool had_intersection_with_request = std::ranges::any_of(
         fetcher->GetRequestedFacetURIs(), [&facets](const auto& uri) {
           return std::ranges::find(facets, uri, &Facet::uri) != facets.end();
         });
     if (had_intersection_with_request)
-      fake_response->affiliations.push_back(facets);
+      fake_response.affiliations.push_back(facets);
   }
   for (const auto& group : groups_) {
     bool had_intersection_with_request = std::ranges::any_of(
@@ -58,7 +57,7 @@
                  group.facets.end();
         });
     if (had_intersection_with_request)
-      fake_response->groupings.push_back(group);
+      fake_response.groupings.push_back(group);
   }
   fetcher->SimulateSuccess(std::move(fake_response));
 }
diff --git a/components/affiliations/core/browser/fake_affiliation_fetcher.cc b/components/affiliations/core/browser/fake_affiliation_fetcher.cc
index 8fabe6ca..2935156 100644
--- a/components/affiliations/core/browser/fake_affiliation_fetcher.cc
+++ b/components/affiliations/core/browser/fake_affiliation_fetcher.cc
@@ -17,18 +17,25 @@
 FakeAffiliationFetcher::~FakeAffiliationFetcher() = default;
 
 void FakeAffiliationFetcher::SimulateSuccess(
-    std::unique_ptr<AffiliationFetcherDelegate::Result> fake_result) {
-  delegate_->OnFetchSucceeded(this, std::move(fake_result));
+    const ParsedFetchResponse& fake_result_data) {
+  FetchResult result;
+  result.data = fake_result_data;
+  std::move(result_callback_).Run(std::move(result));
+  delegate_->OnFetchSucceeded(
+      this, std::make_unique<ParsedFetchResponse>(fake_result_data));
 }
 
 void FakeAffiliationFetcher::SimulateFailure() {
+  std::move(result_callback_).Run(FetchResult());
   delegate_->OnFetchFailed(this);
 }
 
 void FakeAffiliationFetcher::StartRequest(
     const std::vector<FacetURI>& facet_uris,
-    RequestInfo request_info) {
+    RequestInfo request_info,
+    base::OnceCallback<void(FetchResult)> result_callback) {
   facets_ = facet_uris;
+  result_callback_ = std::move(result_callback);
 }
 const std::vector<FacetURI>&
 FakeAffiliationFetcher::GetRequestedFacetURIs() const {
diff --git a/components/affiliations/core/browser/fake_affiliation_fetcher.h b/components/affiliations/core/browser/fake_affiliation_fetcher.h
index 8c792a6..0ee8272 100644
--- a/components/affiliations/core/browser/fake_affiliation_fetcher.h
+++ b/components/affiliations/core/browser/fake_affiliation_fetcher.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/containers/queue.h"
+#include "base/functional/callback.h"
 #include "base/memory/raw_ptr.h"
 #include "components/affiliations/core/browser/affiliation_fetcher_delegate.h"
 #include "components/affiliations/core/browser/affiliation_fetcher_factory.h"
@@ -26,22 +27,24 @@
 
   // Simulates successful completion of the request with |fake_result|. Note
   // that the consumer may choose to destroy |this| from within this call.
-  void SimulateSuccess(
-      std::unique_ptr<AffiliationFetcherDelegate::Result> fake_result);
+  void SimulateSuccess(const ParsedFetchResponse& fake_result);
 
   // Simulates completion of the request with failure. Note that the consumer
   // may choose to destroy |this| from within this call.
   void SimulateFailure();
 
   // AffiliationFetcherInterface
-  void StartRequest(const std::vector<FacetURI>& facet_uris,
-                    RequestInfo request_info) override;
+  void StartRequest(
+      const std::vector<FacetURI>& facet_uris,
+      RequestInfo request_info,
+      base::OnceCallback<void(FetchResult)> result_callback) override;
   const std::vector<FacetURI>& GetRequestedFacetURIs() const override;
 
  private:
   const raw_ptr<AffiliationFetcherDelegate> delegate_;
 
   std::vector<FacetURI> facets_;
+  base::OnceCallback<void(FetchResult)> result_callback_;
 };
 
 // Used in tests to return fake API responses to users of AffiliationFetcher.
diff --git a/components/affiliations/core/browser/hash_affiliation_fetcher.cc b/components/affiliations/core/browser/hash_affiliation_fetcher.cc
index b9dde414..8532454 100644
--- a/components/affiliations/core/browser/hash_affiliation_fetcher.cc
+++ b/components/affiliations/core/browser/hash_affiliation_fetcher.cc
@@ -2,6 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <memory>
+#include <utility>
+
+#include "base/functional/callback_forward.h"
 #ifdef UNSAFE_BUFFERS_BUILD
 // TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
 #pragma allow_unsafe_buffers
@@ -43,7 +47,7 @@
 // Enumeration listing the possible outcomes of fetching affiliation information
 // from the Affiliation API. This is used in UMA histograms, so do not change
 // existing values, only add new values at the end.
-enum class AffiliationFetchResult {
+enum class AffiliationFetchOutcome {
   kSuccess = 0,
   kFailure = 1,
   kMalformed = 2,
@@ -74,28 +78,28 @@
   return result;
 }
 
-void LogFetchResult(AffiliationFetchResult result,
+void LogFetchResult(AffiliationFetchOutcome result,
                     base::TimeDelta fetch_time,
                     size_t response_size = 0) {
   base::UmaHistogramEnumeration(
       "PasswordManager.AffiliationFetcher.FetchResult", result);
 
   switch (result) {
-    case AffiliationFetchResult::kSuccess:
+    case AffiliationFetchOutcome::kSuccess:
       base::UmaHistogramTimes(
           "PasswordManager.AffiliationFetcher.FetchTime.Success", fetch_time);
       base::UmaHistogramCounts1M(
           "PasswordManager.AffiliationFetcher.ResponseSize.Success",
           response_size);
       break;
-    case AffiliationFetchResult::kMalformed:
+    case AffiliationFetchOutcome::kMalformed:
       base::UmaHistogramTimes(
           "PasswordManager.AffiliationFetcher.FetchTime.Malformed", fetch_time);
       base::UmaHistogramCounts1M(
           "PasswordManager.AffiliationFetcher.ResponseSize.Malformed",
           response_size);
       break;
-    case AffiliationFetchResult::kFailure:
+    case AffiliationFetchOutcome::kFailure:
       base::UmaHistogramTimes(
           "PasswordManager.AffiliationFetcher.FetchTime.Failure", fetch_time);
       break;
@@ -120,7 +124,13 @@
     AffiliationFetcherDelegate* delegate)
     : url_loader_factory_(std::move(url_loader_factory)), delegate_(delegate) {}
 
-HashAffiliationFetcher::~HashAffiliationFetcher() = default;
+HashAffiliationFetcher::~HashAffiliationFetcher() {
+  // Run the callback in case the fetcher is destroyed before fetching the
+  // result.
+  if (result_callback_) {
+    std::move(result_callback_).Run(AffiliationFetcherInterface::FetchResult());
+  }
+}
 
 AffiliationFetcherDelegate* HashAffiliationFetcher::delegate() const {
   return delegate_;
@@ -128,8 +138,10 @@
 
 void HashAffiliationFetcher::StartRequest(
     const std::vector<FacetURI>& facet_uris,
-    RequestInfo request_info) {
+    RequestInfo request_info,
+    base::OnceCallback<void(FetchResult)> result_callback) {
   requested_facet_uris_ = facet_uris;
+  result_callback_ = std::move(result_callback);
 
   net::NetworkTrafficAnnotationTag traffic_annotation =
       net::DefineNetworkTrafficAnnotation("affiliation_lookup_by_hash", R"(
@@ -252,39 +264,49 @@
 
 void HashAffiliationFetcher::OnSimpleLoaderComplete(
     std::unique_ptr<std::string> response_body) {
+  CHECK(result_callback_);
+  FetchResult fetch_result;
+  fetch_result.network_status = simple_url_loader_->NetError();
   base::TimeDelta fetch_time = fetch_timer_.Elapsed();
   // Note that invoking the |delegate_| may destroy |this| synchronously, so the
   // invocation must happen last.
   bool success = simple_url_loader_->NetError() == net::OK;
-  int response_code = 0;
+  std::optional<net::HttpStatusCode> response_code;
   if (simple_url_loader_->ResponseInfo() &&
       simple_url_loader_->ResponseInfo()->headers) {
-    response_code =
-        simple_url_loader_->ResponseInfo()->headers->response_code();
+    response_code = net::TryToGetHttpStatusCode(
+        simple_url_loader_->ResponseInfo()->headers->response_code());
   }
-
+  fetch_result.http_status_code = response_code;
   if (!success || net::HTTP_OK != response_code) {
-    LogFetchResult(AffiliationFetchResult::kFailure, fetch_time);
-    base::UmaHistogramSparse(
-        "PasswordManager.AffiliationFetcher.FetchHttpResponseCode",
-        response_code);
+    LogFetchResult(AffiliationFetchOutcome::kFailure, fetch_time);
+    if (response_code.has_value()) {
+      base::UmaHistogramSparse(
+          "PasswordManager.AffiliationFetcher.FetchHttpResponseCode",
+          response_code.value());
+    }
     // Network error codes are negative. See: src/net/base/net_error_list.h.
     base::UmaHistogramSparse(
         "PasswordManager.AffiliationFetcher.FetchErrorCode",
         -simple_url_loader_->NetError());
     delegate_->OnFetchFailed(this);
+    std::move(result_callback_).Run(std::move(fetch_result));
     return;
   }
 
-  auto result_data = std::make_unique<AffiliationFetcherDelegate::Result>();
-  if (ParseResponse(*response_body, result_data.get())) {
-    LogFetchResult(AffiliationFetchResult::kSuccess, fetch_time,
+  ParsedFetchResponse result_data;
+  if (ParseResponse(*response_body, &result_data)) {
+    LogFetchResult(AffiliationFetchOutcome::kSuccess, fetch_time,
                    response_body->size());
-    delegate_->OnFetchSucceeded(this, std::move(result_data));
+    fetch_result.data = result_data;
+    delegate_->OnFetchSucceeded(
+        this, std::make_unique<ParsedFetchResponse>(result_data));
+    std::move(result_callback_).Run(std::move(fetch_result));
   } else {
-    LogFetchResult(AffiliationFetchResult::kMalformed, fetch_time,
+    LogFetchResult(AffiliationFetchOutcome::kMalformed, fetch_time,
                    response_body->size());
     delegate_->OnMalformedResponse(this);
+    std::move(result_callback_).Run(std::move(fetch_result));
   }
 }
 
diff --git a/components/affiliations/core/browser/hash_affiliation_fetcher.h b/components/affiliations/core/browser/hash_affiliation_fetcher.h
index d2d240e7..de91408 100644
--- a/components/affiliations/core/browser/hash_affiliation_fetcher.h
+++ b/components/affiliations/core/browser/hash_affiliation_fetcher.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/functional/callback.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/ref_counted.h"
 #include "base/timer/elapsed_timer.h"
@@ -35,8 +36,10 @@
   ~HashAffiliationFetcher() override;
 
   // AffiliationFetcherInterface
-  void StartRequest(const std::vector<FacetURI>& facet_uris,
-                    RequestInfo request_info) override;
+  void StartRequest(
+      const std::vector<FacetURI>& facet_uris,
+      RequestInfo request_info,
+      base::OnceCallback<void(FetchResult)> result_callback) override;
   const std::vector<FacetURI>& GetRequestedFacetURIs() const override;
 
   // Builds the URL for the Affiliation API's lookup method.
@@ -70,6 +73,7 @@
   void OnSimpleLoaderComplete(std::unique_ptr<std::string> response_body);
 
   std::vector<FacetURI> requested_facet_uris_;
+  base::OnceCallback<void(FetchResult)> result_callback_;
   scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
   const raw_ptr<AffiliationFetcherDelegate> delegate_;
   base::ElapsedTimer fetch_timer_;
diff --git a/components/affiliations/core/browser/hash_affiliation_fetcher_unittest.cc b/components/affiliations/core/browser/hash_affiliation_fetcher_unittest.cc
index c2029c5a..5d04761 100644
--- a/components/affiliations/core/browser/hash_affiliation_fetcher_unittest.cc
+++ b/components/affiliations/core/browser/hash_affiliation_fetcher_unittest.cc
@@ -7,11 +7,13 @@
 #include <memory>
 #include <string>
 
+#include "base/functional/callback_helpers.h"
 #include "base/strings/string_number_conversions_win.h"
 #include "base/test/bind.h"
 #include "base/test/gmock_move_support.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/task_environment.h"
+#include "base/test/test_future.h"
 #include "components/affiliations/core/browser/affiliation_api.pb.h"
 #include "components/affiliations/core/browser/affiliation_service_impl.h"
 #include "components/affiliations/core/browser/affiliation_utils.h"
@@ -156,7 +158,8 @@
   requested_uris.push_back(FacetURI::FromCanonicalSpec(k1ExampleURL));
   requested_uris.push_back(FacetURI::FromCanonicalSpec(k2ExampleURL));
 
-  fetcher.StartRequest(requested_uris, kChangePasswordUrlRequestInfo);
+  fetcher.StartRequest(requested_uris, kChangePasswordUrlRequestInfo,
+                       base::DoNothing());
   WaitForResponse();
 
   EXPECT_THAT(fetcher.GetRequestedFacetURIs(),
@@ -172,7 +175,8 @@
   requested_uris.push_back(FacetURI::FromCanonicalSpec(k1ExampleURL));
   requested_uris.push_back(FacetURI::FromCanonicalSpec(k2ExampleURL));
 
-  fetcher.StartRequest(requested_uris, kChangePasswordUrlRequestInfo);
+  fetcher.StartRequest(requested_uris, kChangePasswordUrlRequestInfo,
+                       base::DoNothing());
   WaitForResponse();
 
   std::vector<uint64_t> hash_prefixes;
@@ -207,27 +211,32 @@
   testing::StrictMock<MockAffiliationFetcherDelegate> mock_delegate;
   HashAffiliationFetcher fetcher(test_shared_loader_factory(), &mock_delegate);
 
-  std::unique_ptr<AffiliationFetcherDelegate::Result> result;
+  std::unique_ptr<AffiliationFetcherDelegate::Result> result_for_delegate;
+  base::test::TestFuture<AffiliationFetcherInterface::FetchResult>
+      result_callback;
   EXPECT_CALL(mock_delegate, OnFetchSucceeded(&fetcher, testing::_))
-      .WillOnce(MoveArg<1>(&result));
-  fetcher.StartRequest(requested_uris, request_info);
+      .WillOnce(MoveArg<1>(&result_for_delegate));
+  fetcher.StartRequest(requested_uris, request_info,
+                       result_callback.GetCallback());
   WaitForResponse();
+  auto result = result_callback.Take().data.value();
 
   ASSERT_NO_FATAL_FAILURE(
       VerifyRequestPayload(ComputeHashes(requested_uris), request_info));
   ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&mock_delegate));
 
-  ASSERT_EQ(2u, result->affiliations.size());
-  EXPECT_THAT(result->affiliations[0],
+  ASSERT_EQ(2u, result_for_delegate->affiliations.size());
+  EXPECT_THAT(result_for_delegate->affiliations[0],
               testing::UnorderedElementsAre(
                   Facet{FacetURI::FromCanonicalSpec(kExampleWebFacet1URI)},
                   Facet{FacetURI::FromCanonicalSpec(kExampleWebFacet2URI)},
                   Facet{FacetURI::FromCanonicalSpec(kExampleAndroidFacetURI)}));
   EXPECT_THAT(
-      result->affiliations[1],
+      result_for_delegate->affiliations[1],
       testing::UnorderedElementsAre(
           Facet{FacetURI::FromCanonicalSpec(kNotExampleWebFacetURI)},
           Facet{FacetURI::FromCanonicalSpec(kNotExampleAndroidFacetURI)}));
+  EXPECT_EQ(*result_for_delegate, result);
 }
 
 TEST_F(HashAffiliationFetcherTest, AndroidBrandingInfoIsReturnedIfPresent) {
@@ -249,24 +258,29 @@
   SetupSuccessfulResponse(test_response.SerializeAsString());
   testing::StrictMock<MockAffiliationFetcherDelegate> mock_delegate;
   HashAffiliationFetcher fetcher(test_shared_loader_factory(), &mock_delegate);
-  std::unique_ptr<AffiliationFetcherDelegate::Result> result;
+  std::unique_ptr<AffiliationFetcherDelegate::Result> result_for_delegate;
+  base::test::TestFuture<AffiliationFetcherInterface::FetchResult>
+      result_callback;
   EXPECT_CALL(mock_delegate, OnFetchSucceeded(&fetcher, testing::_))
-      .WillOnce(MoveArg<1>(&result));
-  fetcher.StartRequest(requested_uris, request_info);
+      .WillOnce(MoveArg<1>(&result_for_delegate));
+  fetcher.StartRequest(requested_uris, request_info,
+                       result_callback.GetCallback());
   WaitForResponse();
+  auto result = result_callback.Take().data.value();
 
   ASSERT_NO_FATAL_FAILURE(
       VerifyRequestPayload(ComputeHashes(requested_uris), request_info));
   ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&mock_delegate));
 
-  ASSERT_EQ(1u, result->affiliations.size());
-  EXPECT_THAT(result->affiliations[0],
+  ASSERT_EQ(1u, result_for_delegate->affiliations.size());
+  EXPECT_THAT(result_for_delegate->affiliations[0],
               testing::UnorderedElementsAre(
                   Facet{FacetURI::FromCanonicalSpec(kExampleWebFacet1URI)},
                   Facet{FacetURI::FromCanonicalSpec(kExampleWebFacet2URI)},
                   Facet{FacetURI::FromCanonicalSpec(kExampleAndroidFacetURI),
                         FacetBrandingInfo{kExampleAndroidPlayName,
                                           GURL(kExampleAndroidIconURL)}}));
+  EXPECT_EQ(*result_for_delegate, result);
 }
 
 TEST_F(HashAffiliationFetcherTest, ChangePasswordInfoIsReturnedIfPresent) {
@@ -291,25 +305,30 @@
   SetupSuccessfulResponse(test_response.SerializeAsString());
   testing::StrictMock<MockAffiliationFetcherDelegate> mock_delegate;
   HashAffiliationFetcher fetcher(test_shared_loader_factory(), &mock_delegate);
-  std::unique_ptr<AffiliationFetcherDelegate::Result> result;
+  std::unique_ptr<AffiliationFetcherDelegate::Result> result_for_delegate;
+  base::test::TestFuture<AffiliationFetcherInterface::FetchResult>
+      result_callback;
   EXPECT_CALL(mock_delegate, OnFetchSucceeded(&fetcher, testing::_))
-      .WillOnce(MoveArg<1>(&result));
-  fetcher.StartRequest(requested_uris, kChangePasswordUrlRequestInfo);
+      .WillOnce(MoveArg<1>(&result_for_delegate));
+  fetcher.StartRequest(requested_uris, kChangePasswordUrlRequestInfo,
+                       result_callback.GetCallback());
   WaitForResponse();
+  auto result = result_callback.Take().data.value();
 
   ASSERT_NO_FATAL_FAILURE(VerifyRequestPayload(ComputeHashes(requested_uris),
                                                kChangePasswordUrlRequestInfo));
   ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&mock_delegate));
 
-  ASSERT_EQ(1u, result->groupings.size());
+  ASSERT_EQ(1u, result_for_delegate->groupings.size());
   EXPECT_THAT(
-      result->groupings[0].facets,
+      result_for_delegate->groupings[0].facets,
       testing::UnorderedElementsAre(
           Facet(FacetURI::FromCanonicalSpec(kExampleWebFacet1URI),
                 FacetBrandingInfo(), GURL(kExampleWebFacet1ChangePasswordURI)),
           Facet(FacetURI::FromCanonicalSpec(kExampleWebFacet2URI),
                 FacetBrandingInfo(),
                 GURL(kExampleWebFacet2ChangePasswordURI))));
+  EXPECT_EQ(*result_for_delegate, result);
 }
 
 // The API contract of this class is to return an equivalence class for all
@@ -326,20 +345,25 @@
   SetupSuccessfulResponse(empty_test_response.SerializeAsString());
   testing::StrictMock<MockAffiliationFetcherDelegate> mock_delegate;
   HashAffiliationFetcher fetcher(test_shared_loader_factory(), &mock_delegate);
-  std::unique_ptr<AffiliationFetcherDelegate::Result> result;
+  std::unique_ptr<AffiliationFetcherDelegate::Result> result_for_delegate;
+  base::test::TestFuture<AffiliationFetcherInterface::FetchResult>
+      result_callback;
   EXPECT_CALL(mock_delegate, OnFetchSucceeded(&fetcher, testing::_))
-      .WillOnce(MoveArg<1>(&result));
-  fetcher.StartRequest(requested_uris, request_info);
+      .WillOnce(MoveArg<1>(&result_for_delegate));
+  fetcher.StartRequest(requested_uris, request_info,
+                       result_callback.GetCallback());
   WaitForResponse();
+  auto result = result_callback.Take().data.value();
 
   ASSERT_NO_FATAL_FAILURE(
       VerifyRequestPayload(ComputeHashes(requested_uris), request_info));
   ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&mock_delegate));
 
-  ASSERT_EQ(1u, result->affiliations.size());
-  EXPECT_THAT(result->affiliations[0],
+  ASSERT_EQ(1u, result_for_delegate->affiliations.size());
+  EXPECT_THAT(result_for_delegate->affiliations[0],
               testing::UnorderedElementsAre(
                   Facet{FacetURI::FromCanonicalSpec(kExampleWebFacet1URI)}));
+  EXPECT_EQ(*result_for_delegate, result);
 }
 
 TEST_F(HashAffiliationFetcherTest, DuplicateEquivalenceClassesAreIgnored) {
@@ -359,20 +383,24 @@
   SetupSuccessfulResponse(test_response.SerializeAsString());
   testing::StrictMock<MockAffiliationFetcherDelegate> mock_delegate;
   HashAffiliationFetcher fetcher(test_shared_loader_factory(), &mock_delegate);
-  std::unique_ptr<AffiliationFetcherDelegate::Result> result;
+  std::unique_ptr<AffiliationFetcherDelegate::Result> result_for_delegate;
+  base::test::TestFuture<AffiliationFetcherInterface::FetchResult>
+      result_callback;
   EXPECT_CALL(mock_delegate, OnFetchSucceeded(&fetcher, testing::_))
-      .WillOnce(MoveArg<1>(&result));
-  fetcher.StartRequest(requested_uris, {});
+      .WillOnce(MoveArg<1>(&result_for_delegate));
+  fetcher.StartRequest(requested_uris, {}, result_callback.GetCallback());
   WaitForResponse();
+  auto result = result_callback.Take().data.value();
 
   ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&mock_delegate));
 
-  ASSERT_EQ(1u, result->affiliations.size());
-  EXPECT_THAT(result->affiliations[0],
+  ASSERT_EQ(1u, result_for_delegate->affiliations.size());
+  EXPECT_THAT(result_for_delegate->affiliations[0],
               testing::UnorderedElementsAre(
                   Facet{FacetURI::FromCanonicalSpec(kExampleWebFacet1URI)},
                   Facet{FacetURI::FromCanonicalSpec(kExampleWebFacet2URI)},
                   Facet{FacetURI::FromCanonicalSpec(kExampleAndroidFacetURI)}));
+  EXPECT_EQ(*result_for_delegate, result);
 }
 
 TEST_F(HashAffiliationFetcherTest, NonRequestedEquivalenceClassesAreIgnored) {
@@ -391,19 +419,23 @@
   SetupSuccessfulResponse(test_response.SerializeAsString());
   testing::StrictMock<MockAffiliationFetcherDelegate> mock_delegate;
   HashAffiliationFetcher fetcher(test_shared_loader_factory(), &mock_delegate);
-  std::unique_ptr<AffiliationFetcherDelegate::Result> result;
+  std::unique_ptr<AffiliationFetcherDelegate::Result> result_for_delegate;
+  base::test::TestFuture<AffiliationFetcherInterface::FetchResult>
+      result_callback;
   EXPECT_CALL(mock_delegate, OnFetchSucceeded(&fetcher, testing::_))
-      .WillOnce(MoveArg<1>(&result));
-  fetcher.StartRequest(requested_uris, {});
+      .WillOnce(MoveArg<1>(&result_for_delegate));
+  fetcher.StartRequest(requested_uris, {}, result_callback.GetCallback());
   WaitForResponse();
+  auto result = result_callback.Take().data.value();
 
   ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&mock_delegate));
 
-  ASSERT_EQ(1u, result->affiliations.size());
-  EXPECT_THAT(result->affiliations[0],
+  ASSERT_EQ(1u, result_for_delegate->affiliations.size());
+  EXPECT_THAT(result_for_delegate->affiliations[0],
               testing::UnorderedElementsAre(
                   Facet{FacetURI::FromCanonicalSpec(kExampleWebFacet2URI)},
                   Facet{FacetURI::FromCanonicalSpec(kExampleAndroidFacetURI)}));
+  EXPECT_EQ(*result_for_delegate, result);
 }
 
 TEST_F(HashAffiliationFetcherTest, EmptyEquivalenceClassesAreIgnored) {
@@ -419,18 +451,22 @@
   SetupSuccessfulResponse(test_response.SerializeAsString());
   testing::StrictMock<MockAffiliationFetcherDelegate> mock_delegate;
   HashAffiliationFetcher fetcher(test_shared_loader_factory(), &mock_delegate);
-  std::unique_ptr<AffiliationFetcherDelegate::Result> result;
+  std::unique_ptr<AffiliationFetcherDelegate::Result> result_for_delegate;
+  base::test::TestFuture<AffiliationFetcherInterface::FetchResult>
+      result_callback;
   EXPECT_CALL(mock_delegate, OnFetchSucceeded(&fetcher, testing::_))
-      .WillOnce(MoveArg<1>(&result));
-  fetcher.StartRequest(requested_uris, {});
+      .WillOnce(MoveArg<1>(&result_for_delegate));
+  fetcher.StartRequest(requested_uris, {}, result_callback.GetCallback());
   WaitForResponse();
+  auto result = result_callback.Take().data.value();
 
   ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&mock_delegate));
 
-  ASSERT_EQ(1u, result->affiliations.size());
-  EXPECT_THAT(result->affiliations[0],
+  ASSERT_EQ(1u, result_for_delegate->affiliations.size());
+  EXPECT_THAT(result_for_delegate->affiliations[0],
               testing::UnorderedElementsAre(
                   Facet{FacetURI::FromCanonicalSpec(kExampleWebFacet1URI)}));
+  EXPECT_EQ(*result_for_delegate, result);
 }
 
 TEST_F(HashAffiliationFetcherTest, UnrecognizedFacetURIsAreIgnored) {
@@ -452,20 +488,24 @@
   SetupSuccessfulResponse(test_response.SerializeAsString());
   testing::StrictMock<MockAffiliationFetcherDelegate> mock_delegate;
   HashAffiliationFetcher fetcher(test_shared_loader_factory(), &mock_delegate);
-  std::unique_ptr<AffiliationFetcherDelegate::Result> result;
+  std::unique_ptr<AffiliationFetcherDelegate::Result> result_for_delegate;
+  base::test::TestFuture<AffiliationFetcherInterface::FetchResult>
+      result_callback;
   EXPECT_CALL(mock_delegate, OnFetchSucceeded(&fetcher, testing::_))
-      .WillOnce(MoveArg<1>(&result));
-  fetcher.StartRequest(requested_uris, {});
+      .WillOnce(MoveArg<1>(&result_for_delegate));
+  fetcher.StartRequest(requested_uris, {}, result_callback.GetCallback());
   WaitForResponse();
+  auto result = result_callback.Take().data.value();
 
   ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&mock_delegate));
 
-  ASSERT_EQ(1u, result->affiliations.size());
-  EXPECT_THAT(result->affiliations[0],
+  ASSERT_EQ(1u, result_for_delegate->affiliations.size());
+  EXPECT_THAT(result_for_delegate->affiliations[0],
               testing::UnorderedElementsAre(
                   Facet{FacetURI::FromCanonicalSpec(kExampleWebFacet1URI)},
                   Facet{FacetURI::FromCanonicalSpec(kExampleWebFacet2URI)},
                   Facet{FacetURI::FromCanonicalSpec(kExampleAndroidFacetURI)}));
+  EXPECT_EQ(*result_for_delegate, result);
 }
 
 TEST_F(HashAffiliationFetcherTest, FailureBecauseResponseIsNotAProtobuf) {
@@ -478,8 +518,14 @@
   testing::StrictMock<MockAffiliationFetcherDelegate> mock_delegate;
   HashAffiliationFetcher fetcher(test_shared_loader_factory(), &mock_delegate);
   EXPECT_CALL(mock_delegate, OnMalformedResponse(&fetcher));
-  fetcher.StartRequest(uris, {});
+  base::test::TestFuture<AffiliationFetcherInterface::FetchResult>
+      result_callback;
+  fetcher.StartRequest(uris, {}, result_callback.GetCallback());
   WaitForResponse();
+  auto result = result_callback.Take();
+  EXPECT_EQ(net::HTTP_OK, result.http_status_code);
+  EXPECT_EQ(net::OK, result.network_status);
+  EXPECT_FALSE(result.data.has_value());
 }
 
 // Partially overlapping equivalence classes violate the invariant that
@@ -501,8 +547,14 @@
   testing::StrictMock<MockAffiliationFetcherDelegate> mock_delegate;
   HashAffiliationFetcher fetcher(test_shared_loader_factory(), &mock_delegate);
   EXPECT_CALL(mock_delegate, OnMalformedResponse(&fetcher));
-  fetcher.StartRequest(uris, {});
+  base::test::TestFuture<AffiliationFetcherInterface::FetchResult>
+      result_callback;
+  fetcher.StartRequest(uris, {}, result_callback.GetCallback());
   WaitForResponse();
+  auto result = result_callback.Take();
+  EXPECT_EQ(net::HTTP_OK, result.http_status_code);
+  EXPECT_EQ(net::OK, result.network_status);
+  EXPECT_FALSE(result.data.has_value());
 }
 
 TEST_F(HashAffiliationFetcherTest, FailOnServerError) {
@@ -513,8 +565,14 @@
   testing::StrictMock<MockAffiliationFetcherDelegate> mock_delegate;
   HashAffiliationFetcher fetcher(test_shared_loader_factory(), &mock_delegate);
   EXPECT_CALL(mock_delegate, OnFetchFailed(&fetcher));
-  fetcher.StartRequest(uris, {});
+  base::test::TestFuture<AffiliationFetcherInterface::FetchResult>
+      result_callback;
+  fetcher.StartRequest(uris, {}, result_callback.GetCallback());
   WaitForResponse();
+  auto result = result_callback.Take();
+
+  EXPECT_EQ(net::HTTP_INTERNAL_SERVER_ERROR, result.http_status_code);
+  EXPECT_EQ(net::ERR_HTTP_RESPONSE_CODE_FAILURE, result.network_status);
 }
 
 TEST_F(HashAffiliationFetcherTest, FailOnNetworkError) {
@@ -525,8 +583,14 @@
   testing::StrictMock<MockAffiliationFetcherDelegate> mock_delegate;
   HashAffiliationFetcher fetcher(test_shared_loader_factory(), &mock_delegate);
   EXPECT_CALL(mock_delegate, OnFetchFailed(&fetcher));
-  fetcher.StartRequest(uris, {});
+  base::test::TestFuture<AffiliationFetcherInterface::FetchResult>
+      result_callback;
+  fetcher.StartRequest(uris, {}, result_callback.GetCallback());
   WaitForResponse();
+  auto result = result_callback.Take();
+
+  EXPECT_EQ(net::ERR_NETWORK_CHANGED, result.network_status);
+  EXPECT_FALSE(result.http_status_code.has_value());
 }
 
 TEST_F(HashAffiliationFetcherTest, MetricsWhenSuccess) {
@@ -538,11 +602,14 @@
       affiliation_pb::LookupAffiliationResponse().SerializeAsString());
   testing::StrictMock<MockAffiliationFetcherDelegate> mock_delegate;
   HashAffiliationFetcher fetcher(test_shared_loader_factory(), &mock_delegate);
-  std::unique_ptr<AffiliationFetcherDelegate::Result> result;
+  std::unique_ptr<AffiliationFetcherDelegate::Result> result_for_delegate;
+  base::test::TestFuture<AffiliationFetcherInterface::FetchResult>
+      result_callback;
   EXPECT_CALL(mock_delegate, OnFetchSucceeded(&fetcher, testing::_))
-      .WillOnce(MoveArg<1>(&result));
-  fetcher.StartRequest(requested_uris, {});
+      .WillOnce(MoveArg<1>(&result_for_delegate));
+  fetcher.StartRequest(requested_uris, {}, result_callback.GetCallback());
   WaitForResponse();
+  auto result = result_callback.Take().data.value();
 
   histogram_tester.ExpectTotalCount(
       "PasswordManager.AffiliationFetcher.FetchTime.Success", 1);
@@ -564,11 +631,15 @@
   SetupSuccessfulResponse(kMalformedResponse);
   testing::StrictMock<MockAffiliationFetcherDelegate> mock_delegate;
   HashAffiliationFetcher fetcher(test_shared_loader_factory(), &mock_delegate);
-  std::unique_ptr<AffiliationFetcherDelegate::Result> result;
+  std::unique_ptr<AffiliationFetcherDelegate::Result> result_for_delegate;
+  base::test::TestFuture<AffiliationFetcherInterface::FetchResult>
+      result_callback;
   EXPECT_CALL(mock_delegate, OnMalformedResponse(&fetcher));
-  fetcher.StartRequest(uris, {});
+  fetcher.StartRequest(uris, {}, result_callback.GetCallback());
   WaitForResponse();
+  auto result = result_callback.Take();
 
+  EXPECT_FALSE(result.data.has_value());
   histogram_tester.ExpectTotalCount(
       "PasswordManager.AffiliationFetcher.FetchTime.Success", 0);
   histogram_tester.ExpectTotalCount(
@@ -604,21 +675,25 @@
   SetupSuccessfulResponse(test_response.SerializeAsString());
   testing::StrictMock<MockAffiliationFetcherDelegate> mock_delegate;
   HashAffiliationFetcher fetcher(test_shared_loader_factory(), &mock_delegate);
-  std::unique_ptr<AffiliationFetcherDelegate::Result> result;
+  std::unique_ptr<AffiliationFetcherDelegate::Result> result_for_delegate;
+  base::test::TestFuture<AffiliationFetcherInterface::FetchResult>
+      result_callback;
   EXPECT_CALL(mock_delegate, OnFetchSucceeded(&fetcher, testing::_))
-      .WillOnce(MoveArg<1>(&result));
-  fetcher.StartRequest(requested_uris, request_info);
+      .WillOnce(MoveArg<1>(&result_for_delegate));
+  fetcher.StartRequest(requested_uris, request_info,
+                       result_callback.GetCallback());
   WaitForResponse();
+  auto result = result_callback.Take().data.value();
 
   ASSERT_NO_FATAL_FAILURE(
       VerifyRequestPayload(ComputeHashes(requested_uris), request_info));
   ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&mock_delegate));
 
-  ASSERT_EQ(2u, result->groupings.size());
-  EXPECT_THAT(result->groupings[0].branding_info,
+  ASSERT_EQ(2u, result_for_delegate->groupings.size());
+  EXPECT_THAT(result_for_delegate->groupings[0].branding_info,
               testing::Eq(FacetBrandingInfo{kExampleAndroidPlayName,
                                             GURL(kExampleAndroidIconURL)}));
-  EXPECT_THAT(result->groupings[1].branding_info,
+  EXPECT_THAT(result_for_delegate->groupings[1].branding_info,
               testing::Eq(FacetBrandingInfo()));
 }
 
diff --git a/components/affiliations/core/browser/mock_affiliation_fetcher.h b/components/affiliations/core/browser/mock_affiliation_fetcher.h
index 13b1ce5..5701707 100644
--- a/components/affiliations/core/browser/mock_affiliation_fetcher.h
+++ b/components/affiliations/core/browser/mock_affiliation_fetcher.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_AFFILIATIONS_CORE_BROWSER_MOCK_AFFILIATION_FETCHER_H_
 #define COMPONENTS_AFFILIATIONS_CORE_BROWSER_MOCK_AFFILIATION_FETCHER_H_
 
+#include "base/functional/callback.h"
 #include "components/affiliations/core/browser/affiliation_fetcher_interface.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
@@ -17,7 +18,9 @@
 
   MOCK_METHOD(void,
               StartRequest,
-              (const std::vector<FacetURI>&, RequestInfo),
+              (const std::vector<FacetURI>&,
+               RequestInfo,
+               base::OnceCallback<void(FetchResult)>),
               (override));
   MOCK_METHOD(std::vector<FacetURI>&,
               GetRequestedFacetURIs,
diff --git a/components/autofill/core/browser/data_model/transliterator.cc b/components/autofill/core/browser/data_model/transliterator.cc
index c5e1140..a9311360 100644
--- a/components/autofill/core/browser/data_model/transliterator.cc
+++ b/components/autofill/core/browser/data_model/transliterator.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "base/containers/fixed_flat_set.h"
+#include "base/containers/flat_map.h"
 #include "base/feature_list.h"
 #include "base/i18n/transliterator.h"
 #include "base/i18n/unicodestring.h"
@@ -39,7 +40,20 @@
     base::MakeFixedFlatSet<std::string_view>(
         {"AT", "BE", "CH", "DE", "IT", "LI", "LU"});
 
-std::unique_ptr<base::i18n::Transliterator> GetTransliterator(
+base::flat_map<TransliterationId,
+               std::unique_ptr<const base::i18n::Transliterator>>&
+GetTransliteratorsMap() {
+  // The `ICU` library does not cache the transliterators created from rules,
+  // since their creation caused ANR errors on IOS and Android, it is important
+  // that until those are converted to be generated during the compile time,
+  // they are cached in memory for the duration of the browser lifetime.
+  static base::NoDestructor<base::flat_map<
+      TransliterationId, std::unique_ptr<const base::i18n::Transliterator>>>
+      autofill_transliterators;
+  return *autofill_transliterators;
+}
+
+std::unique_ptr<base::i18n::Transliterator> CreateTransliterator(
     TransliterationId id) {
   std::string transliteration_rules;
   std::unique_ptr<base::i18n::Transliterator> transliterator;
@@ -61,7 +75,7 @@
           "[ü {u \u0308} Ü {U \u0308}] → ue;";
       [[fallthrough]];
     case TransliterationId::kDefault:
-      // This rules are happening in the following order:
+      // These rules are happening in the following order:
       // First there are `TransliterationId::kGerman` specific rules if they are
       // present, then
       // "::NFD;" performs a decomposition and normalization.
@@ -88,6 +102,20 @@
   return transliterator;
 }
 
+// May return nullptr if the transliterator cannot be initialized.
+const base::i18n::Transliterator* GetCachedTransliterator(
+    TransliterationId transliteration_id) {
+  static base::NoDestructor<base::Lock> getting_transliterator_lock;
+  base::AutoLock lock(*getting_transliterator_lock);
+
+  const auto [it, inserted] =
+      GetTransliteratorsMap().try_emplace(transliteration_id, nullptr);
+  if (inserted) {
+    it->second = CreateTransliterator(transliteration_id);
+  }
+  return it->second.get();
+}
+
 std::u16string Transliterate(std::u16string_view value,
                              TransliterationId transliteration_id) {
   if (value.empty()) {
@@ -95,8 +123,8 @@
   }
 
   base::Time transliterator_creation_time = base::Time::Now();
-  std::unique_ptr<base::i18n::Transliterator> transliterator =
-      GetTransliterator(transliteration_id);
+  const base::i18n::Transliterator* transliterator =
+      GetCachedTransliterator(transliteration_id);
   // TODO(crbug.com/399657187): Remove once the issue is resolved.
   base::UmaHistogramTimes("Autofill.TransliteratorCreationTime",
                           base::Time::Now() - transliterator_creation_time);
@@ -129,4 +157,10 @@
                                   : TransliterationId::kKatakanaToHiragana);
 }
 
+// Should be only used for testing. In general transliterators shouldn't be
+// deleted during the lifetime of the browser.
+void ClearCachedTransliterators() {
+  GetTransliteratorsMap().clear();
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/browser/data_model/transliterator.h b/components/autofill/core/browser/data_model/transliterator.h
index 0aac388..73800c6 100644
--- a/components/autofill/core/browser/data_model/transliterator.h
+++ b/components/autofill/core/browser/data_model/transliterator.h
@@ -29,6 +29,11 @@
     std::u16string_view value,
     bool inverse_transliteration = false);
 
+#if defined(UNIT_TEST)
+// Clears the stored transliterators, should be only used for testing puproses.
+void ClearCachedTransliterators();
+#endif
+
 }  // namespace autofill
 
 #endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_TRANSLITERATOR_H_
diff --git a/components/autofill/core/browser/data_model/transliterator_unittest.cc b/components/autofill/core/browser/data_model/transliterator_unittest.cc
index 2e5e033..6995776 100644
--- a/components/autofill/core/browser/data_model/transliterator_unittest.cc
+++ b/components/autofill/core/browser/data_model/transliterator_unittest.cc
@@ -13,17 +13,23 @@
 
 namespace autofill {
 
-TEST(Transliterator, RemoveDiacriticsAndConvertToLowerCase) {
+class TransliteratorTest : public ::testing::Test {
+ public:
+  TransliteratorTest() { ClearCachedTransliterators(); }
+};
+
+TEST_F(TransliteratorTest, RemoveDiacriticsAndConvertToLowerCase) {
   base::HistogramTester histogram_tester;
   EXPECT_EQ(RemoveDiacriticsAndConvertToLowerCase(
                 u"āēaa11.īūčģķļņšžKāäǟḑēīļņōȯȱõȭŗšțūžßł"),
             u"aeaa11.iucgklnszkaaadeilnooooorstuzssl");
-  // Check that the transliterator initialization status is recorded.
+  EXPECT_EQ(RemoveDiacriticsAndConvertToLowerCase(u"ABC.Ó"), u"abc.o");
+  // Check that there is only one transliterator object created.
   histogram_tester.ExpectUniqueSample("Autofill.TransliteratorInitStatus", true,
                                       1);
 }
 
-TEST(Transliterator, GermanTransliteration) {
+TEST_F(TransliteratorTest, GermanTransliteration) {
   base::HistogramTester histogram_tester;
   base::test::ScopedFeatureList features{
       features::kAutofillEnableGermanTransliteration};
@@ -36,9 +42,11 @@
   EXPECT_EQ(RemoveDiacriticsAndConvertToLowerCase(u"Ä_Ö_Ü_ß",
                                                   AddressCountryCode("DE")),
             u"ae_oe_ue_ss");
-  // Check that the transliterator initialization status is recorded.
+  // Check that the transliterator object is initialized only twice (one for
+  // the default transliteration without the country code present and the other
+  // for the german transliteration).
   histogram_tester.ExpectUniqueSample("Autofill.TransliteratorInitStatus", true,
-                                      3);
+                                      2);
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/filling/addresses/field_filling_address_util_unittest.cc b/components/autofill/core/browser/filling/addresses/field_filling_address_util_unittest.cc
index 94c3e02..fe7f2b0 100644
--- a/components/autofill/core/browser/filling/addresses/field_filling_address_util_unittest.cc
+++ b/components/autofill/core/browser/filling/addresses/field_filling_address_util_unittest.cc
@@ -15,6 +15,7 @@
 #include "components/autofill/core/browser/autofill_field.h"
 #include "components/autofill/core/browser/autofill_type.h"
 #include "components/autofill/core/browser/data_model/addresses/autofill_profile.h"
+#include "components/autofill/core/browser/data_model/transliterator.h"
 #include "components/autofill/core/browser/data_quality/addresses/address_normalizer.h"
 #include "components/autofill/core/browser/data_quality/addresses/address_normalizer_impl.h"
 #include "components/autofill/core/browser/field_types.h"
@@ -864,7 +865,10 @@
 class AlternativeNameFillingTest
     : public FieldFillingAddressUtilTest,
       public testing::WithParamInterface<
-          std::tuple<FieldType, AlternativeNameFillingTestCase>> {};
+          std::tuple<FieldType, AlternativeNameFillingTestCase>> {
+ public:
+  AlternativeNameFillingTest() { ClearCachedTransliterators(); }
+};
 
 TEST_P(AlternativeNameFillingTest, FillAlternativeName) {
   base::test::ScopedFeatureList features{
diff --git a/components/cronet/gn2bp/copy.bara.sky b/components/cronet/gn2bp/copy.bara.sky
index 9e15b9c..026aef4 100644
--- a/components/cronet/gn2bp/copy.bara.sky
+++ b/components/cronet/gn2bp/copy.bara.sky
@@ -65,7 +65,6 @@
     "net/third_party/uri_template/**",
     "third_party/abseil-cpp/**",
     "third_party/android_ndk/sources/android/cpufeatures/**",
-    "third_party/llvm-libc/**",
     # See https://chromium-review.googlesource.com/c/chromium/src/+/4885470
     # Note: Only used for tests.
     "third_party/anonymous_tokens/**",
@@ -84,7 +83,6 @@
     "third_party/googletest/**",
     "third_party/icu/**",
     "third_party/jni_zero/**",
-    "third_party/libc++/**",
     "third_party/libc++abi/**",
     # Note: Only used for tests.
     "third_party/libxml/**",
@@ -104,6 +102,18 @@
     "url/third_party/mozilla/**",
     "third_party/simdutf/**",
   ]) + glob([
+    "third_party/libc++/**",
+  ]) - glob([
+    # This is not used, and contains a huge number of files (~10k) that slows
+    # down imports and checkouts.
+    "third_party/libc++/src/test/**",
+  ]) + glob([
+    "third_party/llvm-libc/**",
+  ]) - glob([
+    # This is not used, and contains a large number of files that slows down
+    # imports and checkouts.
+    "third_party/llvm-libc/src/test/**"
+  ]) + glob([
     "third_party/boringssl/**",
   ]) - glob([
     # This is not used, and contains a large number of files that slows down
diff --git a/components/data_sharing/public/group_data.cc b/components/data_sharing/public/group_data.cc
index 59d01be..985910d2 100644
--- a/components/data_sharing/public/group_data.cc
+++ b/components/data_sharing/public/group_data.cc
@@ -91,11 +91,13 @@
                      std::string display_name_param,
                      std::vector<GroupMember> members_param,
                      std::vector<GroupMember> former_members_param,
-                     std::string access_token)
+                     std::string access_token,
+                    GroupEnabledStatus enabled_status)
     : group_token(GroupToken(group_id, access_token)),
       display_name(std::move(display_name_param)),
       members(std::move(members_param)),
-      former_members(std::move(former_members_param)) {}
+      former_members(std::move(former_members_param)),
+      enabled_status(enabled_status) {}
 
 GroupData::GroupData(const GroupData&) = default;
 GroupData& GroupData::operator=(const GroupData&) = default;
diff --git a/components/data_sharing/public/group_data.h b/components/data_sharing/public/group_data.h
index ee13737..10f1a95 100644
--- a/components/data_sharing/public/group_data.h
+++ b/components/data_sharing/public/group_data.h
@@ -26,6 +26,15 @@
   kFormerMember = 4
 };
 
+// This tells if the group is enabled or not. This field is set by chrome client
+// after comparing the version info from ReadGroup request and comparing it with
+// hardcoded version info in Chrome client.
+enum class GroupEnabledStatus {
+  kUnknown = 0,
+  kEnabled = 1,
+  kDisabledChromeNeedsUpdate = 2,
+};
+
 struct GroupMember {
   GroupMember();
 
@@ -102,7 +111,8 @@
             std::string display_name,
             std::vector<GroupMember> members,
             std::vector<GroupMember> former_members,
-            std::string access_token);
+            std::string access_token,
+            GroupEnabledStatus enabled_status = GroupEnabledStatus::kUnknown);
 
   GroupData(const GroupData&);
   GroupData& operator=(const GroupData&);
@@ -116,6 +126,7 @@
   std::string display_name;
   std::vector<GroupMember> members;
   std::vector<GroupMember> former_members;
+  GroupEnabledStatus enabled_status = GroupEnabledStatus::kUnknown;
 };
 
 struct GroupEvent {
diff --git a/components/omnibox/browser/most_visited_sites_provider.cc b/components/omnibox/browser/most_visited_sites_provider.cc
index 4ea359505..10ad361 100644
--- a/components/omnibox/browser/most_visited_sites_provider.cc
+++ b/components/omnibox/browser/most_visited_sites_provider.cc
@@ -11,6 +11,7 @@
 #include "base/functional/bind.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/strings/escape.h"
+#include "base/trace_event/trace_event.h"
 #include "components/history/core/browser/history_service.h"
 #include "components/history/core/browser/top_sites.h"
 #include "components/omnibox/browser/autocomplete_input.h"
@@ -255,27 +256,26 @@
 
   done_ = false;
 
-  const TabMatcher& tab_matcher = client_->GetTabMatcher();
-
   // TODO(ender): Relocate this to StartPrefetch() when additional prefetch
   // contexts are available.
   auto url_suggestions_on_focus_config =
       omnibox_feature_configs::OmniboxUrlSuggestionsOnFocus::Get();
   if (url_suggestions_on_focus_config.enabled &&
       url_suggestions_on_focus_config.directly_query_history_service) {
-    // The requested results size is the maximum amount of suggestions
-    // that can be shown in the omnibox in addition to the number of blocked
-    // sites and open tabs. Add 1 to `GetOpenTabs` since it doesn't consider
-    // the currently active tab.
-    client_->GetHistoryService()->QueryMostVisitedURLs(
-        (tab_matcher.GetOpenTabs(&input).size() + 1) +
-            url_suggestions_on_focus_config.max_suggestions,
-        base::BindOnce(
-            &MostVisitedSitesProvider::OnMostVisitedUrlsFromHistoryAvailable,
-            request_weak_ptr_factory_.GetWeakPtr(), input),
-        &cancelable_task_tracker_,
-        url_suggestions_on_focus_config.most_visited_recency_factor,
-        url_suggestions_on_focus_config.most_visited_recency_window);
+    CHECK(url_suggestions_on_focus_config.MostVisitedPrefetchingEnabled() ||
+          cached_sites_.empty());
+    // If there are cached results, use them.
+    if (!cached_sites_.empty()) {
+      OnMostVisitedUrlsFromHistoryAvailable(input, cached_sites_);
+    }
+    // Queries the HistoryService for sites. If prefetching is enabled, this
+    // updates `cached_sites_`, otherwise this updates the provider's matches.
+    // Prefetching doesn't update the provider's matches since it is expected
+    // to only return synchronous results. `debouncer_` used base::Unretained
+    // since it does not live beyond the scope of MostVisitedSitesProvider.
+    debouncer_->RequestRun(base::BindOnce(
+        &MostVisitedSitesProvider::RequestSitesFromHistoryService,
+        base::Unretained(this), input));
   } else {
     // TopSites updates itself after a delay. To ensure up-to-date results,
     // force an update now.
@@ -286,11 +286,29 @@
   }
 }
 
+void MostVisitedSitesProvider::StartPrefetch(const AutocompleteInput& input) {
+  AutocompleteProvider::StartPrefetch(input);
+
+  TRACE_EVENT0("omnibox", "MostVisitedProvider::StartPrefetch");
+
+  if (!AllowMostVisitedSitesSuggestions(input)) {
+    return;
+  }
+
+  if (omnibox_feature_configs::OmniboxUrlSuggestionsOnFocus::Get()
+          .MostVisitedPrefetchingEnabled()) {
+    debouncer_->RequestRun(base::BindOnce(
+        &MostVisitedSitesProvider::RequestSitesFromHistoryService,
+        base::Unretained(this), input));
+  }
+}
+
 void MostVisitedSitesProvider::Stop(bool clear_cached_results,
                                     bool due_to_user_inactivity) {
   AutocompleteProvider::Stop(clear_cached_results, due_to_user_inactivity);
   request_weak_ptr_factory_.InvalidateWeakPtrs();
   cancelable_task_tracker_.TryCancelAll();
+  debouncer_->CancelRequest();
 }
 
 MostVisitedSitesProvider::MostVisitedSitesProvider(
@@ -301,6 +319,15 @@
       client_{client} {
   AddListener(listener);
 
+  auto url_suggestions_on_focus_config =
+      omnibox_feature_configs::OmniboxUrlSuggestionsOnFocus::Get();
+  int debounce_delay =
+      url_suggestions_on_focus_config.MostVisitedPrefetchingEnabled()
+          ? url_suggestions_on_focus_config.prefetch_most_visited_sites_delay_ms
+          : 0;
+  debouncer_ = std::make_unique<AutocompleteProviderDebouncer>(
+      /*from_last_run=*/true, debounce_delay);
+
   // TopSites updates itself after a delay. To ensure up-to-date results,
   // force an update now.
   scoped_refptr<history::TopSites> top_sites = client_->GetTopSites();
@@ -454,3 +481,35 @@
     matches_.clear();
   }
 }
+
+void MostVisitedSitesProvider::RequestSitesFromHistoryService(
+    const AutocompleteInput& input) {
+  auto url_suggestions_on_focus_config =
+      omnibox_feature_configs::OmniboxUrlSuggestionsOnFocus::Get();
+  const TabMatcher& tab_matcher = client_->GetTabMatcher();
+
+  QueryMostVisitedURLsCallback callback =
+      url_suggestions_on_focus_config.MostVisitedPrefetchingEnabled()
+          ? base::BindOnce(&MostVisitedSitesProvider::UpdateCachedSites,
+                           request_weak_ptr_factory_.GetWeakPtr())
+          : base::BindOnce(&MostVisitedSitesProvider::
+                               OnMostVisitedUrlsFromHistoryAvailable,
+                           request_weak_ptr_factory_.GetWeakPtr(), input);
+
+  // The requested results size is the maximum amount of suggestions
+  // that can be shown in the omnibox in addition to the number of open tabs.
+  // Add 1 to `GetOpenTabs` since it doesn't consider the currently active tab.
+  size_t requested_result_size =
+      url_suggestions_on_focus_config.max_suggestions +
+      (tab_matcher.GetOpenTabs(&input).size() + 1);
+
+  client_->GetHistoryService()->QueryMostVisitedURLs(
+      requested_result_size, std::move(callback), &cancelable_task_tracker_,
+      url_suggestions_on_focus_config.most_visited_recency_factor,
+      url_suggestions_on_focus_config.most_visited_recency_window);
+}
+
+void MostVisitedSitesProvider::UpdateCachedSites(
+    history::MostVisitedURLList sites) {
+  cached_sites_ = std::move(sites);
+}
diff --git a/components/omnibox/browser/most_visited_sites_provider.h b/components/omnibox/browser/most_visited_sites_provider.h
index a66693b..5732eb6a 100644
--- a/components/omnibox/browser/most_visited_sites_provider.h
+++ b/components/omnibox/browser/most_visited_sites_provider.h
@@ -5,16 +5,22 @@
 #ifndef COMPONENTS_OMNIBOX_BROWSER_MOST_VISITED_SITES_PROVIDER_H_
 #define COMPONENTS_OMNIBOX_BROWSER_MOST_VISITED_SITES_PROVIDER_H_
 
+#include "base/functional/callback.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/task/cancelable_task_tracker.h"
+#include "components/history/core/browser/history_types.h"
 #include "components/omnibox/browser/autocomplete_input.h"
 #include "components/omnibox/browser/autocomplete_provider.h"
 #include "components/omnibox/browser/autocomplete_provider_client.h"
+#include "components/omnibox/browser/autocomplete_provider_debouncer.h"
 #include "components/omnibox/browser/autocomplete_provider_listener.h"
 #include "ui/base/device_form_factor.h"
 
+using QueryMostVisitedURLsCallback =
+    base::OnceCallback<void(history::MostVisitedURLList)>;
+
 // Autocomplete provider serving Most Visited Sites in zero-prefix context.
 // Serves most frequently visited URLs in a form of either individual- or
 // aggregate suggestions.
@@ -23,6 +29,8 @@
   MostVisitedSitesProvider(AutocompleteProviderClient* client,
                            AutocompleteProviderListener* listener);
 
+  // AutocompleteProvider:
+  void StartPrefetch(const AutocompleteInput& input) override;
   void Start(const AutocompleteInput& input, bool minimal_changes) override;
   void Stop(bool clear_cached_results, bool due_to_user_inactivity) override;
   void DeleteMatch(const AutocompleteMatch& match) override;
@@ -35,6 +43,10 @@
   FRIEND_TEST_ALL_PREFIXES(MostVisitedSitesProviderTest, NoSRPCoverage);
   FRIEND_TEST_ALL_PREFIXES(MostVisitedSitesProviderTest,
                            DesktopProviderDoesNotAllowChromeSites);
+  FRIEND_TEST_ALL_PREFIXES(MostVisitedSitesProviderTest,
+                           PrefetchingUpdatesCachedSites);
+  FRIEND_TEST_ALL_PREFIXES(MostVisitedSitesProviderTest,
+                           StartDoesNotUpdateMatchesWhenPrefetchEnabled);
 
   ~MostVisitedSitesProvider() override;
 
@@ -58,9 +70,25 @@
 
   void BlockURL(const GURL& site_url);
 
+  // Calls HistoryService's QueryMostVisitedURLs().
+  // Called in `StartPrefetch()` and in `Start()` by the debouncer.
+  void RequestSitesFromHistoryService(const AutocompleteInput& input);
+
+  // Updates the list of cached sites.
+  void UpdateCachedSites(history::MostVisitedURLList sites);
+
   // Task tracker for querying the most visited URLs from HistoryService.
   base::CancelableTaskTracker cancelable_task_tracker_;
 
+  // Debouncer used to throttle the frequency of calls to HistoryService's
+  // `QueryMostVisitedURLs()`.
+  std::unique_ptr<AutocompleteProviderDebouncer> debouncer_;
+
+  // `cached_sites_` stores both the prefetched sites as well as sites returned
+  // returned from subsequent queries to the history service when prefetching
+  // is enabled.
+  history::MostVisitedURLList cached_sites_;
+
   const ui::DeviceFormFactor device_form_factor_;
   const raw_ptr<AutocompleteProviderClient, DanglingUntriaged> client_;
   // Note: used to cancel requests - not a general purpose WeakPtr factory.
diff --git a/components/omnibox/browser/most_visited_sites_provider_unittest.cc b/components/omnibox/browser/most_visited_sites_provider_unittest.cc
index 9a6f40c..cdf4e89 100644
--- a/components/omnibox/browser/most_visited_sites_provider_unittest.cc
+++ b/components/omnibox/browser/most_visited_sites_provider_unittest.cc
@@ -157,6 +157,13 @@
                                   metrics::OmniboxFocusType::INTERACTION_FOCUS);
   }
 
+  // A prefetch AutocompleteInput on Web.
+  AutocompleteInput BuildAutocompletePrefetchInputForWeb() {
+    return BuildAutocompleteInput(
+        WEB_URL, WEB_URL, metrics::OmniboxEventProto::OTHER_ZPS_PREFETCH,
+        metrics::OmniboxFocusType::INTERACTION_FOCUS);
+  }
+
   // Iterate over all matches offered by the Provider and verify these against
   // the supplied list of History URLs.
   void CheckMatchesEquivalentTo(const std::vector<TestData>& data,
@@ -596,6 +603,7 @@
   scoped_config.Get().most_visited_recency_factor =
       history::kMvtScoringParamRecencyFactor_Default;
   scoped_config.Get().max_suggestions = 8;
+  scoped_config.Get().prefetch_most_visited_sites = false;
 
   history::HistoryService::QueryMostVisitedURLsCallback callback;
   EXPECT_CALL(history_service_ref, QueryMostVisitedURLs(_, _, _, _, _))
@@ -639,6 +647,7 @@
       scoped_config;
   scoped_config.Get().enabled = true;
   scoped_config.Get().max_suggestions = 8;
+  scoped_config.Get().prefetch_most_visited_sites = false;
 
   history::HistoryService::QueryMostVisitedURLsCallback callback;
   EXPECT_CALL(history_service_ref, QueryMostVisitedURLs(_, _, _, _, _))
@@ -681,4 +690,100 @@
   ASSERT_EQ(3u, provider_->matches().size());
 }
 
+TEST_F(MostVisitedSitesProviderTest, PrefetchingUpdatesCachedSites) {
+  // Set a MockHistoryService.
+  auto history_service = std::make_unique<MockHistoryService>();
+  auto& history_service_ref = *history_service;
+  client_.set_history_service(std::move(history_service));
+  omnibox_feature_configs::ScopedConfigForTesting<
+      omnibox_feature_configs::OmniboxUrlSuggestionsOnFocus>
+      scoped_config;
+  scoped_config.Get().enabled = true;
+  scoped_config.Get().max_suggestions = 8;
+  scoped_config.Get().prefetch_most_visited_sites = true;
+
+  history::HistoryService::QueryMostVisitedURLsCallback callback;
+  EXPECT_CALL(history_service_ref, QueryMostVisitedURLs(_, _, _, _, _))
+      .Times(2)
+      .WillRepeatedly(
+          [&](int result_count,
+              history::HistoryService::QueryMostVisitedURLsCallback cb,
+              base::CancelableTaskTracker* tracker,
+              std::optional<std::string> recency_factor_name,
+              std::optional<size_t> recency_window_days)
+              -> base::CancelableTaskTracker::TaskId {
+            // Add 1 to simulate 1 site being open.
+            EXPECT_EQ(static_cast<int>(scoped_config.Get().max_suggestions) + 1,
+                      result_count);
+            callback = std::move(cb);
+            return {};
+          });
+
+  AutocompleteInput input(BuildAutocompletePrefetchInputForWeb());
+  // `StartPrefetch()` shouldn't affect provider state.
+  EXPECT_TRUE(provider_->done());
+  provider_->StartPrefetch(input);
+  EXPECT_TRUE(provider_->done());
+  history::MostVisitedURLList result;
+  for (const auto& test_element : DefaultTestData()) {
+    result.push_back(test_element.entry);
+  }
+
+  std::move(callback).Run(std::move(result));
+
+  // `StartPrefetch()` should update the list of cached sites, but not
+  // update the actual provider's matches.
+  ASSERT_EQ(5u, provider_->cached_sites_.size());
+  ASSERT_EQ(0u, provider_->matches().size());
+
+  // Calling Start() should use the cached sites to create matches. Shouldn't
+  // include the SRP result.
+  provider_->Start(input, false);
+  ASSERT_EQ(4u, provider_->matches().size());
+}
+
+TEST_F(MostVisitedSitesProviderTest,
+       StartDoesNotUpdateMatchesWhenPrefetchEnabled) {
+  // Set a MockHistoryService.
+  auto history_service = std::make_unique<MockHistoryService>();
+  auto& history_service_ref = *history_service;
+  client_.set_history_service(std::move(history_service));
+  omnibox_feature_configs::ScopedConfigForTesting<
+      omnibox_feature_configs::OmniboxUrlSuggestionsOnFocus>
+      scoped_config;
+  scoped_config.Get().enabled = true;
+  scoped_config.Get().max_suggestions = 8;
+  scoped_config.Get().prefetch_most_visited_sites = true;
+
+  history::HistoryService::QueryMostVisitedURLsCallback callback;
+  EXPECT_CALL(history_service_ref, QueryMostVisitedURLs(_, _, _, _, _))
+      .WillOnce([&](int result_count,
+                    history::HistoryService::QueryMostVisitedURLsCallback cb,
+                    base::CancelableTaskTracker* tracker,
+                    std::optional<std::string> recency_factor_name,
+                    std::optional<size_t> recency_window_days)
+                    -> base::CancelableTaskTracker::TaskId {
+        // Add 1 to simulate 1 site being open.
+        EXPECT_EQ(static_cast<int>(scoped_config.Get().max_suggestions) + 1,
+                  result_count);
+        callback = std::move(cb);
+        return {};
+      });
+
+  AutocompleteInput input(BuildAutocompleteInputForWebOnFocus());
+  provider_->Start(input, false);
+  history::MostVisitedURLList result;
+  for (const auto& test_element : DefaultTestData()) {
+    result.push_back(test_element.entry);
+  }
+
+  std::move(callback).Run(std::move(result));
+
+  EXPECT_FALSE(provider_->done());
+  // `Start()` when prefetch is enabled should update the list of cached sites,
+  // but not update the actual provider's matches if the cache is empty.
+  ASSERT_EQ(5u, provider_->cached_sites_.size());
+  ASSERT_EQ(0u, provider_->matches().size());
+}
+
 #endif  // !(BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS))
diff --git a/components/omnibox/browser/omnibox_controller.cc b/components/omnibox/browser/omnibox_controller.cc
index 4a73a442..f9f613ed 100644
--- a/components/omnibox/browser/omnibox_controller.cc
+++ b/components/omnibox/browser/omnibox_controller.cc
@@ -18,6 +18,7 @@
 #include "components/omnibox/browser/omnibox_popup_view.h"
 #include "components/omnibox/browser/omnibox_prefs.h"
 #include "components/omnibox/browser/page_classification_functions.h"
+#include "components/omnibox/common/omnibox_feature_configs.h"
 #include "components/search_engines/template_url_starter_pack_data.h"
 #include "ui/gfx/geometry/rect.h"
 
@@ -83,7 +84,9 @@
   // TODO(crbug.com/406826913): Remove this check from OmniboxController and
   // fix associated tests.
   if (!OmniboxFieldTrial::IsZeroSuggestPrefetchingEnabledInContext(
-          page_classification)) {
+          page_classification) &&
+      !omnibox_feature_configs::OmniboxUrlSuggestionsOnFocus::Get()
+           .MostVisitedPrefetchingEnabled()) {
     return;
   }
 
diff --git a/components/omnibox/browser/page_classification_functions.cc b/components/omnibox/browser/page_classification_functions.cc
index a2d5e575..87bff60e 100644
--- a/components/omnibox/browser/page_classification_functions.cc
+++ b/components/omnibox/browser/page_classification_functions.cc
@@ -68,10 +68,10 @@
 
 bool SupportsMostVisitedSites(OEP::PageClassification classification) {
   if (omnibox_feature_configs::OmniboxUrlSuggestionsOnFocus::Get().enabled) {
-    // This provider doesn't actually run on SRP_ZPS_PREFETCH page
-    // classification since it doesn't implement prefetching.
     return classification == OEP::OTHER_ON_CCT ||
-           classification == OEP::OTHER || IsSearchResultsPage(classification);
+           classification == OEP::OTHER ||
+           classification == OEP::OTHER_ZPS_PREFETCH ||
+           IsSearchResultsPage(classification);
   }
 
   return classification == OEP::OTHER ||
diff --git a/components/omnibox/common/omnibox_feature_configs.cc b/components/omnibox/common/omnibox_feature_configs.cc
index 300d4cb..26d27fa 100644
--- a/components/omnibox/common/omnibox_feature_configs.cc
+++ b/components/omnibox/common/omnibox_feature_configs.cc
@@ -284,6 +284,14 @@
                                "OnFocusMostVisitedDirectlyQueryHistoryService",
                                true)
           .Get();
+  prefetch_most_visited_sites =
+      base::FeatureParam<bool>(&kOmniboxUrlSuggestionsOnFocus,
+                               "OnFocusPrefetchMostVisitedSites", true)
+          .Get();
+  prefetch_most_visited_sites_delay_ms =
+      base::FeatureParam<int>(&kOmniboxUrlSuggestionsOnFocus,
+                              "OnFocusPrefetchDelay", 300)
+          .Get();
 }
 
 OmniboxUrlSuggestionsOnFocus::OmniboxUrlSuggestionsOnFocus(
@@ -294,6 +302,10 @@
 
 OmniboxUrlSuggestionsOnFocus::~OmniboxUrlSuggestionsOnFocus() = default;
 
+bool OmniboxUrlSuggestionsOnFocus::MostVisitedPrefetchingEnabled() const {
+  return enabled && prefetch_most_visited_sites;
+}
+
 BASE_FEATURE(HappinessTrackingSurveyForOmniboxOnFocusZps::
                  kHappinessTrackingSurveyForOmniboxOnFocusZps,
              "HappinessTrackingSurveyForOmniboxOnFocusZps",
diff --git a/components/omnibox/common/omnibox_feature_configs.h b/components/omnibox/common/omnibox_feature_configs.h
index 710be50..3abd31c5 100644
--- a/components/omnibox/common/omnibox_feature_configs.h
+++ b/components/omnibox/common/omnibox_feature_configs.h
@@ -270,6 +270,13 @@
   // Whether MostVisitedProvider should directly query HistoryService for its
   // most visited sites list. False if the provider should query TopSites.
   bool directly_query_history_service;
+  // Whether to prefetch the most visited sites.
+  bool prefetch_most_visited_sites;
+  // The debouncing delay (in milliseconds) to use when throttling
+  // HistoryService requests.
+  int prefetch_most_visited_sites_delay_ms;
+
+  bool MostVisitedPrefetchingEnabled() const;
 };
 
 // Enables the HaTS for On-Focus ZPS so that it may show up for a user.
diff --git a/components/performance_manager/features.cc b/components/performance_manager/features.cc
index 4fb4dc4..f593286 100644
--- a/components/performance_manager/features.cc
+++ b/components/performance_manager/features.cc
@@ -70,6 +70,12 @@
                    "ppm_survey_max_delay",
                    base::Minutes(60));
 
+BASE_FEATURE_PARAM(bool,
+                   kPerformanceControlsPPMSurveyUniformSampleValue,
+                   &kPerformanceControlsPPMSurvey,
+                   "ppm_survey_uniform_sample",
+                   true);
+
 // Depending on platform, clients will be split into 1-3 segments based on the
 // amount of physical RAM they have. "ppm_survey_segment_name1" through
 // "ppm_survey_segment_name3" give the names of the segments, which will be
diff --git a/components/performance_manager/public/features.h b/components/performance_manager/public/features.h
index 0eb21f0..25e63b1 100644
--- a/components/performance_manager/public/features.h
+++ b/components/performance_manager/public/features.h
@@ -72,6 +72,12 @@
 BASE_DECLARE_FEATURE_PARAM(base::TimeDelta,
                            kPerformanceControlsPPMSurveyMaxDelay);
 
+// Controls whether survey responses will be tagged as "Selected For Uniform
+// Sample". The subset of responses with this tag approximate the general
+// population, no matter how many responses are received in individual segments.
+BASE_DECLARE_FEATURE_PARAM(bool,
+                           kPerformanceControlsPPMSurveyUniformSampleValue);
+
 // Defines the names and boundaries of up to 3 segments for the PPM survey.
 // There's no kPerformanceControlsPPMSurveySegmentMaxMemoryGB3 because there's
 // never a 4th segment, so segment 3 has no maximum.
diff --git a/components/plus_addresses/resources/internal b/components/plus_addresses/resources/internal
index 85e0ab9..32ee8b6 160000
--- a/components/plus_addresses/resources/internal
+++ b/components/plus_addresses/resources/internal
@@ -1 +1 @@
-Subproject commit 85e0ab9fd2d5d2c25d4593596b81d4977c60fd1a
+Subproject commit 32ee8b65a346a72e8692d112ba9304d6344e3dd6
diff --git a/components/signin/core/browser/active_primary_accounts_metrics_recorder.cc b/components/signin/core/browser/active_primary_accounts_metrics_recorder.cc
index 9a84b89..6dd5e47f 100644
--- a/components/signin/core/browser/active_primary_accounts_metrics_recorder.cc
+++ b/components/signin/core/browser/active_primary_accounts_metrics_recorder.cc
@@ -26,6 +26,12 @@
 constexpr char kActiveAccountsManagedPrefName[] =
     "signin.active_accounts_managed";
 
+#if BUILDFLAG(IS_IOS)
+// A list of timestamps of recent account switches.
+constexpr char kAccountSwitchTimestampsPrefName[] =
+    "signin.account_switch_timestamps";
+#endif  // BUILDFLAG(IS_IOS)
+
 constexpr char kTimerPrefName[] = "signin.active_accounts_last_emitted";
 
 // How often the metrics get emitted.
@@ -55,6 +61,9 @@
     PrefRegistrySimple* registry) {
   registry->RegisterDictionaryPref(kActiveAccountsPrefName);
   registry->RegisterDictionaryPref(kActiveAccountsManagedPrefName);
+#if BUILDFLAG(IS_IOS)
+  registry->RegisterListPref(kAccountSwitchTimestampsPrefName);
+#endif  // BUILDFLAG(IS_IOS)
   registry->RegisterTimePref(kTimerPrefName, base::Time());
 }
 
@@ -97,6 +106,26 @@
   managed_accounts_pref_update.Get().Set(key, is_managed_account);
 }
 
+#if BUILDFLAG(IS_IOS)
+void ActivePrimaryAccountsMetricsRecorder::AccountWasSwitched() {
+  const base::Time now = base::Time::Now();
+
+  ScopedListPrefUpdate switch_timestamps_pref_update(
+      &local_state_.get(), kAccountSwitchTimestampsPrefName);
+  switch_timestamps_pref_update->Append(base::TimeToValue(now));
+
+  // Ensure the number of entries in the pref doesn't grow unreasonably large.
+  constexpr size_t kMaxTimestamps = 100;
+  if (switch_timestamps_pref_update->size() > kMaxTimestamps) {
+    size_t entries_to_erase =
+        switch_timestamps_pref_update->size() - kMaxTimestamps;
+    switch_timestamps_pref_update->erase(
+        switch_timestamps_pref_update->begin(),
+        switch_timestamps_pref_update->begin() + entries_to_erase);
+  }
+}
+#endif  // BUILDFLAG(IS_IOS)
+
 std::optional<base::Time>
 ActivePrimaryAccountsMetricsRecorder::GetLastActiveTimeForAccount(
     const GaiaId& gaia_id) const {
@@ -159,6 +188,28 @@
         "Signin.NumberOfActiveAccounts.AnyManaged.Last28Days",
         accounts_in_28_days);
   }
+
+#if BUILDFLAG(IS_IOS)
+  int switches_in_7_days = 0;
+  int switches_in_28_days = 0;
+  const base::Value::List& account_switch_timestamps =
+      local_state_->GetList(kAccountSwitchTimestampsPrefName);
+  for (const base::Value& timestamp : account_switch_timestamps) {
+    base::Time switch_time =
+        base::ValueToTime(timestamp).value_or(base::Time());
+    if (now - switch_time <= base::Days(7)) {
+      ++switches_in_7_days;
+    }
+    if (now - switch_time <= base::Days(28)) {
+      ++switches_in_28_days;
+    }
+  }
+
+  base::UmaHistogramCounts100("Signin.IOSNumberOfAccountSwitches.Last7Days",
+                              switches_in_7_days);
+  base::UmaHistogramCounts100("Signin.IOSNumberOfAccountSwitches.Last28Days",
+                              switches_in_28_days);
+#endif  // BUILDFLAG(IS_IOS)
 }
 
 void ActivePrimaryAccountsMetricsRecorder::CleanUpExpiredEntries() {
@@ -196,6 +247,23 @@
       managed_accounts_pref_update.Get().Remove(gaia_id_hash);
     }
   }
+
+#if BUILDFLAG(IS_IOS)
+  const base::Value::List& old_timestamps =
+      local_state_->GetList(kAccountSwitchTimestampsPrefName);
+  base::Value::List new_timestamps;
+  for (const base::Value& timestamp : old_timestamps) {
+    base::Time switch_time =
+        base::ValueToTime(timestamp).value_or(base::Time());
+    if (now - switch_time <= base::Days(28)) {
+      new_timestamps.Append(timestamp.Clone());
+    }
+  }
+  if (new_timestamps.size() != old_timestamps.size()) {
+    local_state_->SetList(kAccountSwitchTimestampsPrefName,
+                          std::move(new_timestamps));
+  }
+#endif  // BUILDFLAG(IS_IOS)
 }
 
 }  // namespace signin
diff --git a/components/signin/core/browser/active_primary_accounts_metrics_recorder.h b/components/signin/core/browser/active_primary_accounts_metrics_recorder.h
index abcc111..425daee 100644
--- a/components/signin/core/browser/active_primary_accounts_metrics_recorder.h
+++ b/components/signin/core/browser/active_primary_accounts_metrics_recorder.h
@@ -40,6 +40,12 @@
   // are fine, and calls for not-recently-active accounts are no-ops.)
   void MarkAccountAsManaged(const GaiaId& gaia_id, bool is_managed_account);
 
+#if BUILDFLAG(IS_IOS)
+  // Should be called when the user explicitly switches to a different account.
+  // Used to track the number of account switches per client.
+  void AccountWasSwitched();
+#endif  // BUILDFLAG(IS_IOS)
+
   // Returns the last know active-time for the given account. If the account has
   // never been marked as active, or it was too long ago so that the entry has
   // expired, returns nullopt.
diff --git a/components/signin/core/browser/active_primary_accounts_metrics_recorder_unittest.cc b/components/signin/core/browser/active_primary_accounts_metrics_recorder_unittest.cc
index 9277363f..4ea6125 100644
--- a/components/signin/core/browser/active_primary_accounts_metrics_recorder_unittest.cc
+++ b/components/signin/core/browser/active_primary_accounts_metrics_recorder_unittest.cc
@@ -22,6 +22,10 @@
 constexpr char kActiveAccountsManagedPrefName[] =
     "signin.active_accounts_managed";
 constexpr char kTimerPrefName[] = "signin.active_accounts_last_emitted";
+#if BUILDFLAG(IS_IOS)
+constexpr char kAccountSwitchTimestampsPrefName[] =
+    "signin.account_switch_timestamps";
+#endif  // BUILDFLAG(IS_IOS)
 
 constexpr std::array<std::string_view, 4>
     kUnconditionalNumberOfActiveAccountsHistograms = {
@@ -417,6 +421,125 @@
   EXPECT_EQ(local_state_.GetDict(kActiveAccountsManagedPrefName).size(), 1u);
 }
 
+#if BUILDFLAG(IS_IOS)
+
+TEST_F(ActivePrimaryAccountsMetricsRecorderTest,
+       RecordsNumberOfAccountSwitches) {
+  // The metrics were previously recorded, and the next emission is (24-13)==11
+  // hours away.
+  local_state_.SetTime(kTimerPrefName, base::Time::Now() - base::Hours(13));
+  ActivePrimaryAccountsMetricsRecorder tracker(local_state_);
+
+  task_environment_.FastForwardBy(base::Days(1));
+  tracker.AccountWasSwitched();
+  task_environment_.FastForwardBy(base::Days(1));
+  tracker.AccountWasSwitched();
+  task_environment_.FastForwardBy(base::Days(4));
+
+  ASSERT_EQ(local_state_.GetList(kAccountSwitchTimestampsPrefName).size(), 2u);
+
+  task_environment_.FastForwardBy(base::Hours(12));
+  // The user switched from "first_gaia" to "second_gaia" 5.5 days ago, and to
+  // "third_gaia" 4.5 days ago. The next metrics emission is 23 hours away.
+
+  {
+    base::HistogramTester histograms;
+
+    task_environment_.FastForwardBy(base::Days(1));
+    // The first account switch is now 6.5 days ago, and the second 5.5 days
+    // ago.
+    histograms.ExpectUniqueSample("Signin.IOSNumberOfAccountSwitches.Last7Days",
+                                  /*sample=*/2, /*expected_bucket_count=*/1);
+    histograms.ExpectUniqueSample(
+        "Signin.IOSNumberOfAccountSwitches.Last28Days",
+        /*sample=*/2, /*expected_bucket_count=*/1);
+
+    EXPECT_EQ(local_state_.GetList(kAccountSwitchTimestampsPrefName).size(),
+              2u);
+  }
+
+  {
+    base::HistogramTester histograms;
+
+    task_environment_.FastForwardBy(base::Days(1));
+    // The first account switch is now 7.5 days ago, and the second 6.5 days
+    // ago.
+    histograms.ExpectUniqueSample("Signin.IOSNumberOfAccountSwitches.Last7Days",
+                                  /*sample=*/1, /*expected_bucket_count=*/1);
+    histograms.ExpectUniqueSample(
+        "Signin.IOSNumberOfAccountSwitches.Last28Days",
+        /*sample=*/2, /*expected_bucket_count=*/1);
+
+    EXPECT_EQ(local_state_.GetList(kAccountSwitchTimestampsPrefName).size(),
+              2u);
+  }
+
+  task_environment_.FastForwardBy(base::Days(20));
+  // The first account switch is now 27.5 days ago, and the second 26.5 days
+  // ago.
+
+  {
+    base::HistogramTester histograms;
+
+    task_environment_.FastForwardBy(base::Days(1));
+    // The first account switch is now 28.5 days ago, and the second 27.5 days
+    // ago.
+    histograms.ExpectUniqueSample("Signin.IOSNumberOfAccountSwitches.Last7Days",
+                                  /*sample=*/0, /*expected_bucket_count=*/1);
+    histograms.ExpectUniqueSample(
+        "Signin.IOSNumberOfAccountSwitches.Last28Days",
+        /*sample=*/1, /*expected_bucket_count=*/1);
+
+    EXPECT_EQ(local_state_.GetList(kAccountSwitchTimestampsPrefName).size(),
+              1u);
+  }
+
+  tracker.AccountWasSwitched();
+  {
+    base::HistogramTester histograms;
+
+    task_environment_.FastForwardBy(base::Days(1));
+    // The original two account switches are out of the 28-day window now, and
+    // only the one recent switch should be recorded.
+    histograms.ExpectUniqueSample("Signin.IOSNumberOfAccountSwitches.Last7Days",
+                                  /*sample=*/1, /*expected_bucket_count=*/1);
+    histograms.ExpectUniqueSample(
+        "Signin.IOSNumberOfAccountSwitches.Last28Days",
+        /*sample=*/1, /*expected_bucket_count=*/1);
+
+    EXPECT_EQ(local_state_.GetList(kAccountSwitchTimestampsPrefName).size(),
+              1u);
+  }
+}
+
+TEST_F(ActivePrimaryAccountsMetricsRecorderTest,
+       LimitsTrackedNumberOfSwitches) {
+  ActivePrimaryAccountsMetricsRecorder tracker(local_state_);
+
+  // A reasonable number of switches should be tracked accurately in the pref.
+  constexpr size_t kSmallNumberOfSwitches = 10;
+  for (size_t i = 0; i < kSmallNumberOfSwitches; i++) {
+    task_environment_.FastForwardBy(base::Seconds(1));
+    tracker.AccountWasSwitched();
+  }
+  EXPECT_EQ(local_state_.GetList(kAccountSwitchTimestampsPrefName).size(),
+            kSmallNumberOfSwitches);
+
+  // A very large number of switches should not be tracked in the pref anymore
+  // - there should be a limit.
+  constexpr size_t kLargeNumberOfSwitches = 200;
+  for (size_t i = 0; i < kLargeNumberOfSwitches; i++) {
+    task_environment_.FastForwardBy(base::Seconds(1));
+    tracker.AccountWasSwitched();
+  }
+  EXPECT_GT(local_state_.GetList(kAccountSwitchTimestampsPrefName).size(),
+            kSmallNumberOfSwitches);
+  EXPECT_LT(local_state_.GetList(kAccountSwitchTimestampsPrefName).size(),
+            kLargeNumberOfSwitches);
+}
+
+#endif  // BUILDFLAG(IS_IOS)
+
 }  // namespace
 
 }  // namespace signin
diff --git a/components/supervised_user/test_support/family_link_settings_state_management.h b/components/supervised_user/test_support/family_link_settings_state_management.h
index baa14d7..2f4e0e2 100644
--- a/components/supervised_user/test_support/family_link_settings_state_management.h
+++ b/components/supervised_user/test_support/family_link_settings_state_management.h
@@ -155,7 +155,7 @@
   // Sets the Advanced Setting toggles (Permissions, Extensions, Cookies) to
   // their default values.
   static FamilyLinkSettingsState SetAdvancedSettingsDefault();
-  // LINT.ThenChange(/ios/chrome/browser/ui/settings/supervised_user_family_link_app_interface.mm:TestFamilyLinkFamilyLinkSettingsStateHelper)
+  // LINT.ThenChange(/ios/chrome/browser/settings/ui_bundled/supervised_user_family_link_app_interface.mm)
   // After issuing, Permissions, Extensions and Cookies toggles are set to the
   // given values, if such a value is provided on the input list.
   static FamilyLinkSettingsState AdvancedSettingsToggles(
diff --git a/components/user_manager/test_helper.cc b/components/user_manager/test_helper.cc
index 4f245d14..59773986 100644
--- a/components/user_manager/test_helper.cc
+++ b/components/user_manager/test_helper.cc
@@ -4,6 +4,7 @@
 
 #include "components/user_manager/test_helper.h"
 
+#include "base/check_deref.h"
 #include "chromeos/ash/components/cryptohome/cryptohome_parameters.h"
 #include "chromeos/ash/components/dbus/userdataauth/userdataauth_client.h"
 #include "components/account_id/account_id.h"
@@ -91,8 +92,8 @@
       cryptohome::CreateAccountIdentifierFromAccountId(account_id));
 }
 
-TestHelper::TestHelper(UserManager& user_manager)
-    : user_manager_(user_manager) {}
+TestHelper::TestHelper(UserManager* user_manager)
+    : user_manager_(CHECK_DEREF(user_manager)) {}
 
 TestHelper::~TestHelper() = default;
 
diff --git a/components/user_manager/test_helper.h b/components/user_manager/test_helper.h
index 92558dfb..320828c 100644
--- a/components/user_manager/test_helper.h
+++ b/components/user_manager/test_helper.h
@@ -51,7 +51,8 @@
   // Valid AccountId must be used, otherwise CHECKed.
   static std::string GetFakeUsernameHash(const AccountId& account_id);
 
-  explicit TestHelper(UserManager& user_manager);
+  // `user_manager` must outlive the instance of the TestHelper.
+  explicit TestHelper(UserManager* user_manager);
   ~TestHelper();
 
   // Creates and adds a regular (persisted) user, and returns it.
diff --git a/content/browser/BACK_FORWARD_CACHE_OWNERS b/content/browser/BACK_FORWARD_CACHE_OWNERS
index 1807156..ea45364 100644
--- a/content/browser/BACK_FORWARD_CACHE_OWNERS
+++ b/content/browser/BACK_FORWARD_CACHE_OWNERS
@@ -1,3 +1,2 @@
-altimin@chromium.org
 fergal@chromium.org
 rakina@chromium.org
diff --git a/content/browser/accessibility/browser_accessibility_state_impl_unittest.cc b/content/browser/accessibility/browser_accessibility_state_impl_unittest.cc
index 0626cbf..1f5323cb 100644
--- a/content/browser/accessibility/browser_accessibility_state_impl_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_state_impl_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "content/public/test/browser_task_environment.h"
+#include "content/public/test/scoped_accessibility_mode_override.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/accessibility/accessibility_features.h"
@@ -40,11 +41,6 @@
     state_ = BrowserAccessibilityStateImpl::GetInstance();
   }
 
-  void TearDown() override {
-    // Disable accessibility so that it does not impact subsequent tests.
-    state_->DisableProcessAccessibility();
-  }
-
   base::test::ScopedFeatureList scoped_feature_list_;
   raw_ptr<BrowserAccessibilityStateImpl> state_;
   BrowserTaskEnvironment task_environment_{
@@ -55,87 +51,12 @@
 };
 
 TEST_F(BrowserAccessibilityStateImplTest,
-       DisableAccessibilityBasedOnUserEvents) {
-  base::HistogramTester histograms;
-
-  // Initially, accessibility should be disabled.
-  EXPECT_EQ(ui::AXPlatform::GetInstance().GetMode(), ui::AXMode());
-
-  // Enable accessibility based on usage of accessibility APIs.
-  state_->EnableProcessAccessibility();
-  // Indicate that an actual screen reader is not running (a screen reader
-  // will prevent auto-disable from taking place).
-  state_->SetScreenReaderAppActive(false);
-  EXPECT_EQ(ui::AXPlatform::GetInstance().GetMode(), ui::kAXModeComplete);
-
-  // Send user input, wait 31 seconds, then send another user input event.
-  // Don't simulate any accessibility APIs in that time.
-  state_->OnUserInputEvent();
-  state_->OnUserInputEvent();
-  task_environment_.FastForwardBy(base::Seconds(31));
-  state_->OnUserInputEvent();
-
-  // Accessibility should now be disabled.
-  EXPECT_EQ(ui::AXPlatform::GetInstance().GetMode(), ui::AXMode());
-
-  // A histogram should record that accessibility was disabled with
-  // 3 input events.
-  histograms.ExpectUniqueSample("Accessibility.AutoDisabled.EventCount", 3, 1);
-
-  // A histogram should record that accessibility was enabled for
-  // 31 seconds.
-  histograms.ExpectUniqueTimeSample("Accessibility.AutoDisabled.EnabledTime",
-                                    base::Seconds(31), 1);
-}
-
-TEST_F(BrowserAccessibilityStateImplTest,
-       AccessibilityApiUsagePreventsAutoDisableAccessibility) {
-  // Initially, accessibility should be disabled.
-  EXPECT_EQ(ui::AXPlatform::GetInstance().GetMode(), ui::AXMode());
-
-  // Enable accessibility based on usage of accessibility APIs.
-  state_->EnableProcessAccessibility();
-  // Indicate that an actual screen reader is not running (a screen reader
-  // will prevent auto-disable from taking place).
-  state_->SetScreenReaderAppActive(false);
-  EXPECT_EQ(ui::AXPlatform::GetInstance().GetMode(), ui::kAXModeComplete);
-
-  // Send user input, wait 31 seconds, then send another user input event -
-  // but simulate accessibility APIs in that time.
-  state_->OnUserInputEvent();
-  state_->OnUserInputEvent();
-  task_environment_.FastForwardBy(base::Seconds(31));
-  state_->OnAccessibilityApiUsage();
-  state_->OnUserInputEvent();
-
-  // Accessibility should still be enabled.
-  EXPECT_EQ(ui::AXPlatform::GetInstance().GetMode(), ui::kAXModeComplete);
-
-  // Same test, but simulate accessibility API usage after the first
-  // user input event, before the delay.
-  state_->OnUserInputEvent();
-  state_->OnAccessibilityApiUsage();
-  task_environment_.FastForwardBy(base::Seconds(31));
-  state_->OnUserInputEvent();
-  state_->OnUserInputEvent();
-
-  // Accessibility should still be enabled.
-  EXPECT_EQ(ui::AXPlatform::GetInstance().GetMode(), ui::kAXModeComplete);
-
-  // Advance another 31 seconds and simulate another user input event;
-  // now accessibility should be disabled.
-  task_environment_.FastForwardBy(base::Seconds(31));
-  state_->OnUserInputEvent();
-  EXPECT_EQ(ui::AXPlatform::GetInstance().GetMode(), ui::AXMode());
-}
-
-TEST_F(BrowserAccessibilityStateImplTest,
        AddAccessibilityModeFlagsPreventsAutoDisableAccessibility) {
   // Initially, accessibility should be disabled.
   EXPECT_EQ(ui::AXPlatform::GetInstance().GetMode(), ui::AXMode());
 
   // Enable accessibility.
-  state_->EnableProcessAccessibility();
+  ScopedAccessibilityModeOverride scoped_mode(ui::kAXModeComplete);
   // Indicate that an actual screen reader is not running (a screen reader
   // will prevent auto-disable from taking place).
   state_->SetScreenReaderAppActive(false);
@@ -181,7 +102,7 @@
   EXPECT_EQ(ui::AXPlatform::GetInstance().GetMode(), ui::AXMode());
 
   // Enable accessibility.
-  state_->EnableProcessAccessibility();
+  ScopedAccessibilityModeOverride scoped_mode(ui::kAXModeComplete);
   EXPECT_EQ(ui::AXPlatform::GetInstance().GetMode(), ui::kAXModeComplete);
 
   // Send user input, wait 31 seconds, then send another user input event after
@@ -218,11 +139,11 @@
 
   // Enable accessibility.
   EXPECT_CALL(mock_observer, OnAXModeAdded(ui::kAXModeComplete));
-  state_->EnableProcessAccessibility();
+  ScopedAccessibilityModeOverride scoped_mode(ui::kAXModeComplete);
   ::testing::Mock::VerifyAndClearExpectations(&mock_observer);
 
   // A second call should be a no-op.
-  state_->EnableProcessAccessibility();
+  ScopedAccessibilityModeOverride scoped_mode_2(ui::kAXModeComplete);
   ::testing::Mock::VerifyAndClearExpectations(&mock_observer);
 }
 
diff --git a/content/browser/preloading/prefetch/prefetch_container.h b/content/browser/preloading/prefetch/prefetch_container.h
index 0a8a6680..c8432aa 100644
--- a/content/browser/preloading/prefetch/prefetch_container.h
+++ b/content/browser/preloading/prefetch/prefetch_container.h
@@ -270,6 +270,11 @@
   // prefetch exists.
   bool HasSpeculationRulesTags() { return speculation_rules_tags_.has_value(); }
 
+  // Returns the serialized string of speculation rules tags.
+  std::optional<std::string> GetSpeculationRulesTagsHeaderString() {
+    return speculation_rules_tags_->ConvertStringToHeaderString();
+  }
+
   // The type of this prefetch. Controls how the prefetch is handled.
   const PrefetchType& GetPrefetchType() const { return prefetch_type_; }
 
diff --git a/content/browser/preloading/prefetch/prefetch_service_unittest.cc b/content/browser/preloading/prefetch/prefetch_service_unittest.cc
index cf04e14..23895dda 100644
--- a/content/browser/preloading/prefetch/prefetch_service_unittest.cc
+++ b/content/browser/preloading/prefetch/prefetch_service_unittest.cc
@@ -116,6 +116,49 @@
 </html>
 )";
 
+// Param for parametrized tests for rearchitecturing/refactoring of
+// `PrefetchService`.
+//
+// Do not remove and keep it even if there is no param to make it easy to add
+// another param in the future.
+struct PrefetchServiceRearchParam {
+ public:
+  using Arg = int;
+
+  static std::vector<PrefetchServiceRearchParam::Arg> Params();
+  static PrefetchServiceRearchParam CreateFromIndex(int index);
+};
+
+// static
+std::vector<int> PrefetchServiceRearchParam::Params() {
+  return {0};
+}
+
+// static
+PrefetchServiceRearchParam PrefetchServiceRearchParam::CreateFromIndex(
+    int index) {
+  std::vector<PrefetchServiceRearchParam> params = {
+      PrefetchServiceRearchParam{},
+  };
+  return params[index];
+}
+
+class WithPrefetchServiceRearchParam {
+ public:
+  explicit WithPrefetchServiceRearchParam(int index)
+      : param_(PrefetchServiceRearchParam::CreateFromIndex(index)) {}
+  virtual ~WithPrefetchServiceRearchParam() = default;
+
+  void InitRearchFeatures();
+
+  const PrefetchServiceRearchParam& rearch_param() { return param_; }
+
+ private:
+  PrefetchServiceRearchParam param_;
+};
+
+void WithPrefetchServiceRearchParam::InitRearchFeatures() {}
+
 class ScopedPrefetchServiceContentBrowserClient
     : public TestContentBrowserClient {
  public:
@@ -1160,10 +1203,20 @@
       variations::VariationsIdsProvider::Mode::kIgnoreSignedInState};
 };
 
-class PrefetchServiceTest : public PrefetchServiceTestBase {
+class PrefetchServiceTest
+    : public PrefetchServiceTestBase,
+      public WithPrefetchServiceRearchParam,
+      public ::testing::WithParamInterface<PrefetchServiceRearchParam::Arg> {
+ public:
+  PrefetchServiceTest() : WithPrefetchServiceRearchParam(GetParam()) {}
 };
 
-TEST_F(PrefetchServiceTest, SuccessCase) {
+INSTANTIATE_TEST_SUITE_P(
+    ParametrizedTests,
+    PrefetchServiceTest,
+    testing::ValuesIn(PrefetchServiceRearchParam::Params()));
+
+TEST_P(PrefetchServiceTest, SuccessCase) {
   base::HistogramTester histogram_tester;
 
   MakePrefetchService(
@@ -1201,7 +1254,7 @@
         false, 1);
 }
 
-TEST_F(PrefetchServiceTest, SuccessCase_Browser) {
+TEST_P(PrefetchServiceTest, SuccessCase_Browser) {
   base::test::ScopedFeatureList scoped_feature_list(
       features::kPrefetchBrowserInitiatedTriggers);
   base::HistogramTester histogram_tester;
@@ -1268,7 +1321,7 @@
             GURL("https://example.com/?b=1"));
 }
 
-TEST_F(PrefetchServiceTest, SuccessCase_Browser_NoVarySearch) {
+TEST_P(PrefetchServiceTest, SuccessCase_Browser_NoVarySearch) {
   base::test::ScopedFeatureList scoped_feature_list(
       features::kPrefetchBrowserInitiatedTriggers);
   base::HistogramTester histogram_tester;
@@ -1339,7 +1392,7 @@
             GURL("https://example.com/?a=1"));
 }
 
-TEST_F(PrefetchServiceTest, FailureCase_Browser_ServerErrorResponseCode) {
+TEST_P(PrefetchServiceTest, FailureCase_Browser_ServerErrorResponseCode) {
   base::test::ScopedFeatureList scoped_feature_list(
       features::kPrefetchBrowserInitiatedTriggers);
   base::HistogramTester histogram_tester;
@@ -1396,7 +1449,7 @@
   EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com?b=1")));
 }
 
-TEST_F(PrefetchServiceTest, FailureCase_Browser_NetError) {
+TEST_P(PrefetchServiceTest, FailureCase_Browser_NetError) {
   base::HistogramTester histogram_tester;
   MakePrefetchService(
       std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>(
@@ -1441,7 +1494,7 @@
   EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com?c=1")));
 }
 
-TEST_F(PrefetchServiceTest, FailureCase_Browser_NotEligibleNonHttps) {
+TEST_P(PrefetchServiceTest, FailureCase_Browser_NotEligibleNonHttps) {
   base::HistogramTester histogram_tester;
   MakePrefetchService(
       std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>(
@@ -1483,7 +1536,7 @@
   EXPECT_FALSE(GetPrefetchToServe(GURL("http://example.com")));
 }
 
-TEST_F(PrefetchServiceTest, BrowserContextPrefetchRespectsTTL) {
+TEST_P(PrefetchServiceTest, BrowserContextPrefetchRespectsTTL) {
   base::HistogramTester histogram_tester;
   MakePrefetchService(
       std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>(
@@ -1527,7 +1580,7 @@
   EXPECT_FALSE(serveable_reader);
 }
 
-TEST_F(PrefetchServiceTest, PrefetchDoesNotMatchIfDocumentTokenDoesNotMatch) {
+TEST_P(PrefetchServiceTest, PrefetchDoesNotMatchIfDocumentTokenDoesNotMatch) {
   base::HistogramTester histogram_tester;
 
   MakePrefetchService(
@@ -1556,7 +1609,7 @@
                                   different_document_token));
 }
 
-TEST_F(PrefetchServiceTest, SuccessCase_Embedder) {
+TEST_P(PrefetchServiceTest, SuccessCase_Embedder) {
   base::test::ScopedFeatureList scoped_feature_list(
       features::kPrefetchBrowserInitiatedTriggers);
 
@@ -1602,7 +1655,7 @@
       "PrefetchProxy.AfterClick.RedirectChainSize", 1, 1);
 }
 
-TEST_F(PrefetchServiceTest,
+TEST_P(PrefetchServiceTest,
        PrefetchDoesNotMatchIfDocumentTokenDoesNotMatch_Embedder) {
   base::test::ScopedFeatureList scoped_feature_list(
       features::kPrefetchBrowserInitiatedTriggers);
@@ -1647,7 +1700,7 @@
       GetPrefetchToServe(GURL("https://example.com"), MainDocumentToken()));
 }
 
-TEST_F(PrefetchServiceTest, NoPrefetchingPreloadingDisabled) {
+TEST_P(PrefetchServiceTest, NoPrefetchingPreloadingDisabled) {
   base::HistogramTester histogram_tester;
 
   std::unique_ptr<MockPrefetchServiceDelegate> mock_prefetch_service_delegate =
@@ -1682,7 +1735,7 @@
   ExpectServingMetrics(PrefetchStatus::kPrefetchIneligiblePreloadingDisabled);
 }
 
-TEST_F(PrefetchServiceTest, NoPrefetchingDomainNotInAllowList) {
+TEST_P(PrefetchServiceTest, NoPrefetchingDomainNotInAllowList) {
   base::HistogramTester histogram_tester;
 
   std::unique_ptr<MockPrefetchServiceDelegate> mock_prefetch_service_delegate =
@@ -1721,8 +1774,14 @@
   EXPECT_FALSE(serving_page_metrics->prefetch_status);
 }
 
-class PrefetchServiceAllowAllDomainsTest : public PrefetchServiceTestBase {
+class PrefetchServiceAllowAllDomainsTest
+    : public PrefetchServiceTestBase,
+      public WithPrefetchServiceRearchParam,
+      public ::testing::WithParamInterface<PrefetchServiceRearchParam::Arg> {
  public:
+  PrefetchServiceAllowAllDomainsTest()
+      : WithPrefetchServiceRearchParam(GetParam()) {}
+
   void InitScopedFeatureList() override {
     scoped_feature_list_.InitWithFeaturesAndParameters(
         {{features::kPrefetchUseContentRefactor,
@@ -1730,10 +1789,16 @@
            {"prefetch_container_lifetime_s", "-1"},
            {"allow_all_domains", "true"}}}},
         {});
+    InitRearchFeatures();
   }
 };
 
-TEST_F(PrefetchServiceAllowAllDomainsTest, AllowAllDomains) {
+INSTANTIATE_TEST_SUITE_P(
+    ParametrizedTests,
+    PrefetchServiceAllowAllDomainsTest,
+    testing::ValuesIn(PrefetchServiceRearchParam::Params()));
+
+TEST_P(PrefetchServiceAllowAllDomainsTest, AllowAllDomains) {
   base::HistogramTester histogram_tester;
 
   std::unique_ptr<MockPrefetchServiceDelegate> mock_prefetch_service_delegate =
@@ -1768,8 +1833,13 @@
 }
 
 class PrefetchServiceAllowAllDomainsForExtendedPreloadingTest
-    : public PrefetchServiceTestBase {
+    : public PrefetchServiceTestBase,
+      public WithPrefetchServiceRearchParam,
+      public ::testing::WithParamInterface<PrefetchServiceRearchParam::Arg> {
  public:
+  PrefetchServiceAllowAllDomainsForExtendedPreloadingTest()
+      : WithPrefetchServiceRearchParam(GetParam()) {}
+
   void InitScopedFeatureList() override {
     scoped_feature_list_.InitWithFeaturesAndParameters(
         {{features::kPrefetchUseContentRefactor,
@@ -1777,10 +1847,16 @@
            {"prefetch_container_lifetime_s", "-1"},
            {"allow_all_domains_for_extended_preloading", "true"}}}},
         {});
+    InitRearchFeatures();
   }
 };
 
-TEST_F(PrefetchServiceAllowAllDomainsForExtendedPreloadingTest,
+INSTANTIATE_TEST_SUITE_P(
+    ParametrizedTests,
+    PrefetchServiceAllowAllDomainsForExtendedPreloadingTest,
+    testing::ValuesIn(PrefetchServiceRearchParam::Params()));
+
+TEST_P(PrefetchServiceAllowAllDomainsForExtendedPreloadingTest,
        ExtendedPreloadingEnabled) {
   base::HistogramTester histogram_tester;
 
@@ -1817,7 +1893,7 @@
   ExpectServingMetricsSuccess();
 }
 
-TEST_F(PrefetchServiceAllowAllDomainsForExtendedPreloadingTest,
+TEST_P(PrefetchServiceAllowAllDomainsForExtendedPreloadingTest,
        ExtendedPreloadingDisabled) {
   base::HistogramTester histogram_tester;
 
@@ -1857,7 +1933,7 @@
   EXPECT_FALSE(serving_page_metrics->prefetch_status);
 }
 
-TEST_F(PrefetchServiceTest, NonProxiedPrefetchDoesNotRequireAllowList) {
+TEST_P(PrefetchServiceTest, NonProxiedPrefetchDoesNotRequireAllowList) {
   NavigationSimulator::NavigateAndCommitFromBrowser(
       web_contents(), GURL("https://example.com/referrer"));
   base::HistogramTester histogram_tester;
@@ -1894,7 +1970,7 @@
   ExpectServingMetricsSuccess(/*required_private_prefetch_proxy=*/false);
 }
 
-TEST_F(PrefetchServiceTest, NotEligibleHostnameNonUnique) {
+TEST_P(PrefetchServiceTest, NotEligibleHostnameNonUnique) {
   base::HistogramTester histogram_tester;
 
   MakePrefetchService(
@@ -1923,7 +1999,7 @@
   ExpectServingMetrics(PrefetchStatus::kPrefetchIneligibleHostIsNonUnique);
 }
 
-TEST_F(PrefetchServiceTest, NotEligibleDataSaverEnabled) {
+TEST_P(PrefetchServiceTest, NotEligibleDataSaverEnabled) {
   base::HistogramTester histogram_tester;
 
   std::unique_ptr<MockPrefetchServiceDelegate> mock_prefetch_service_delegate =
@@ -1958,7 +2034,7 @@
   ExpectServingMetrics(PrefetchStatus::kPrefetchIneligibleDataSaverEnabled);
 }
 
-TEST_F(PrefetchServiceTest, NotEligibleNonHttps) {
+TEST_P(PrefetchServiceTest, NotEligibleNonHttps) {
   base::HistogramTester histogram_tester;
 
   MakePrefetchService(
@@ -1984,7 +2060,7 @@
   ExpectServingMetrics(PrefetchStatus::kPrefetchIneligibleSchemeIsNotHttps);
 }
 
-TEST_F(PrefetchServiceTest, NotEligiblePrefetchProxyNotAvailable) {
+TEST_P(PrefetchServiceTest, NotEligiblePrefetchProxyNotAvailable) {
   base::HistogramTester histogram_tester;
 
   std::unique_ptr<MockPrefetchServiceDelegate> mock_prefetch_service_delegate =
@@ -2019,7 +2095,7 @@
       PrefetchStatus::kPrefetchIneligiblePrefetchProxyNotAvailable);
 }
 
-TEST_F(PrefetchServiceTest,
+TEST_P(PrefetchServiceTest,
        EligiblePrefetchProxyNotAvailableNonProxiedPrefetch) {
   base::HistogramTester histogram_tester;
 
@@ -2053,7 +2129,7 @@
   ExpectServingMetricsSuccess(/*required_private_prefetch_proxy=*/false);
 }
 
-TEST_F(PrefetchServiceTest, NotEligibleOriginWithinRetryAfterWindow) {
+TEST_P(PrefetchServiceTest, NotEligibleOriginWithinRetryAfterWindow) {
   base::HistogramTester histogram_tester;
 
   std::unique_ptr<MockPrefetchServiceDelegate> mock_prefetch_service_delegate =
@@ -2086,7 +2162,7 @@
   ExpectServingMetrics(PrefetchStatus::kPrefetchIneligibleRetryAfter);
 }
 
-TEST_F(PrefetchServiceTest, EligibleNonHttpsNonProxiedPotentiallyTrustworthy) {
+TEST_P(PrefetchServiceTest, EligibleNonHttpsNonProxiedPotentiallyTrustworthy) {
   base::HistogramTester histogram_tester;
 
   MakePrefetchService(
@@ -2111,7 +2187,7 @@
   ExpectServingMetricsSuccess(/*required_private_prefetch_proxy=*/false);
 }
 
-TEST_F(PrefetchServiceTest, NotEligibleServiceWorkerRegistered) {
+TEST_P(PrefetchServiceTest, NotEligibleServiceWorkerRegistered) {
   base::HistogramTester histogram_tester;
 
   MakePrefetchService(
@@ -2143,7 +2219,7 @@
   ExpectServingMetrics(PrefetchStatus::kPrefetchIneligibleUserHasServiceWorker);
 }
 
-TEST_F(PrefetchServiceTest,
+TEST_P(PrefetchServiceTest,
        NotEligibleServiceWorkerRegisteredServiceWorkerCheckUKM) {
   // ukm::TestAutoSetUkmRecorder ukm_recorder;
   MakePrefetchService(
@@ -2197,7 +2273,7 @@
               kServiceWorkerRegisteredCheckDurationBucketSpacing));
 }
 
-TEST_F(PrefetchServiceTest, EligibleServiceWorkerNotRegistered) {
+TEST_P(PrefetchServiceTest, EligibleServiceWorkerNotRegistered) {
   base::HistogramTester histogram_tester;
 
   MakePrefetchService(
@@ -2229,7 +2305,7 @@
   ExpectServingMetricsSuccess();
 }
 
-TEST_F(PrefetchServiceTest,
+TEST_P(PrefetchServiceTest,
        EligibleServiceWorkerNotRegisteredServiceWorkerCheckUKM) {
   MakePrefetchService(
       std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>());
@@ -2285,7 +2361,7 @@
                  kServiceWorkerRegisteredCheckDurationBucketSpacing));
 }
 
-TEST_F(PrefetchServiceTest, EligibleServiceWorkerRegistered) {
+TEST_P(PrefetchServiceTest, EligibleServiceWorkerRegistered) {
   base::HistogramTester histogram_tester;
 
   MakePrefetchService(
@@ -2317,7 +2393,7 @@
   ExpectServingMetricsSuccess();
 }
 
-TEST_F(PrefetchServiceTest,
+TEST_P(PrefetchServiceTest,
        EligibleServiceWorkerRegisteredServiceWorkerCheckUKM) {
   ukm::TestAutoSetUkmRecorder ukm_recorder;
   MakePrefetchService(
@@ -2372,7 +2448,7 @@
               kServiceWorkerRegisteredCheckDurationBucketSpacing));
 }
 
-TEST_F(PrefetchServiceTest, EligibleServiceWorkerNotRegisteredAtThisPath) {
+TEST_P(PrefetchServiceTest, EligibleServiceWorkerNotRegisteredAtThisPath) {
   base::HistogramTester histogram_tester;
 
   MakePrefetchService(
@@ -2405,7 +2481,7 @@
   ExpectServingMetricsSuccess();
 }
 
-TEST_F(PrefetchServiceTest, NotEligibleUserHasCookies) {
+TEST_P(PrefetchServiceTest, NotEligibleUserHasCookies) {
   base::HistogramTester histogram_tester;
 
   MakePrefetchService(
@@ -2433,7 +2509,7 @@
   ExpectServingMetrics(PrefetchStatus::kPrefetchIneligibleUserHasCookies);
 }
 
-TEST_F(PrefetchServiceTest, EligibleUserHasCookiesForDifferentUrl) {
+TEST_P(PrefetchServiceTest, EligibleUserHasCookiesForDifferentUrl) {
   base::HistogramTester histogram_tester;
 
   MakePrefetchService(
@@ -2461,7 +2537,7 @@
   ExpectServingMetricsSuccess();
 }
 
-TEST_F(PrefetchServiceTest, EligibleSameOriginPrefetchCanHaveExistingCookies) {
+TEST_P(PrefetchServiceTest, EligibleSameOriginPrefetchCanHaveExistingCookies) {
   NavigationSimulator::NavigateAndCommitFromBrowser(
       web_contents(), GURL("https://example.com/referrer"));
   base::HistogramTester histogram_tester;
@@ -2491,7 +2567,7 @@
 }
 
 // TODO(crbug.com/40249481): Test flaky on trybots.
-TEST_F(PrefetchServiceTest,
+TEST_P(PrefetchServiceTest,
        DISABLED_CHROMEOS(FailedCookiesChangedAfterPrefetchStarted)) {
   base::HistogramTester histogram_tester;
 
@@ -2553,7 +2629,7 @@
 }
 
 // TODO(crbug.com/40249481): Test flaky on trybots.
-TEST_F(PrefetchServiceTest,
+TEST_P(PrefetchServiceTest,
        DISABLED_CHROMEOS(SameOriginPrefetchIgnoresProxyRequirement)) {
   NavigationSimulator::NavigateAndCommitFromBrowser(
       web_contents(), GURL("https://example.com/referrer"));
@@ -2587,7 +2663,7 @@
 }
 
 // TODO(crbug.com/40249481): Test flaky on trybots.
-TEST_F(PrefetchServiceTest,
+TEST_P(PrefetchServiceTest,
        DISABLED_CHROMEOS(NotEligibleSameSiteCrossOriginPrefetchRequiresProxy)) {
   NavigationSimulator::NavigateAndCommitFromBrowser(
       web_contents(), GURL("https://example.com/referrer"));
@@ -2623,7 +2699,7 @@
           kPrefetchIneligibleSameSiteCrossOriginPrefetchRequiredProxy);
 }
 
-TEST_F(PrefetchServiceTest, NotEligibleExistingConnectProxy) {
+TEST_P(PrefetchServiceTest, NotEligibleExistingConnectProxy) {
   base::HistogramTester histogram_tester;
 
   MakePrefetchService(
@@ -2657,7 +2733,7 @@
   PrefetchService::SetNetworkContextForProxyLookupForTesting(nullptr);
 }
 
-TEST_F(PrefetchServiceTest, EligibleExistingConnectProxyButSameOriginPrefetch) {
+TEST_P(PrefetchServiceTest, EligibleExistingConnectProxyButSameOriginPrefetch) {
   NavigationSimulator::NavigateAndCommitFromBrowser(
       web_contents(), GURL("https://example.com/referrer"));
   base::HistogramTester histogram_tester;
@@ -2692,7 +2768,7 @@
   PrefetchService::SetNetworkContextForProxyLookupForTesting(nullptr);
 }
 
-TEST_F(PrefetchServiceTest, FailedNon2XXResponseCode) {
+TEST_P(PrefetchServiceTest, FailedNon2XXResponseCode) {
   base::HistogramTester histogram_tester;
 
   MakePrefetchService(
@@ -2721,7 +2797,7 @@
                        /*prefetch_header_latency=*/true);
 }
 
-TEST_F(PrefetchServiceTest, FailedNetError) {
+TEST_P(PrefetchServiceTest, FailedNetError) {
   base::HistogramTester histogram_tester;
 
   MakePrefetchService(
@@ -2747,7 +2823,7 @@
   ExpectServingMetrics(PrefetchStatus::kPrefetchFailedNetError);
 }
 
-TEST_F(PrefetchServiceTest, HandleRetryAfterResponse) {
+TEST_P(PrefetchServiceTest, HandleRetryAfterResponse) {
   base::HistogramTester histogram_tester;
 
   std::unique_ptr<MockPrefetchServiceDelegate> mock_prefetch_service_delegate =
@@ -2786,7 +2862,7 @@
                        /*prefetch_header_latency=*/true);
 }
 
-TEST_F(PrefetchServiceTest, SuccessNonHTML) {
+TEST_P(PrefetchServiceTest, SuccessNonHTML) {
   base::HistogramTester histogram_tester;
 
   MakePrefetchService(
@@ -2818,7 +2894,7 @@
 // the cookies for the prefetched URL. It then creates two NavigationRequests
 // (to the same URL) and calls GetPrefetchToServe for each request. This can
 // happen in practice when a user clicks on a link to a URL twice).
-TEST_F(PrefetchServiceTest,
+TEST_P(PrefetchServiceTest,
        MultipleNavigationRequestsCallGetPrefetchAfterCookieChange) {
   MakePrefetchService(
       std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>());
@@ -2858,7 +2934,7 @@
   EXPECT_FALSE(future_2.Get().GetPrefetchContainer());
 }
 
-TEST_F(PrefetchServiceTest, NotServeableNavigationInDifferentRenderFrameHost) {
+TEST_P(PrefetchServiceTest, NotServeableNavigationInDifferentRenderFrameHost) {
   base::HistogramTester histogram_tester;
 
   MakePrefetchService(
@@ -2895,8 +2971,14 @@
   EXPECT_FALSE(serving_page_metrics);
 }
 
-class PrefetchServiceWithHTMLOnlyTest : public PrefetchServiceTestBase {
+class PrefetchServiceWithHTMLOnlyTest
+    : public PrefetchServiceTestBase,
+      public WithPrefetchServiceRearchParam,
+      public ::testing::WithParamInterface<PrefetchServiceRearchParam::Arg> {
  public:
+  PrefetchServiceWithHTMLOnlyTest()
+      : WithPrefetchServiceRearchParam(GetParam()) {}
+
   void InitScopedFeatureList() override {
     scoped_feature_list_.InitWithFeaturesAndParameters(
         {{features::kPrefetchUseContentRefactor,
@@ -2904,10 +2986,16 @@
            {"prefetch_container_lifetime_s", "-1"},
            {"html_only", "true"}}}},
         {});
+    InitRearchFeatures();
   }
 };
 
-TEST_F(PrefetchServiceWithHTMLOnlyTest, FailedNonHTMLWithHTMLOnly) {
+INSTANTIATE_TEST_SUITE_P(
+    ParametrizedTests,
+    PrefetchServiceWithHTMLOnlyTest,
+    testing::ValuesIn(PrefetchServiceRearchParam::Params()));
+
+TEST_P(PrefetchServiceWithHTMLOnlyTest, FailedNonHTMLWithHTMLOnly) {
   base::HistogramTester histogram_tester;
 
   MakePrefetchService(
@@ -2939,18 +3027,29 @@
 }
 
 class PrefetchServiceAlwaysMakeDecoyRequestTest
-    : public PrefetchServiceTestBase {
+    : public PrefetchServiceTestBase,
+      public WithPrefetchServiceRearchParam,
+      public ::testing::WithParamInterface<PrefetchServiceRearchParam::Arg> {
  public:
+  PrefetchServiceAlwaysMakeDecoyRequestTest()
+      : WithPrefetchServiceRearchParam(GetParam()) {}
+
   void InitScopedFeatureList() override {
     scoped_feature_list_.InitWithFeaturesAndParameters(
         {{features::kPrefetchUseContentRefactor,
           {{"ineligible_decoy_request_probability", "1"},
            {"prefetch_container_lifetime_s", "-1"}}}},
         {});
+    InitRearchFeatures();
   }
 };
 
-TEST_F(PrefetchServiceAlwaysMakeDecoyRequestTest, DecoyRequest) {
+INSTANTIATE_TEST_SUITE_P(
+    ParametrizedTests,
+    PrefetchServiceAlwaysMakeDecoyRequestTest,
+    testing::ValuesIn(PrefetchServiceRearchParam::Params()));
+
+TEST_P(PrefetchServiceAlwaysMakeDecoyRequestTest, DecoyRequest) {
   base::HistogramTester histogram_tester;
 
   MakePrefetchService(
@@ -2981,7 +3080,7 @@
                        /*prefetch_header_latency=*/true);
 }
 
-TEST_F(PrefetchServiceAlwaysMakeDecoyRequestTest,
+TEST_P(PrefetchServiceAlwaysMakeDecoyRequestTest,
        NavigateBeforeDecoyResponseReceived) {
   base::HistogramTester histogram_tester;
 
@@ -3006,7 +3105,7 @@
   ExpectCorrectUkmLogs({.outcome = PreloadingTriggeringOutcome::kUnspecified});
 }
 
-TEST_F(PrefetchServiceAlwaysMakeDecoyRequestTest,
+TEST_P(PrefetchServiceAlwaysMakeDecoyRequestTest,
        NoDecoyRequestDisableDecoysBasedOnUserSettings) {
   base::HistogramTester histogram_tester;
 
@@ -3039,7 +3138,7 @@
 }
 
 // TODO(crbug.com/40249481): Test flaky on trybots.
-TEST_F(PrefetchServiceAlwaysMakeDecoyRequestTest,
+TEST_P(PrefetchServiceAlwaysMakeDecoyRequestTest,
        DISABLED_CHROMEOS(RedirectDecoyRequest)) {
   base::HistogramTester histogram_tester;
 
@@ -3091,7 +3190,18 @@
                        /*prefetch_header_latency=*/true);
 }
 
-class PrefetchServiceIncognitoTest : public PrefetchServiceTestBase {
+class PrefetchServiceIncognitoTest
+    : public PrefetchServiceTestBase,
+      public WithPrefetchServiceRearchParam,
+      public ::testing::WithParamInterface<PrefetchServiceRearchParam::Arg> {
+ public:
+  PrefetchServiceIncognitoTest() : WithPrefetchServiceRearchParam(GetParam()) {}
+
+  void InitScopedFeatureList() override {
+    PrefetchServiceTestBase::InitScopedFeatureList();
+    InitRearchFeatures();
+  }
+
  protected:
   std::unique_ptr<BrowserContext> CreateBrowserContext() override {
     auto browser_context = std::make_unique<TestBrowserContext>();
@@ -3100,7 +3210,12 @@
   }
 };
 
-TEST_F(PrefetchServiceIncognitoTest, OffTheRecordEligible) {
+INSTANTIATE_TEST_SUITE_P(
+    ParametrizedTests,
+    PrefetchServiceIncognitoTest,
+    testing::ValuesIn(PrefetchServiceRearchParam::Params()));
+
+TEST_P(PrefetchServiceIncognitoTest, OffTheRecordEligible) {
   base::HistogramTester histogram_tester;
 
   MakePrefetchService(
@@ -3119,7 +3234,7 @@
   ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody));
 }
 
-TEST_F(PrefetchServiceTest, NonDefaultStoragePartition) {
+TEST_P(PrefetchServiceTest, NonDefaultStoragePartition) {
   base::HistogramTester histogram_tester;
 
   MakePrefetchService(
@@ -3150,7 +3265,7 @@
 }
 
 // TODO(crbug.com/40249481): Test flaky on trybots.
-TEST_F(PrefetchServiceTest, DISABLED_CHROMEOS(StreamingURLLoaderSuccessCase)) {
+TEST_P(PrefetchServiceTest, DISABLED_CHROMEOS(StreamingURLLoaderSuccessCase)) {
   base::HistogramTester histogram_tester;
 
   MakePrefetchService(
@@ -3226,7 +3341,7 @@
 }
 
 // TODO(crbug.com/40249481): Test flaky on trybots.
-TEST_F(PrefetchServiceTest, DISABLED_CHROMEOS(NoVarySearchSuccessCase)) {
+TEST_P(PrefetchServiceTest, DISABLED_CHROMEOS(NoVarySearchSuccessCase)) {
   base::HistogramTester histogram_tester;
 
   MakePrefetchService(
@@ -3259,7 +3374,7 @@
   ExpectServingMetricsSuccess();
 }
 
-TEST_F(PrefetchServiceTest, NoVarySearchSuccessCase_Embedder) {
+TEST_P(PrefetchServiceTest, NoVarySearchSuccessCase_Embedder) {
   base::test::ScopedFeatureList scoped_feature_list(
       features::kPrefetchBrowserInitiatedTriggers);
   base::HistogramTester histogram_tester;
@@ -3307,7 +3422,7 @@
 }
 
 // TODO(crbug.com/40249481): Test flaky on trybots.
-TEST_F(PrefetchServiceTest, DISABLED_CHROMEOS(PrefetchEligibleRedirect)) {
+TEST_P(PrefetchServiceTest, DISABLED_CHROMEOS(PrefetchEligibleRedirect)) {
   base::HistogramTester histogram_tester;
 
   MakePrefetchService(
@@ -3358,7 +3473,7 @@
 }
 
 // TODO(crbug.com/40249481): Test flaky on trybots.
-TEST_F(PrefetchServiceTest, DISABLED_CHROMEOS(IneligibleRedirectCookies)) {
+TEST_P(PrefetchServiceTest, DISABLED_CHROMEOS(IneligibleRedirectCookies)) {
   base::HistogramTester histogram_tester;
 
   MakePrefetchService(
@@ -3420,7 +3535,7 @@
 }
 
 // TODO(crbug.com/40249481): Test flaky on trybots.
-TEST_F(PrefetchServiceTest,
+TEST_P(PrefetchServiceTest,
        DISABLED_CHROMEOS(IneligibleRedirectServiceWorker)) {
   base::HistogramTester histogram_tester;
 
@@ -3479,7 +3594,7 @@
 }
 
 // TODO(crbug.com/40249481): Test flaky on trybots.
-TEST_F(PrefetchServiceTest, DISABLED_CHROMEOS(InvalidRedirect)) {
+TEST_P(PrefetchServiceTest, DISABLED_CHROMEOS(InvalidRedirect)) {
   base::HistogramTester histogram_tester;
 
   MakePrefetchService(
@@ -3526,7 +3641,7 @@
 }
 
 // TODO(crbug.com/40249481): Test flaky on trybots.
-TEST_F(PrefetchServiceTest,
+TEST_P(PrefetchServiceTest,
        DISABLED_CHROMEOS(PrefetchSameOriginEligibleRedirect)) {
   NavigationSimulator::NavigateAndCommitFromBrowser(
       web_contents(), GURL("https://example.com/referrer"));
@@ -3582,7 +3697,7 @@
 // TODO(crbug.com/40249481): Test flaky on trybots.
 // TODO(crbug.com/40265797): This test is testing the current
 // functionality, and should be removed while fixing this bug.
-TEST_F(PrefetchServiceTest,
+TEST_P(PrefetchServiceTest,
        DISABLED_CHROMEOS(IneligibleSameSiteCrossOriginRequiresProxyRedirect)) {
   NavigationSimulator::NavigateAndCommitFromBrowser(
       web_contents(), GURL("https://example.com/referrer"));
@@ -3638,7 +3753,7 @@
 }
 
 // TODO(crbug.com/40249481): Test flaky on trybots.
-TEST_F(PrefetchServiceTest,
+TEST_P(PrefetchServiceTest,
        DISABLED_CHROMEOS(RedirectDefaultToIsolatedNetworkContextTransition)) {
   NavigationSimulator::NavigateAndCommitFromBrowser(
       web_contents(), GURL("https://example.com/referrer"));
@@ -3698,7 +3813,7 @@
 }
 
 // TODO(crbug.com/40249481): Test flaky on trybots.
-TEST_F(PrefetchServiceTest,
+TEST_P(PrefetchServiceTest,
        DISABLED_CHROMEOS(
            RedirectDefaultToIsolatedNetworkContextTransitionWithProxy)) {
   NavigationSimulator::NavigateAndCommitFromBrowser(
@@ -3762,7 +3877,7 @@
 }
 
 // TODO(crbug.com/40249481): Test flaky on trybots.
-TEST_F(PrefetchServiceTest,
+TEST_P(PrefetchServiceTest,
        DISABLED_CHROMEOS(RedirectIsolatedToDefaultNetworkContextTransition)) {
   NavigationSimulator::NavigateAndCommitFromBrowser(
       web_contents(), GURL("https://example.com/referrer"));
@@ -3824,7 +3939,7 @@
 }
 
 // TODO(crbug.com/40249481): Test flaky on trybots.
-TEST_F(PrefetchServiceTest,
+TEST_P(PrefetchServiceTest,
        DISABLED_CHROMEOS(RedirectNetworkContextTransitionBlockUntilHead)) {
   NavigationSimulator::NavigateAndCommitFromBrowser(
       web_contents(), GURL("https://example.com/referrer"));
@@ -3896,7 +4011,7 @@
 }
 
 // TODO(crbug.com/40249481): Test flaky on trybots.
-TEST_F(PrefetchServiceTest,
+TEST_P(PrefetchServiceTest,
        DISABLED_CHROMEOS(RedirectInsufficientReferrerPolicy)) {
   NavigationSimulator::NavigateAndCommitFromBrowser(
       web_contents(), GURL("https://referrer.com"));
@@ -3952,8 +4067,14 @@
 
 class PrefetchServiceAlwaysBlockUntilHeadTest
     : public PrefetchServiceTestBase,
-      public ::testing::WithParamInterface<blink::mojom::SpeculationEagerness> {
+      public WithPrefetchServiceRearchParam,
+      public ::testing::WithParamInterface<
+          std::tuple<PrefetchServiceRearchParam::Arg,
+                     blink::mojom::SpeculationEagerness>> {
  public:
+  PrefetchServiceAlwaysBlockUntilHeadTest()
+      : WithPrefetchServiceRearchParam(std::get<0>(GetParam())) {}
+
   const int kPrefetchTimeout = 10000;
   const int kBlockUntilHeadTimeout = 1000;
   void InitScopedFeatureList() override {
@@ -3969,9 +4090,22 @@
               {"block_until_head_timeout_conservative_prefetch", "1000"},
           }}},
         {});
+    InitRearchFeatures();
+  }
+
+  blink::mojom::SpeculationEagerness GetEagernessParam() {
+    return std::get<1>(GetParam());
   }
 };
 
+INSTANTIATE_TEST_SUITE_P(
+    ParametrizedTests,
+    PrefetchServiceAlwaysBlockUntilHeadTest,
+    testing::Combine(
+        testing::ValuesIn(PrefetchServiceRearchParam::Params()),
+        testing::Values(blink::mojom::SpeculationEagerness::kModerate,
+                        blink::mojom::SpeculationEagerness::kConservative)));
+
 // TODO(crbug.com/40249481): Test flaky on trybots.
 TEST_P(PrefetchServiceAlwaysBlockUntilHeadTest,
        DISABLED_CHROMEOS(BlockUntilHeadReceived)) {
@@ -3983,13 +4117,13 @@
   MakePrefetchOnMainFrame(
       GURL("https://example.com"),
       PrefetchType(PreloadingTriggerType::kSpeculationRule,
-                   /*use_prefetch_proxy=*/true, GetParam()));
+                   /*use_prefetch_proxy=*/true, GetEagernessParam()));
   task_environment()->RunUntilIdle();
 
   VerifyCommonRequestState(
       GURL("https://example.com"),
       {.use_prefetch_proxy = true,
-       .expected_priority = ExpectedPriorityForEagerness(GetParam())});
+       .expected_priority = ExpectedPriorityForEagerness(GetEagernessParam())});
 
   // Navigate to the URL before the head of the prefetch response is received
   NavigateInitiatedByRenderer(GURL("https://example.com"));
@@ -4016,13 +4150,14 @@
   CompleteResponseAndWait(net::OK, std::size(kHTMLBody));
 
   // Check the metrics now that the prefetch is complete.
-  ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody), GetParam(),
+  ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody),
+                        GetEagernessParam(),
                         /*is_accurate=*/true);
   ExpectServingReaderSuccess(serveable_reader);
   ExpectServingMetricsSuccess();
 
   std::string histogram_suffix =
-      GetPrefetchEagernessHistogramSuffix(GetParam());
+      GetPrefetchEagernessHistogramSuffix(GetEagernessParam());
   histogram_tester.ExpectUniqueTimeSample(
       base::StringPrintf(
           "PrefetchProxy.AfterClick.BlockUntilHeadDuration2NoBias.Served.%s",
@@ -4064,17 +4199,17 @@
   no_vary_search_hint->search_variance =
       network::mojom::SearchParamsVariance::NewNoVaryParams(
           std::vector<std::string>({"a"}));
-  MakePrefetchOnMainFrame(GURL("https://example.com/index.html?a=5"),
-                          PrefetchType(PreloadingTriggerType::kSpeculationRule,
-                                       /*use_prefetch_proxy=*/true, GetParam()),
-                          /* referrer */ blink::mojom::Referrer(),
-                          std::move(no_vary_search_hint));
+  MakePrefetchOnMainFrame(
+      GURL("https://example.com/index.html?a=5"),
+      PrefetchType(PreloadingTriggerType::kSpeculationRule,
+                   /*use_prefetch_proxy=*/true, GetEagernessParam()),
+      /* referrer */ blink::mojom::Referrer(), std::move(no_vary_search_hint));
   task_environment()->RunUntilIdle();
 
   VerifyCommonRequestState(
       GURL("https://example.com/index.html?a=5"),
       {.use_prefetch_proxy = true,
-       .expected_priority = ExpectedPriorityForEagerness(GetParam())});
+       .expected_priority = ExpectedPriorityForEagerness(GetEagernessParam())});
 
   // Navigate to the URL before the head of the prefetch response is received
   NavigateInitiatedByRenderer(GURL("https://example.com/index.html"));
@@ -4102,13 +4237,14 @@
   CompleteResponseAndWait(net::OK, std::size(kHTMLBody));
 
   // Check the metrics now that the prefetch is complete.
-  ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody), GetParam(),
+  ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody),
+                        GetEagernessParam(),
                         /* is_accurate=*/true);
   ExpectServingReaderSuccess(serveable_reader);
   ExpectServingMetricsSuccess();
 
   std::string histogram_suffix =
-      GetPrefetchEagernessHistogramSuffix(GetParam());
+      GetPrefetchEagernessHistogramSuffix(GetEagernessParam());
   histogram_tester.ExpectUniqueTimeSample(
       base::StringPrintf(
           "PrefetchProxy.AfterClick.BlockUntilHeadDuration2NoBias.Served.%s",
@@ -4153,7 +4289,7 @@
   MakePrefetchOnMainFrame(
       GURL("https://example.com/index.html?a=5"),
       PrefetchType(PreloadingTriggerType::kSpeculationRule,
-                   /*use_prefetch_proxy=*/true, GetParam()),
+                   /*use_prefetch_proxy=*/true, GetEagernessParam()),
       /* referrer */ blink::mojom::Referrer(),
       /* no_vary_search_hint */ std::move(no_vary_search_hint));
   task_environment()->RunUntilIdle();
@@ -4161,7 +4297,7 @@
   VerifyCommonRequestState(
       GURL("https://example.com/index.html?a=5"),
       {.use_prefetch_proxy = true,
-       .expected_priority = ExpectedPriorityForEagerness(GetParam())});
+       .expected_priority = ExpectedPriorityForEagerness(GetEagernessParam())});
 
   // Navigate to the URL before the head of the prefetch response is received
   NavigateInitiatedByRenderer(GURL("https://example.com/index.html"));
@@ -4189,11 +4325,12 @@
   CompleteResponseAndWait(net::OK, std::size(kHTMLBody));
 
   // Check the metrics now that the prefetch is complete.
-  ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody), GetParam());
+  ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody),
+                        GetEagernessParam());
   ExpectServingMetricsSuccess();
 
   std::string histogram_suffix =
-      GetPrefetchEagernessHistogramSuffix(GetParam());
+      GetPrefetchEagernessHistogramSuffix(GetEagernessParam());
   histogram_tester.ExpectTotalCount(
       base::StringPrintf(
           "PrefetchProxy.AfterClick.BlockUntilHeadDuration2NoBias.Served.%s",
@@ -4238,7 +4375,7 @@
   MakePrefetchOnMainFrame(
       GURL("https://example.com/index.html?a=5"),
       PrefetchType(PreloadingTriggerType::kSpeculationRule,
-                   /*use_prefetch_proxy=*/true, GetParam()),
+                   /*use_prefetch_proxy=*/true, GetEagernessParam()),
       /* referrer */ blink::mojom::Referrer(),
       /* no_vary_search_hint */ std::move(no_vary_search_hint));
   task_environment()->RunUntilIdle();
@@ -4246,7 +4383,7 @@
   VerifyCommonRequestState(
       GURL("https://example.com/index.html?a=5"),
       {.use_prefetch_proxy = true,
-       .expected_priority = ExpectedPriorityForEagerness(GetParam())});
+       .expected_priority = ExpectedPriorityForEagerness(GetEagernessParam())});
 
   // Navigate to the URL before the head of the prefetch response is received
   NavigateInitiatedByRenderer(GURL("https://example.com/index.html"));
@@ -4275,11 +4412,12 @@
   CompleteResponseAndWait(net::OK, std::size(kHTMLBody));
 
   // Check the metrics now that the prefetch is complete.
-  ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody), GetParam());
+  ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody),
+                        GetEagernessParam());
   ExpectServingMetricsSuccess();
 
   std::string histogram_suffix =
-      GetPrefetchEagernessHistogramSuffix(GetParam());
+      GetPrefetchEagernessHistogramSuffix(GetEagernessParam());
   histogram_tester.ExpectTotalCount(
       base::StringPrintf(
           "PrefetchProxy.AfterClick.BlockUntilHeadDuration2NoBias.Served.%s",
@@ -4318,13 +4456,13 @@
   MakePrefetchOnMainFrame(
       GURL("https://example.com"),
       PrefetchType(PreloadingTriggerType::kSpeculationRule,
-                   /*use_prefetch_proxy=*/true, GetParam()));
+                   /*use_prefetch_proxy=*/true, GetEagernessParam()));
   task_environment()->RunUntilIdle();
 
   VerifyCommonRequestState(
       GURL("https://example.com"),
       {.use_prefetch_proxy = true,
-       .expected_priority = ExpectedPriorityForEagerness(GetParam())});
+       .expected_priority = ExpectedPriorityForEagerness(GetEagernessParam())});
 
   // Navigate to the URL before the head of the prefetch response is received
   NavigateInitiatedByRenderer(GURL("https://example.com"));
@@ -4374,10 +4512,10 @@
                         .failure = ToPreloadingFailureReason(
                             PrefetchStatus::kPrefetchNotUsedCookiesChanged),
                         .is_accurate = true,
-                        .eagerness = GetParam()});
+                        .eagerness = GetEagernessParam()});
 
   std::string histogram_suffix =
-      GetPrefetchEagernessHistogramSuffix(GetParam());
+      GetPrefetchEagernessHistogramSuffix(GetEagernessParam());
   histogram_tester.ExpectTotalCount(
       base::StringPrintf(
           "PrefetchProxy.AfterClick.BlockUntilHeadDuration2NoBias.Served.%s",
@@ -4414,14 +4552,14 @@
       std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>());
 
   PrefetchType prefetch_type(PreloadingTriggerType::kSpeculationRule,
-                             /*use_prefetch_proxy=*/true, GetParam());
+                             /*use_prefetch_proxy=*/true, GetEagernessParam());
   MakePrefetchOnMainFrame(GURL("https://example.com"), prefetch_type);
   task_environment()->RunUntilIdle();
 
   VerifyCommonRequestState(
       GURL("https://example.com"),
       {.use_prefetch_proxy = true,
-       .expected_priority = ExpectedPriorityForEagerness(GetParam())});
+       .expected_priority = ExpectedPriorityForEagerness(GetEagernessParam())});
 
   // Navigate to the URL before the head of the prefetch response is received
   NavigateInitiatedByRenderer(GURL("https://example.com"));
@@ -4438,12 +4576,13 @@
   PrefetchContainer::Reader serveable_reader = future.Take();
   EXPECT_FALSE(serveable_reader);
 
-  ExpectPrefetchFailedNetError(histogram_tester, net::ERR_TIMED_OUT, GetParam(),
+  ExpectPrefetchFailedNetError(histogram_tester, net::ERR_TIMED_OUT,
+                               GetEagernessParam(),
                                /*is_accurate_triggering=*/true);
   ExpectServingMetrics(PrefetchStatus::kPrefetchFailedNetError);
 
   std::string histogram_suffix =
-      GetPrefetchEagernessHistogramSuffix(GetParam());
+      GetPrefetchEagernessHistogramSuffix(GetEagernessParam());
   base::TimeDelta block_until_head_timeout =
       PrefetchBlockUntilHeadTimeout(prefetch_type, /*is_nav_prerender=*/false);
   histogram_tester.ExpectTotalCount(
@@ -4484,12 +4623,12 @@
   MakePrefetchOnMainFrame(
       GURL("https://example.com"),
       PrefetchType(PreloadingTriggerType::kSpeculationRule,
-                   /*use_prefetch_proxy=*/false, GetParam()));
+                   /*use_prefetch_proxy=*/false, GetEagernessParam()));
   task_environment()->RunUntilIdle();
 
   VerifyCommonRequestState(
       GURL("https://example.com"),
-      {.expected_priority = ExpectedPriorityForEagerness(GetParam())});
+      {.expected_priority = ExpectedPriorityForEagerness(GetEagernessParam())});
 
   // The first navigation is started and then gone before the head of the
   // prefetch response is received. The given callback shouldn't be called (and
@@ -4518,7 +4657,8 @@
   EXPECT_TRUE(second_future.IsReady());
   PrefetchContainer::Reader serveable_reader = second_future.Take();
   EXPECT_FALSE(serveable_reader);
-  ExpectPrefetchFailedNetError(histogram_tester, net::ERR_TIMED_OUT, GetParam(),
+  ExpectPrefetchFailedNetError(histogram_tester, net::ERR_TIMED_OUT,
+                               GetEagernessParam(),
                                /*is_accurate_triggering=*/true);
   ExpectServingMetrics(PrefetchStatus::kPrefetchFailedNetError,
                        /*prefetch_header_latency=*/false,
@@ -4529,7 +4669,7 @@
   // navigation start but decided not to be used later (after
   // `kBlockUntilHeadTimeout` msec) due to timeout.
   std::string histogram_suffix =
-      GetPrefetchEagernessHistogramSuffix(GetParam());
+      GetPrefetchEagernessHistogramSuffix(GetEagernessParam());
   histogram_tester.ExpectTotalCount(
       base::StringPrintf(
           "PrefetchProxy.AfterClick.BlockUntilHeadDuration2NoBias.Served.%s",
@@ -4606,12 +4746,12 @@
   MakePrefetchOnMainFrame(
       GURL("https://example.com"),
       PrefetchType(PreloadingTriggerType::kSpeculationRule,
-                   /*use_prefetch_proxy=*/false, GetParam()));
+                   /*use_prefetch_proxy=*/false, GetEagernessParam()));
   task_environment()->RunUntilIdle();
 
   VerifyCommonRequestState(
       GURL("https://example.com"),
-      {.expected_priority = ExpectedPriorityForEagerness(GetParam())});
+      {.expected_priority = ExpectedPriorityForEagerness(GetEagernessParam())});
 
   // Navigate to the URL before the head of the prefetch response is received
   NavigateInitiatedByRenderer(GURL("https://example.com"));
@@ -4632,13 +4772,14 @@
   EXPECT_FALSE(serveable_reader);
 
   ExpectPrefetchFailedNetError(histogram_tester, net::ERR_ACCESS_DENIED,
-                               GetParam(), /*is_accurate_triggering=*/true);
+                               GetEagernessParam(),
+                               /*is_accurate_triggering=*/true);
   ExpectServingMetrics(PrefetchStatus::kPrefetchFailedNetError,
                        /*prefetch_header_latency=*/false,
                        /*required_private_prefetch_proxy=*/false);
 
   std::string histogram_suffix =
-      GetPrefetchEagernessHistogramSuffix(GetParam());
+      GetPrefetchEagernessHistogramSuffix(GetEagernessParam());
   histogram_tester.ExpectTotalCount(
       base::StringPrintf(
           "PrefetchProxy.AfterClick.BlockUntilHeadDuration2NoBias.Served.%s",
@@ -4700,14 +4841,14 @@
     MakePrefetchOnMainFrame(
         GURL(kTestUrl + "?a=5"),
         PrefetchType(PreloadingTriggerType::kSpeculationRule,
-                     /*use_prefetch_proxy=*/false, GetParam()),
+                     /*use_prefetch_proxy=*/false, GetEagernessParam()),
         /* referrer */ blink::mojom::Referrer(),
         /* no_vary_search_hint */ std::move(no_vary_search_hint));
     task_environment()->RunUntilIdle();
 
-    VerifyCommonRequestState(
-        GURL(kTestUrl + "?a=5"),
-        {.expected_priority = ExpectedPriorityForEagerness(GetParam())});
+    VerifyCommonRequestState(GURL(kTestUrl + "?a=5"),
+                             {.expected_priority = ExpectedPriorityForEagerness(
+                                  GetEagernessParam())});
   }
   {
     network::mojom::NoVarySearchPtr no_vary_search_hint =
@@ -4719,7 +4860,7 @@
     MakePrefetchOnMainFrame(
         GURL(kTestUrl + "?b=3"),
         PrefetchType(PreloadingTriggerType::kSpeculationRule,
-                     /*use_prefetch_proxy=*/false, GetParam()),
+                     /*use_prefetch_proxy=*/false, GetEagernessParam()),
         /* referrer */ blink::mojom::Referrer(),
         /* no_vary_search_hint */ std::move(no_vary_search_hint));
     task_environment()->RunUntilIdle();
@@ -4776,7 +4917,7 @@
   ExpectServingMetricsSuccess(/*required_private_prefetch_proxy=*/false);
 
   std::string histogram_suffix =
-      GetPrefetchEagernessHistogramSuffix(GetParam());
+      GetPrefetchEagernessHistogramSuffix(GetEagernessParam());
   histogram_tester.ExpectUniqueTimeSample(
       base::StringPrintf(
           "PrefetchProxy.AfterClick.BlockUntilHeadDuration2NoBias.Served.%s",
@@ -4822,11 +4963,12 @@
       std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>(2));
 
   MakePrefetchOnMainFrame(
-      GURL(kTestUrl), PrefetchType(PreloadingTriggerType::kSpeculationRule,
-                                   /*use_prefetch_proxy=*/false, GetParam()));
+      GURL(kTestUrl),
+      PrefetchType(PreloadingTriggerType::kSpeculationRule,
+                   /*use_prefetch_proxy=*/false, GetEagernessParam()));
   VerifyCommonRequestState(
       GURL(kTestUrl),
-      {.expected_priority = ExpectedPriorityForEagerness(GetParam())});
+      {.expected_priority = ExpectedPriorityForEagerness(GetEagernessParam())});
   task_environment()->RunUntilIdle();
   MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType,
                       /*use_prefetch_proxy=*/false,
@@ -4842,13 +4984,14 @@
     MakePrefetchOnMainFrame(
         GURL(kTestUrl + "?a=1"),
         PrefetchType(PreloadingTriggerType::kSpeculationRule,
-                     /*use_prefetch_proxy=*/false, GetParam()),
+                     /*use_prefetch_proxy=*/false, GetEagernessParam()),
         /* referrer */ blink::mojom::Referrer(),
         /* no_vary_search_hint */ std::move(no_vary_search_hint));
     task_environment()->RunUntilIdle();
     VerifyCommonRequestStateByUrl(
         GURL(kTestUrl + "?a=1"),
-        {.expected_priority = ExpectedPriorityForEagerness(GetParam())});
+        {.expected_priority =
+             ExpectedPriorityForEagerness(GetEagernessParam())});
   }
 
   // Adding a cookie after the prefetch has started will cause it to fail when
@@ -4900,11 +5043,12 @@
   MakePrefetchService(
       std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>(2));
   MakePrefetchOnMainFrame(
-      GURL(kTestUrl), PrefetchType(PreloadingTriggerType::kSpeculationRule,
-                                   /*use_prefetch_proxy=*/false, GetParam()));
+      GURL(kTestUrl),
+      PrefetchType(PreloadingTriggerType::kSpeculationRule,
+                   /*use_prefetch_proxy=*/false, GetEagernessParam()));
   VerifyCommonRequestState(
       GURL(kTestUrl),
-      {.expected_priority = ExpectedPriorityForEagerness(GetParam())});
+      {.expected_priority = ExpectedPriorityForEagerness(GetEagernessParam())});
   task_environment()->RunUntilIdle();
   {
     network::mojom::NoVarySearchPtr no_vary_search_hint =
@@ -4917,7 +5061,7 @@
     MakePrefetchOnMainFrame(
         url_2,
         PrefetchType(PreloadingTriggerType::kSpeculationRule,
-                     /*use_prefetch_proxy=*/false, GetParam()),
+                     /*use_prefetch_proxy=*/false, GetEagernessParam()),
         /* referrer */ blink::mojom::Referrer(),
         /* no_vary_search_hint */ std::move(no_vary_search_hint));
     task_environment()->RunUntilIdle();
@@ -5012,14 +5156,14 @@
     MakePrefetchOnMainFrame(
         not_matched_url,
         PrefetchType(PreloadingTriggerType::kSpeculationRule,
-                     /*use_prefetch_proxy=*/false, GetParam()),
+                     /*use_prefetch_proxy=*/false, GetEagernessParam()),
         /* referrer */ blink::mojom::Referrer(),
         /* no_vary_search_hint */ std::move(no_vary_search_hint));
     task_environment()->RunUntilIdle();
 
-    VerifyCommonRequestState(
-        not_matched_url,
-        {.expected_priority = ExpectedPriorityForEagerness(GetParam())});
+    VerifyCommonRequestState(not_matched_url,
+                             {.expected_priority = ExpectedPriorityForEagerness(
+                                  GetEagernessParam())});
   }
   {
     network::mojom::NoVarySearchPtr no_vary_search_hint =
@@ -5032,7 +5176,7 @@
     MakePrefetchOnMainFrame(
         matched_url,
         PrefetchType(PreloadingTriggerType::kSpeculationRule,
-                     /*use_prefetch_proxy=*/false, GetParam()),
+                     /*use_prefetch_proxy=*/false, GetEagernessParam()),
         /* referrer */ blink::mojom::Referrer(),
         /* no_vary_search_hint */ std::move(no_vary_search_hint));
     task_environment()->RunUntilIdle();
@@ -5082,7 +5226,7 @@
   EXPECT_EQ(referring_page_metrics->prefetch_eligible_count, 2);
 
   std::string histogram_suffix =
-      GetPrefetchEagernessHistogramSuffix(GetParam());
+      GetPrefetchEagernessHistogramSuffix(GetEagernessParam());
   histogram_tester.ExpectTotalCount(
       base::StringPrintf(
           "PrefetchProxy.AfterClick.BlockUntilHeadDuration2NoBias.Served.%s",
@@ -5110,12 +5254,6 @@
       true, 1);
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    ParametrizedTests,
-    PrefetchServiceAlwaysBlockUntilHeadTest,
-    testing::Values(blink::mojom::SpeculationEagerness::kModerate,
-                    blink::mojom::SpeculationEagerness::kConservative));
-
 TEST_P(PrefetchServiceAlwaysBlockUntilHeadTest,
        DISABLED_CHROMEOS(BlockUntilHeadTimedout)) {
   base::HistogramTester histogram_tester;
@@ -5126,13 +5264,13 @@
   MakePrefetchOnMainFrame(
       GURL("https://example.com"),
       PrefetchType(PreloadingTriggerType::kSpeculationRule,
-                   /*use_prefetch_proxy=*/true, GetParam()));
+                   /*use_prefetch_proxy=*/true, GetEagernessParam()));
   task_environment()->RunUntilIdle();
 
   VerifyCommonRequestState(
       GURL("https://example.com"),
       {.use_prefetch_proxy = true,
-       .expected_priority = ExpectedPriorityForEagerness(GetParam())});
+       .expected_priority = ExpectedPriorityForEagerness(GetEagernessParam())});
 
   // Navigate to the URL before the head of the prefetch response is received
   NavigateInitiatedByRenderer(GURL("https://example.com"));
@@ -5154,13 +5292,14 @@
                       {{"X-Testing", "Hello World"}}, kHTMLBody);
 
   // Check the metrics now that the prefetch is complete.
-  ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody), GetParam(),
+  ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody),
+                        GetEagernessParam(),
                         /*is_accurate=*/true);
   ExpectServingMetricsSuccess();
   EXPECT_FALSE(serveable_reader);
 
   std::string histogram_suffix =
-      GetPrefetchEagernessHistogramSuffix(GetParam());
+      GetPrefetchEagernessHistogramSuffix(GetEagernessParam());
   histogram_tester.ExpectTotalCount(
       base::StringPrintf(
           "PrefetchProxy.AfterClick.BlockUntilHeadDuration2NoBias.Served.%s",
@@ -5198,13 +5337,13 @@
   MakePrefetchOnMainFrame(
       GURL("https://example.com"),
       PrefetchType(PreloadingTriggerType::kSpeculationRule,
-                   /*use_prefetch_proxy=*/true, GetParam()));
+                   /*use_prefetch_proxy=*/true, GetEagernessParam()));
   task_environment()->RunUntilIdle();
 
   VerifyCommonRequestState(
       GURL("https://example.com"),
       {.use_prefetch_proxy = true,
-       .expected_priority = ExpectedPriorityForEagerness(GetParam())});
+       .expected_priority = ExpectedPriorityForEagerness(GetEagernessParam())});
 
   // Navigate to the URL before the head of the prefetch response is received
   NavigateInitiatedByRenderer(GURL("https://example.com"));
@@ -5226,13 +5365,14 @@
                       {{"X-Testing", "Hello World"}}, kHTMLBody);
 
   // Check the metrics now that the prefetch is complete.
-  ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody), GetParam(),
+  ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody),
+                        GetEagernessParam(),
                         /*is_accurate=*/true);
   ExpectServingMetricsSuccess();
   EXPECT_FALSE(serveable_reader);
 
   std::string histogram_suffix =
-      GetPrefetchEagernessHistogramSuffix(GetParam());
+      GetPrefetchEagernessHistogramSuffix(GetEagernessParam());
   histogram_tester.ExpectTotalCount(
       base::StringPrintf(
           "PrefetchProxy.AfterClick.BlockUntilHeadDuration2NoBias.Served.%s",
@@ -5271,13 +5411,13 @@
   MakePrefetchOnMainFrame(
       GURL("https://example.com"),
       PrefetchType(PreloadingTriggerType::kSpeculationRule,
-                   /*use_prefetch_proxy=*/true, GetParam()));
+                   /*use_prefetch_proxy=*/true, GetEagernessParam()));
   task_environment()->RunUntilIdle();
 
   VerifyCommonRequestState(
       GURL("https://example.com"),
       {.use_prefetch_proxy = true,
-       .expected_priority = ExpectedPriorityForEagerness(GetParam())});
+       .expected_priority = ExpectedPriorityForEagerness(GetEagernessParam())});
 
   // Navigate to the URL before the head of the prefetch response is received
   NavigateInitiatedByRenderer(GURL("https://example.com"));
@@ -5307,12 +5447,13 @@
                       {{"X-Testing", "Hello World"}}, kHTMLBody);
 
   // Check the metrics now that the prefetch is complete.
-  ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody), GetParam(),
+  ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody),
+                        GetEagernessParam(),
                         /*is_accurate=*/true);
   ExpectServingMetricsSuccess();
 
   std::string histogram_suffix =
-      GetPrefetchEagernessHistogramSuffix(GetParam());
+      GetPrefetchEagernessHistogramSuffix(GetEagernessParam());
   histogram_tester.ExpectTotalCount(
       base::StringPrintf(
           "PrefetchProxy.AfterClick.BlockUntilHeadDuration2NoBias.Served.%s",
@@ -5340,8 +5481,13 @@
       true, 2);
 }
 
-class PrefetchServiceNewLimitsTest : public PrefetchServiceTest {
+class PrefetchServiceNewLimitsTest
+    : public PrefetchServiceTestBase,
+      public WithPrefetchServiceRearchParam,
+      public ::testing::WithParamInterface<PrefetchServiceRearchParam::Arg> {
  public:
+  PrefetchServiceNewLimitsTest() : WithPrefetchServiceRearchParam(GetParam()) {}
+
   void InitScopedFeatureList() override {
     scoped_feature_list_.InitWithFeaturesAndParameters(
         {{features::kPrefetchUseContentRefactor,
@@ -5350,6 +5496,7 @@
          {features::kPrefetchNewLimits,
           {{"max_eager_prefetches", "2"}, {"max_non_eager_prefetches", "2"}}}},
         {});
+    InitRearchFeatures();
   }
 
   PrefetchContainer::Reader CompletePrefetch(
@@ -5377,7 +5524,12 @@
   }
 };
 
-TEST_F(PrefetchServiceNewLimitsTest,
+INSTANTIATE_TEST_SUITE_P(
+    ParametrizedTests,
+    PrefetchServiceNewLimitsTest,
+    testing::ValuesIn(PrefetchServiceRearchParam::Params()));
+
+TEST_P(PrefetchServiceNewLimitsTest,
        NonEagerPrefetchAllowedWhenEagerLimitIsReached) {
   const GURL url_1 = GURL("https://example.com/one");
   const GURL url_2 = GURL("https://example.com/two");
@@ -5420,7 +5572,7 @@
   EXPECT_EQ(referring_page_metrics->prefetch_successful_count, 3);
 }
 
-TEST_F(PrefetchServiceNewLimitsTest, NonEagerPrefetchEvictedAtLimit) {
+TEST_P(PrefetchServiceNewLimitsTest, NonEagerPrefetchEvictedAtLimit) {
   const GURL url_1 = GURL("https://example.com/one");
   const GURL url_2 = GURL("https://example.com/two");
   const GURL url_3 = GURL("https://example.com/three");
@@ -5530,7 +5682,7 @@
   }
 }
 
-TEST_F(PrefetchServiceNewLimitsTest, PrefetchWithNoCandidateIsNotStarted) {
+TEST_P(PrefetchServiceNewLimitsTest, PrefetchWithNoCandidateIsNotStarted) {
   const GURL url_1 = GURL("https://example.com/one");
   const GURL url_2 = GURL("https://example.com/two");
   const GURL url_3 = GURL("https://example.com/three");
@@ -5591,7 +5743,7 @@
   EXPECT_EQ(RequestCount(), 0);
 }
 
-TEST_F(PrefetchServiceNewLimitsTest,
+TEST_P(PrefetchServiceNewLimitsTest,
        InProgressPrefetchWithNoCandidateIsCancelled) {
   const GURL url_1 = GURL("https://example.com/one");
   const GURL url_2 = GURL("https://example.com/two");
@@ -5652,7 +5804,7 @@
   EXPECT_FALSE(serveable_reader);
 }
 
-TEST_F(PrefetchServiceNewLimitsTest,
+TEST_P(PrefetchServiceNewLimitsTest,
        CompletedPrefetchWithNoCandidateIsEvicted) {
   const GURL url_1 = GURL("https://example.com/one");
   const GURL url_2 = GURL("https://example.com/two");
@@ -5705,7 +5857,7 @@
 }
 
 // Test to see if we can re-prefetch a url whose previous prefetch expired.
-TEST_F(PrefetchServiceNewLimitsTest, PrefetchReset) {
+TEST_P(PrefetchServiceNewLimitsTest, PrefetchReset) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitWithFeaturesAndParameters(
       {{features::kPrefetchUseContentRefactor,
@@ -5787,7 +5939,7 @@
   }
 }
 
-TEST_F(PrefetchServiceNewLimitsTest, NextPrefetchQueuedImmediatelyAfterReset) {
+TEST_P(PrefetchServiceNewLimitsTest, NextPrefetchQueuedImmediatelyAfterReset) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitWithFeaturesAndParameters(
       {{features::kPrefetchUseContentRefactor,
@@ -5846,7 +5998,7 @@
 // Tests that the prefetch queue is stuck when resetting the running prefetch
 // during waiting its response.
 // Regression test for crbug.com/400233773, which is currently not fixed.
-TEST_F(PrefetchServiceNewLimitsTest,
+TEST_P(PrefetchServiceNewLimitsTest,
        PrefetchQueueStuckWhenResettingRunningPrefetch) {
   NavigateAndCommit(GURL("https://example.com"));
   MakePrefetchService(
@@ -5891,7 +6043,7 @@
             PrefetchContainer::LoadState::kStarted);
 }
 
-TEST_F(PrefetchServiceNewLimitsTest, PrefetchFailsAndIsReset) {
+TEST_P(PrefetchServiceNewLimitsTest, PrefetchFailsAndIsReset) {
   base::HistogramTester histogram_tester;
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitWithFeaturesAndParameters(
@@ -5942,7 +6094,7 @@
                                       1);
 }
 
-TEST_F(PrefetchServiceNewLimitsTest, EagerPrefetchLimitIsDynamic) {
+TEST_P(PrefetchServiceNewLimitsTest, EagerPrefetchLimitIsDynamic) {
   const GURL url_1 = GURL("https://example.com/one");
   const GURL url_2 = GURL("https://example.com/two");
   const GURL url_3 = GURL("https://example.com/three");
@@ -6097,7 +6249,7 @@
   }
 }
 
-TEST_F(PrefetchServiceNewLimitsTest, RemoveCandidateForFailedPrefetch) {
+TEST_P(PrefetchServiceNewLimitsTest, RemoveCandidateForFailedPrefetch) {
   const GURL url = GURL("https://example.com/one");
 
   NavigateAndCommit(GURL("https://example.com"));
@@ -6152,7 +6304,19 @@
   return metadata;
 }
 
-class PrefetchServiceClientHintsTest : public PrefetchServiceTestBase {
+class PrefetchServiceClientHintsTest
+    : public PrefetchServiceTestBase,
+      public WithPrefetchServiceRearchParam,
+      public ::testing::WithParamInterface<PrefetchServiceRearchParam::Arg> {
+ public:
+  PrefetchServiceClientHintsTest()
+      : WithPrefetchServiceRearchParam(GetParam()) {}
+
+  void InitScopedFeatureList() override {
+    PrefetchServiceTestBase::InitScopedFeatureList();
+    InitRearchFeatures();
+  }
+
  protected:
   std::unique_ptr<BrowserContext> CreateBrowserContext() override {
     auto browser_context = PrefetchServiceTestBase::CreateBrowserContext();
@@ -6170,7 +6334,12 @@
       GetFakeUserAgentMetadata()};
 };
 
-TEST_F(PrefetchServiceClientHintsTest, NoClientHintsWhenDisabled) {
+INSTANTIATE_TEST_SUITE_P(
+    ParametrizedTests,
+    PrefetchServiceClientHintsTest,
+    testing::ValuesIn(PrefetchServiceRearchParam::Params()));
+
+TEST_P(PrefetchServiceClientHintsTest, NoClientHintsWhenDisabled) {
   base::test::ScopedFeatureList disable_prefetch_ch;
   disable_prefetch_ch.InitAndDisableFeature(features::kPrefetchClientHints);
 
@@ -6192,7 +6361,7 @@
   EXPECT_FALSE(pending->request.headers.HasHeader("Sec-CH-UA"));
 }
 
-TEST_F(PrefetchServiceClientHintsTest, LowEntropyClientHints) {
+TEST_P(PrefetchServiceClientHintsTest, LowEntropyClientHints) {
   base::test::ScopedFeatureList enable_prefetch_ch;
   enable_prefetch_ch.InitAndEnableFeature(features::kPrefetchClientHints);
 
@@ -6214,7 +6383,7 @@
   EXPECT_TRUE(pending->request.headers.HasHeader("Sec-CH-UA"));
 }
 
-TEST_F(PrefetchServiceClientHintsTest, HighEntropyClientHints) {
+TEST_P(PrefetchServiceClientHintsTest, HighEntropyClientHints) {
   base::test::ScopedFeatureList enable_prefetch_ch;
   enable_prefetch_ch.InitAndEnableFeature(features::kPrefetchClientHints);
 
@@ -6252,7 +6421,7 @@
   EXPECT_GT(viewport_width_int, 0);
 }
 
-TEST_F(PrefetchServiceClientHintsTest, CrossSiteNone) {
+TEST_P(PrefetchServiceClientHintsTest, CrossSiteNone) {
   base::test::ScopedFeatureList enable_prefetch_ch;
   enable_prefetch_ch.InitAndEnableFeatureWithParameters(
       features::kPrefetchClientHints, {{"cross_site_behavior", "none"}});
@@ -6282,7 +6451,7 @@
   EXPECT_FALSE(pending->request.headers.HasHeader("Sec-CH-Viewport-Width"));
 }
 
-TEST_F(PrefetchServiceClientHintsTest, CrossSiteLowEntropy) {
+TEST_P(PrefetchServiceClientHintsTest, CrossSiteLowEntropy) {
   base::test::ScopedFeatureList enable_prefetch_ch;
   enable_prefetch_ch.InitAndEnableFeatureWithParameters(
       features::kPrefetchClientHints, {{"cross_site_behavior", "low_entropy"}});
@@ -6312,7 +6481,7 @@
   EXPECT_FALSE(pending->request.headers.HasHeader("Sec-CH-Viewport-Width"));
 }
 
-TEST_F(PrefetchServiceClientHintsTest, CrossSiteAll) {
+TEST_P(PrefetchServiceClientHintsTest, CrossSiteAll) {
   base::test::ScopedFeatureList enable_prefetch_ch;
   enable_prefetch_ch.InitAndEnableFeatureWithParameters(
       features::kPrefetchClientHints, {{"cross_site_behavior", "all"}});
@@ -6342,7 +6511,7 @@
   EXPECT_TRUE(pending->request.headers.HasHeader("Sec-CH-Viewport-Width"));
 }
 
-TEST_F(PrefetchServiceTest, CancelWhileBlockedOnHead) {
+TEST_P(PrefetchServiceTest, CancelWhileBlockedOnHead) {
   MakePrefetchService(
       std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>());
   NavigateAndCommit(GURL("https://example.com/"));
@@ -6387,7 +6556,7 @@
 // `PrefetchService` calls `PrefetchStreamingURLLoader::HandleRedirect`) causes
 // no crash, and the corresponding prefetch should not be served.
 // A regression test for crbug.com/396133768.
-TEST_F(
+TEST_P(
     PrefetchServiceTest,
     DISABLED_CHROMEOS(URLLoaderDisconnectedWhileHandlingRedirectEligibilty)) {
   MakePrefetchService(
@@ -6475,7 +6644,7 @@
 // unblocks the navigation that potentially matches the corresponding
 // prefetch and thus was blocked in the match resolver (BlockUntilHead).
 // A regression test for crbug.com/396133768.√
-TEST_F(
+TEST_P(
     PrefetchServiceTest,
     DISABLED_CHROMEOS(
         URLLoaderDisconnectedWhileHandlingRedirectEligibilty_BlockUntilHead)) {
@@ -6572,7 +6741,7 @@
 //   success.
 // - Navigation Y started, which matches to A. Unblocked synchronously as
 //   success.
-TEST_F(
+TEST_P(
     PrefetchServiceTest,
     DISABLED_CHROMEOS(MultipleConcurrentNavigationSuccessBeforeNavigations)) {
   base::test::ScopedFeatureList scoped_feature_list;
@@ -6634,7 +6803,7 @@
 // - Navigation X started, which matches to A. Blocked by A.
 // - Navigation Y started, which matches to A. Blocked by A.
 // - A received non-redirect header. Unblocks them as success.
-TEST_F(
+TEST_P(
     PrefetchServiceTest,
     DISABLED_CHROMEOS(MultipleConcurrentNavigationBlockUntilHeadThenSuccess)) {
   base::test::ScopedFeatureList scoped_feature_list;
@@ -6706,7 +6875,7 @@
 // - Navigation Y started, which is potentially matches and not eventually
 //   matches to A. Blocked by A.
 // - A received non-redirect header. Unblocks them as success/fail.
-TEST_F(PrefetchServiceTest,
+TEST_P(PrefetchServiceTest,
        DISABLED_CHROMEOS(
            MultipleConcurrentNavigationBlockUntilHeadThenSuccessFail)) {
   base::test::ScopedFeatureList scoped_feature_list;
@@ -6784,7 +6953,7 @@
 //
 // This test checks that it is safe to call
 // `PrefetchContainer::OnDetectedCookiesChange()` multiple times.
-TEST_F(PrefetchServiceTest,
+TEST_P(PrefetchServiceTest,
        DISABLED_CHROMEOS(
            MultipleConcurrentNavigationBlockUntilHeadThenCookiesChanged)) {
   base::test::ScopedFeatureList scoped_feature_list;
@@ -6843,7 +7012,7 @@
 //   this test actually.)
 // - The eligibility check of A scceeds. Matching process proceeds and ends as
 //   success.
-TEST_F(PrefetchServiceTest,
+TEST_P(PrefetchServiceTest,
        DISABLED_CHROMEOS(PrefetchAheadOfPrerenderSuccess)) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitWithFeatures(
@@ -6932,7 +7101,7 @@
 //   (Regard X as prerender, while we don't assume that in this test actually.)
 // - The eligibility check of A failed (due to non https). Matching process ends
 //   with no prefetch.
-TEST_F(PrefetchServiceTest,
+TEST_P(PrefetchServiceTest,
        DISABLED_CHROMEOS(PrefetchAheadOfPrerenderIneligible)) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitWithFeatures(
@@ -6989,7 +7158,7 @@
   prefetch_service.SetDelayEligibilityCheckForTesting(base::NullCallback());
 }
 
-TEST_F(PrefetchServiceTest,
+TEST_P(PrefetchServiceTest,
        DISABLED_CHROMEOS(IsPrefetchDuplicateSameNoVarySearchHint)) {
   base::test::ScopedFeatureList scoped_feature_list(
       features::kPrefetchBrowserInitiatedTriggers);
@@ -7032,10 +7201,17 @@
 // `PrefetchService::AddPrefetchContainerWithoutStartingPrefetch()` if an old
 // prefetch is registered and yet another new prefetch for the same key is
 // added.
-class PrefetchServiceAddPrefetchContainerTest : public PrefetchServiceTestBase {
+class PrefetchServiceAddPrefetchContainerTest
+    : public PrefetchServiceTestBase,
+      public WithPrefetchServiceRearchParam,
+      public ::testing::WithParamInterface<PrefetchServiceRearchParam::Arg> {
  public:
+  PrefetchServiceAddPrefetchContainerTest()
+      : WithPrefetchServiceRearchParam(GetParam()) {}
+
   void InitScopedFeatureList() override {
     PrefetchServiceTestBase::InitScopedFeatureList();
+    InitRearchFeatures();
 
     scoped_feature_list_for_prerender2_fallback_.InitWithFeatures(
         {features::kPrerender2FallbackPrefetchSpecRules}, {});
@@ -7091,7 +7267,12 @@
   base::test::ScopedFeatureList scoped_feature_list_for_prerender2_fallback_;
 };
 
-TEST_F(PrefetchServiceAddPrefetchContainerTest, ReplacesOldWithNewByDefault) {
+INSTANTIATE_TEST_SUITE_P(
+    ParametrizedTests,
+    PrefetchServiceAddPrefetchContainerTest,
+    testing::ValuesIn(PrefetchServiceRearchParam::Params()));
+
+TEST_P(PrefetchServiceAddPrefetchContainerTest, ReplacesOldWithNewByDefault) {
   blink::DocumentToken document_token;
 
   std::unique_ptr<PrefetchContainer> prefetch_container1 =
@@ -7123,7 +7304,7 @@
   ASSERT_EQ(attempt2.get(), prefetch_container->preloading_attempt().get());
 }
 
-TEST_F(PrefetchServiceAddPrefetchContainerTest,
+TEST_P(PrefetchServiceAddPrefetchContainerTest,
        PreservesOldIfOldIsAheadOfPrerender) {
   blink::DocumentToken document_token;
 
@@ -7154,7 +7335,7 @@
   ASSERT_EQ(attempt1.get(), prefetch_container->preloading_attempt().get());
 }
 
-TEST_F(PrefetchServiceAddPrefetchContainerTest,
+TEST_P(PrefetchServiceAddPrefetchContainerTest,
        ReplacesOldWithNewIfOldIsAheadOfPrerenderAndNotServable) {
   blink::DocumentToken document_token;
 
@@ -7187,7 +7368,7 @@
   ASSERT_EQ(attempt2.get(), prefetch_container->preloading_attempt().get());
 }
 
-TEST_F(PrefetchServiceAddPrefetchContainerTest,
+TEST_P(PrefetchServiceAddPrefetchContainerTest,
        TakesOldWithAttributeMigrationIfNewIsAheadOfPrerender) {
   blink::DocumentToken document_token;
 
diff --git a/content/browser/preloading/preloading_decider.cc b/content/browser/preloading/preloading_decider.cc
index 5725bbb..2c62ff3b 100644
--- a/content/browser/preloading/preloading_decider.cc
+++ b/content/browser/preloading/preloading_decider.cc
@@ -526,11 +526,42 @@
   prerenderer_->OnLCPPredicted();
 }
 
+std::vector<std::optional<std::string>>
+PreloadingDecider::GetMergedSpeculationTagsFromSuitableCandidates(
+    const PreloadingDecider::SpeculationCandidateKey& lookup_key,
+    const PreloadingPredictor& enacting_predictor,
+    PreloadingConfidence confidence) {
+  std::vector<std::optional<std::string>> merged_tags;
+
+  auto it = on_standby_candidates_.find(lookup_key);
+  if (it == on_standby_candidates_.end()) {
+    return merged_tags;
+  }
+
+  for (const auto& candidate : it->second) {
+    if (!IsSuitableCandidate(candidate, enacting_predictor, confidence,
+                             lookup_key.second)) {
+      continue;
+    }
+
+    for (const auto& tag : candidate->tags) {
+      if (!base::Contains(merged_tags, tag)) {
+        merged_tags.push_back(tag);
+      }
+    }
+  }
+
+  return merged_tags;
+}
+
 bool PreloadingDecider::MaybePrefetch(
     const GURL& url,
     const PreloadingPredictor& enacting_predictor,
     PreloadingConfidence confidence) {
   SpeculationCandidateKey key{url, blink::mojom::SpeculationAction::kPrefetch};
+  std::vector<std::optional<std::string>> merged_tags =
+      GetMergedSpeculationTagsFromSuitableCandidates(key, enacting_predictor,
+                                                     confidence);
   std::optional<std::pair<PreloadingDecider::SpeculationCandidateKey,
                           blink::mojom::SpeculationCandidatePtr>>
       matched_candidate_pair =
@@ -540,6 +571,7 @@
   }
 
   key = matched_candidate_pair.value().first;
+  matched_candidate_pair.value().second->tags = merged_tags;
   bool result = prefetcher_.MaybePrefetch(
       std::move(matched_candidate_pair.value().second), enacting_predictor);
 
diff --git a/content/browser/preloading/preloading_decider.h b/content/browser/preloading/preloading_decider.h
index 474606a8..1e9247a 100644
--- a/content/browser/preloading/preloading_decider.h
+++ b/content/browser/preloading/preloading_decider.h
@@ -99,9 +99,22 @@
                            PreloadingConfidence confidence,
                            bool fallback_to_preconnect);
 
-  // Prefetches the |url| if it is safe and eligible to be prefetched. Returns
-  // false if no suitable (given |enacting_predictor|) on-standby candidate is
-  // found for the given |url|, or the Prefetcher does not accept the candidate.
+  // TODO(crbug.com/381687257): 1. Inline the logic in
+  // `GetMatchedPreloadingCandidate` to reduce redundant code. 2. Support NVS
+  // matching logic.
+  // Returns a vector of std::optional<string> of candidates which will be
+  // enacted by the given parameter. This function is used for non-eager
+  // candidates only.
+  std::vector<std::optional<std::string>>
+  GetMergedSpeculationTagsFromSuitableCandidates(
+      const PreloadingDecider::SpeculationCandidateKey& lookup_key,
+      const PreloadingPredictor& enacting_predictor,
+      PreloadingConfidence confidence);
+
+  // Prefetches the |url| if it is safe and eligible to be prefetched.
+  // Returns false if no suitable (given |enacting_predictor|) on-standby
+  // candidate is found for the given |url|, or the Prefetcher does not
+  // accept the candidate.
   bool MaybePrefetch(const GURL& url,
                      const PreloadingPredictor& enacting_predictor,
                      PreloadingConfidence confidence);
diff --git a/content/browser/preloading/preloading_decider_unittest.cc b/content/browser/preloading/preloading_decider_unittest.cc
index ec8acbd..7da68f4 100644
--- a/content/browser/preloading/preloading_decider_unittest.cc
+++ b/content/browser/preloading/preloading_decider_unittest.cc
@@ -582,6 +582,81 @@
       kUmaName, PredictorConfusionMatrix::kFalseNegative, 1);
 }
 
+// Test that speculation rules tags merging works as expected if multiple
+// matched rules applies.
+TEST_F(PreloadingDeciderTest, SpeculationRulesTagsMergingForNonEagerPrefetch) {
+  const GURL url = GetSameOriginUrl("/candidate1.html");
+  auto* preloading_decider =
+      PreloadingDecider::GetOrCreateForCurrentDocument(&GetPrimaryMainFrame());
+  ASSERT_TRUE(preloading_decider);
+
+  auto candidate_1 =
+      MakeCandidate(url, blink::mojom::SpeculationAction::kPrefetch,
+                    blink::mojom::SpeculationEagerness::kConservative);
+
+  auto candidate_2 = candidate_1.Clone();
+  candidate_2->eagerness = blink::mojom::SpeculationEagerness::kModerate;
+
+  candidate_1->tags = {"tag1"};
+  candidate_2->tags = {"tag2"};
+
+  std::vector<blink::mojom::SpeculationCandidatePtr> candidates;
+  candidates.push_back(candidate_1.Clone());
+  candidates.push_back(candidate_2.Clone());
+
+  // Add conservative and moderate preload candidate and preload on
+  // pointer-down.
+  preloading_decider->UpdateSpeculationCandidates(candidates);
+  const auto& prefetches = GetPrefetchService()->prefetches_;
+  preloading_decider->OnPointerDown(url);
+
+  EXPECT_TRUE(prefetches[0]->HasSpeculationRulesTags());
+  EXPECT_EQ(prefetches[0]->GetSpeculationRulesTagsHeaderString().value(),
+            "\"tag1\", \"tag2\"");
+  EXPECT_FALSE(preloading_decider->IsOnStandByForTesting(
+      url, blink::mojom::SpeculationAction::kPrefetch));
+}
+
+// Test that no speculation rules tags merging happens if multiple candidates
+// are in the queue but only one is enacted.
+TEST_F(PreloadingDeciderTest,
+       SpeculationRulesTagsNoMergingForNonEagerPrefetch) {
+  const GURL url = GetSameOriginUrl("/candidate1.html");
+  auto* preloading_decider =
+      PreloadingDecider::GetOrCreateForCurrentDocument(&GetPrimaryMainFrame());
+  ASSERT_TRUE(preloading_decider);
+
+  auto candidate_1 =
+      MakeCandidate(url, blink::mojom::SpeculationAction::kPrefetch,
+                    blink::mojom::SpeculationEagerness::kConservative);
+
+  auto candidate_2 = candidate_1.Clone();
+  candidate_2->eagerness = blink::mojom::SpeculationEagerness::kModerate;
+
+  candidate_1->tags = {"tag1"};
+  candidate_2->tags = {"tag2"};
+
+  std::vector<blink::mojom::SpeculationCandidatePtr> candidates;
+  candidates.push_back(candidate_1.Clone());
+  candidates.push_back(candidate_2.Clone());
+
+  // Add conservative and moderate  preload candidate and preload on
+  // pointer-hover.
+  preloading_decider->UpdateSpeculationCandidates(candidates);
+  const auto& prefetches = GetPrefetchService()->prefetches_;
+  preloading_decider->OnPointerHover(
+      url, blink::mojom::AnchorElementPointerData::New(
+               /*is_mouse_pointer=*/true,
+               /*mouse_velocity=*/75.0,
+               /*mouse_acceleration=*/0.0));
+
+  EXPECT_TRUE(prefetches[0]->HasSpeculationRulesTags());
+  EXPECT_EQ(prefetches[0]->GetSpeculationRulesTagsHeaderString().value(),
+            "\"tag2\"");
+  EXPECT_FALSE(preloading_decider->IsOnStandByForTesting(
+      url, blink::mojom::SpeculationAction::kPrefetch));
+}
+
 class PreloadingDeciderWithParameterizedSpeculationActionTest
     : public PreloadingDeciderTest,
       public ::testing::WithParamInterface<blink::mojom::SpeculationAction> {
diff --git a/content/browser/renderer_host/render_frame_host_manager.cc b/content/browser/renderer_host/render_frame_host_manager.cc
index 9bf65e1e..301c950e 100644
--- a/content/browser/renderer_host/render_frame_host_manager.cc
+++ b/content/browser/renderer_host/render_frame_host_manager.cc
@@ -565,6 +565,29 @@
   }
 }
 
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class ProcessReuseOnCOOPType {
+  kDifferentSiteInstance = 0,
+  kSameSiteNavigationInSingleWebContents = 1,
+  kPrerender = 2,
+  kNone = 3,
+  kMaxValue = kNone,
+};
+
+constexpr std::array<const char*,
+                     static_cast<size_t>(ProcessReuseOnCOOPType::kMaxValue) + 1>
+    kProcessReuseOnCOOPTypeStrings = {"DifferentSiteInstance",
+                                      "SameSiteNavigationInSingleWebContents",
+                                      "Prerender", "None"};
+
+void RecordProcessReuseOnCoopResult(ProcessReuseOnCOOPType type, bool success) {
+  base::UmaHistogramBoolean(
+      base::StrCat({"Navigation.ProcessReuseOnCOOP.",
+                    kProcessReuseOnCOOPTypeStrings[static_cast<int>(type)]}),
+      success);
+}
+
 }  // namespace
 
 RenderFrameHostManager::IsSameSiteGetter::IsSameSiteGetter()
@@ -3141,18 +3164,24 @@
   //
   // TODO(alexmos): Study if this kind of reuse might be useful in other cases
   // beyond COOP.
+  ProcessReuseOnCOOPType coop_process_reuse_type =
+      ProcessReuseOnCOOPType::kNone;
   if (should_swap_result->type() == BrowsingContextGroupSwapType::kCoopSwap ||
       should_swap_result->type() ==
           BrowsingContextGroupSwapType::kRelatedCoopSwap) {
     if (candidate_instance && candidate_instance != new_instance &&
         candidate_instance->GetSiteInfo() == new_instance->GetSiteInfo()) {
+      coop_process_reuse_type = ProcessReuseOnCOOPType::kDifferentSiteInstance;
       process_to_reuse = candidate_instance->GetProcess();
     } else if (is_same_site.Get(*render_frame_host_, dest_url_info) &&
                current_instance->GetRelatedActiveContentsCount() == 1) {
+      coop_process_reuse_type =
+          ProcessReuseOnCOOPType::kSameSiteNavigationInSingleWebContents;
       process_to_reuse = current_instance->GetProcess();
     } else if (base::FeatureList::IsEnabled(
                    features::kProcessReuseOnPrerenderCOOPSwap) &&
                frame_tree_node_->frame_tree().is_prerendering()) {
+      coop_process_reuse_type = ProcessReuseOnCOOPType::kPrerender;
       process_to_reuse = current_instance->GetProcess();
     }
   }
@@ -3161,16 +3190,20 @@
     DCHECK(frame_tree_node_->IsMainFrame());
     new_instance->ReuseExistingProcessIfPossible(process_to_reuse);
   }
-  if (!new_instance->HasProcess() &&
-      (should_swap_result->type() == BrowsingContextGroupSwapType::kCoopSwap ||
-       should_swap_result->type() ==
-           BrowsingContextGroupSwapType::kRelatedCoopSwap)) {
-    // Mark the coop_reuse_process_failed_ field in SiteInstance.
-    // This may happen in the navigation between non-COOP and COOP
-    // sites.
-    // The field will be passed to the ProcessAllocationContext when the
-    // new_instance tries to create a renderer process.
-    new_instance->SetCOOPReuseProcessFailed();
+  if (should_swap_result->type() == BrowsingContextGroupSwapType::kCoopSwap ||
+      should_swap_result->type() ==
+          BrowsingContextGroupSwapType::kRelatedCoopSwap) {
+    if (new_instance->HasProcess()) {
+      RecordProcessReuseOnCoopResult(coop_process_reuse_type, true);
+    } else {
+      RecordProcessReuseOnCoopResult(coop_process_reuse_type, false);
+      // Mark the coop_reuse_process_failed_ field in SiteInstance.
+      // This may happen in the navigation between non-COOP and COOP
+      // sites.
+      // The field will be passed to the ProcessAllocationContext when the
+      // new_instance tries to create a renderer process.
+      new_instance->SetCOOPReuseProcessFailed();
+    }
   }
 
   // We want fenced frame BrowsingInstances to share the same default
diff --git a/content/browser/security/coop/cross_origin_opener_policy_browsertest.cc b/content/browser/security/coop/cross_origin_opener_policy_browsertest.cc
index 8bd4b70..c3c7653 100644
--- a/content/browser/security/coop/cross_origin_opener_policy_browsertest.cc
+++ b/content/browser/security/coop/cross_origin_opener_policy_browsertest.cc
@@ -4581,6 +4581,7 @@
 // BrowsingInstance swap required by COOP).
 IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest,
                        NoExtraProcessSwapFromDiscardedSpeculativeRFH) {
+  base::HistogramTester histogram_tester;
   if (IsIsolatedOriginRequiredToGuaranteeDedicatedProcess()) {
     IsolateOriginsForTesting(embedded_test_server(), shell()->web_contents(),
                              {url::Origin::Create(GURL("https://b.test/"))});
@@ -4639,6 +4640,9 @@
   // it cannot be reused, and we end up creating a new speculative RFH and
   // destroying the original one.
   EXPECT_TRUE(speculative_rfh.IsDestroyed());
+
+  histogram_tester.ExpectUniqueSample(
+      "Navigation.ProcessReuseOnCOOP.DifferentSiteInstance", true, 1);
 }
 
 // Ensure that same-site navigations that result in a COOP mismatch avoid an
@@ -4646,6 +4650,7 @@
 // BrowsingContextGroup of size 1 (in this case, in the same WebContents).
 IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest,
                        NoExtraProcessSwapFromSameSiteCOOPMismatch) {
+  base::HistogramTester histogram_tester;
   GURL url_1(https_server()->GetURL("a.test", "/empty.html"));
   GURL url_2(https_server()->GetURL(
       "a.test", "/set-header?Cross-Origin-Opener-Policy: same-origin"));
@@ -4706,8 +4711,19 @@
                     ->GetProcess()
                     ->GetProcessLock()
                     .is_locked_to_site());
+    histogram_tester.ExpectUniqueSample("Navigation.ProcessReuseOnCOOP.None",
+                                        false, 1);
   } else {
     EXPECT_EQ(rph_id_2, rph_id_3);
+
+    if (IsBackForwardCacheEnabled() || ShouldCreateNewHostForAllFrames()) {
+      histogram_tester.ExpectUniqueSample(
+          "Navigation.ProcessReuseOnCOOP.DifferentSiteInstance", true, 1);
+    } else {
+      histogram_tester.ExpectUniqueSample(
+          "Navigation.ProcessReuseOnCOOP.SameSiteNavigationInSingleWebContents",
+          true, 1);
+    }
   }
 }
 
@@ -4715,6 +4731,7 @@
 // one COOP page to another COOP page.
 IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest,
                        NavigatingFromCOOPToCOOPHasNoExtraProcessCreation) {
+  base::HistogramTester histogram_tester;
   GURL url_1(https_server()->GetURL(
       "a.test", "/set-header?Cross-Origin-Opener-Policy: same-origin"));
   GURL url_2(https_server()->GetURL(
@@ -4723,6 +4740,8 @@
   // Navigate to a COOP URL.
   EXPECT_TRUE(NavigateToURL(shell(), url_1));
   int rph_id_1 = current_frame_host()->GetProcess()->GetDeprecatedID();
+  histogram_tester.ExpectUniqueSample("Navigation.ProcessReuseOnCOOP.None",
+                                      false, 1);
 
   // Start a navigation to another same-site COOP URL.
   TestNavigationManager navigation(web_contents(), url_2);
@@ -4774,6 +4793,7 @@
 // fresh process.
 IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest,
                        NoProcessReuseForSameSiteCOOPMismatchInPopup) {
+  base::HistogramTester histogram_tester;
   GURL url_1(https_server()->GetURL("a.test", "/empty.html"));
   GURL url_2(https_server()->GetURL(
       "a.test", "/set-header?Cross-Origin-Opener-Policy: same-origin"));
@@ -4796,6 +4816,8 @@
   int rph_id_2 =
       popup_contents->GetPrimaryMainFrame()->GetProcess()->GetDeprecatedID();
   EXPECT_NE(rph_id_1, rph_id_2);
+  histogram_tester.ExpectUniqueSample("Navigation.ProcessReuseOnCOOP.None",
+                                      false, 1);
 }
 
 // Tests the behavior around COOP BrowsingInstance swap when prerendering a COOP
@@ -4803,6 +4825,7 @@
 // Regression test for crbug.com/1519131.
 IN_PROC_BROWSER_TEST_P(ProcessReuseOnPrerenderCOOPSwapBrowserTest,
                        COOPSwapForPrerenderingCOOPPage) {
+  base::HistogramTester histogram_tester;
   GURL initial_page(https_server()->GetURL("a.test", "/empty.html"));
   GURL prerender_page(https_server()->GetURL(
       "a.test", "/set-header?Cross-Origin-Opener-Policy: same-origin"));
@@ -4858,6 +4881,8 @@
   EXPECT_NE(bi_token_2, bi_token_3);
   // Renderer process is reused.
   EXPECT_EQ(rph_id_2, rph_id_3);
+  histogram_tester.ExpectUniqueSample("Navigation.ProcessReuseOnCOOP.Prerender",
+                                      true, 1);
 }
 
 // TODO(crbug.com/40138297). Test inheritance of the virtual browsing
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc
index 7aa3fc3..20e92c7f 100644
--- a/content/browser/service_worker/service_worker_browsertest.cc
+++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -5245,9 +5245,16 @@
           network::mojom::ServiceWorkerRouterSourceType::kNetwork));
 }
 
+// TODO(crbug.com/406829401): Re-enable this test
+#if defined(THREAD_SANITIZER)
+#define MAYBE_NetworkRequest_Wins_PassThrough \
+  DISABLED_NetworkRequest_Wins_PassThrough
+#else
+#define MAYBE_NetworkRequest_Wins_PassThrough NetworkRequest_Wins_PassThrough
+#endif
 IN_PROC_BROWSER_TEST_P(
     ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
-    NetworkRequest_Wins_PassThrough) {
+    MAYBE_NetworkRequest_Wins_PassThrough) {
   // Register the ServiceWorker and navigate to the in scope URL.
   SetupAndRegisterServiceWorker();
   // Capture the response head.
@@ -5387,9 +5394,17 @@
             GetInnerText());
 }
 
+// TODO(crbug.com/406829401): Re-enable this test
+#if defined(THREAD_SANITIZER)
+#define MAYBE_NetworkRequest_Wins_Fetch_No_Respond \
+  DISABLED_NetworkRequest_Wins_Fetch_No_Respond
+#else
+#define MAYBE_NetworkRequest_Wins_Fetch_No_Respond \
+  FetchHandler_NetworkRequest_Wins_Fetch_No_Respond
+#endif
 IN_PROC_BROWSER_TEST_P(
     ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
-    NetworkRequest_Wins_Fetch_No_Respond) {
+    MAYBE_NetworkRequest_Wins_Fetch_No_Respond) {
   // Register the ServiceWorker and navigate to the in scope URL.
   SetupAndRegisterServiceWorker();
   NavigateToURLBlockUntilNavigationsComplete(
@@ -5697,9 +5712,15 @@
   EXPECT_EQ(1, GetRequestCount(path_after_redirect));
 }
 
+// TODO(crbug.com/406829401): Re-enable this test
+#if defined(THREAD_SANITIZER)
+#define MAYBE_FetchHandler_PassThrough DISABLED_FetchHandler_PassThrough
+#else
+#define MAYBE_FetchHandler_PassThrough FetchHandler_PassThrough
+#endif
 IN_PROC_BROWSER_TEST_P(
     ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
-    FetchHandler_PassThrough) {
+    MAYBE_FetchHandler_PassThrough) {
   // Register the ServiceWorker and navigate to the in scope URL.
   scoped_refptr<ServiceWorkerVersion> version = SetupAndRegisterServiceWorker();
   // Capture the response head.
@@ -5728,9 +5749,16 @@
   EXPECT_EQ(1, GetRequestCount(relative_url));
 }
 
+// TODO(crbug.com/406829401): Re-enable this test
+#if defined(THREAD_SANITIZER)
+#define MAYBE_FetchHandler_PassThrough_Clone \
+  DISABLED_FetchHandler_PassThrough_Clone
+#else
+#define MAYBE_FetchHandler_PassThrough_Clone FetchHandler_PassThrough_Clone
+#endif
 IN_PROC_BROWSER_TEST_P(
     ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
-    FetchHandler_PassThrough_Clone) {
+    MAYBE_FetchHandler_PassThrough_Clone) {
   // Register the ServiceWorker and navigate to the in scope URL.
   scoped_refptr<ServiceWorkerVersion> version = SetupAndRegisterServiceWorker();
   // URL which create a cloned request and pass-through.
diff --git a/content/browser/ukm_internals_ui.cc b/content/browser/ukm_internals_ui.cc
index c481ae5d5a..e8cae42 100644
--- a/content/browser/ukm_internals_ui.cc
+++ b/content/browser/ukm_internals_ui.cc
@@ -92,7 +92,7 @@
 }  // namespace
 
 // Changes to this class should be in sync with its iOS equivalent
-// ios/chrome/browser/ui/webui/ukm_internals_ui.mm
+// ios/chrome/browser/webui/ui_bundled/ukm_internals_ui.mm
 UkmInternalsUI::UkmInternalsUI(WebUI* web_ui) : WebUIController(web_ui) {
   ukm::UkmService* ukm_service = GetContentClient()->browser()->GetUkmService();
   web_ui->AddMessageHandler(std::make_unique<UkmMessageHandler>(ukm_service));
diff --git a/content/browser/webid/digital_credentials/cross_device_request_dispatcher.cc b/content/browser/webid/digital_credentials/cross_device_request_dispatcher.cc
index 5d43ede..9b1be32 100644
--- a/content/browser/webid/digital_credentials/cross_device_request_dispatcher.cc
+++ b/content/browser/webid/digital_credentials/cross_device_request_dispatcher.cc
@@ -191,14 +191,14 @@
       std::move(callback_).Run(
           Response(DigitalIdentityProvider::DigitalCredential(
               base::OptionalFromPtr(data_dict.FindString("protocol")),
-              base::WriteJson(*wallet_data).value_or(""))));
+              wallet_data->Clone())));
       return;
     }
   }
   FIDO_LOG(EVENT) << "No proper standard format is received from the mobile "
                      "device. Fallback to legacy format.";
   std::move(callback_).Run(Response(DigitalIdentityProvider::DigitalCredential(
-      /*protocol=*/std::nullopt, base::WriteJson(*data).value_or(""))));
+      /*protocol=*/std::nullopt, data->Clone())));
 }
 
 }  // namespace content::digital_credentials::cross_device
diff --git a/content/browser/webid/digital_credentials/cross_device_request_dispatcher_unittest.cc b/content/browser/webid/digital_credentials/cross_device_request_dispatcher_unittest.cc
index 1c4114e..5d81893 100644
--- a/content/browser/webid/digital_credentials/cross_device_request_dispatcher_unittest.cc
+++ b/content/browser/webid/digital_credentials/cross_device_request_dispatcher_unittest.cc
@@ -27,6 +27,7 @@
 #include "url/gurl.h"
 #include "url/origin.h"
 
+using base::JSONReader;
 using testing::NiceMock;
 
 namespace content::digital_credentials::cross_device {
@@ -138,7 +139,8 @@
       device::cablev2::PayloadType::kJSON,
       R"({"response": {"digital": {"data": {"vp_token" : "token"}}}})");
   ASSERT_TRUE(result.has_value());
-  ASSERT_EQ(result.value()->data, R"({"vp_token":"token"})");
+  ASSERT_EQ(result.value()->data,
+            JSONReader::Read(R"({"vp_token":"token"})").value());
   EXPECT_FALSE(result.value()->protocol.has_value());
 }
 
@@ -206,7 +208,8 @@
            }
          })");
   ASSERT_TRUE(result.has_value());
-  EXPECT_EQ(result.value()->data, R"({"key":"value"})");
+  EXPECT_EQ(result.value()->data,
+            JSONReader::Read(R"({"key":"value"})").value());
   EXPECT_EQ(result.value()->protocol, "ProtocolInResponse");
 }
 
@@ -224,7 +227,8 @@
            }
          })");
   ASSERT_TRUE(result.has_value());
-  EXPECT_EQ(result.value()->data, R"({"key":"value"})");
+  EXPECT_EQ(result.value()->data,
+            JSONReader::Read(R"({"key":"value"})").value());
   EXPECT_FALSE(result.value()->protocol.has_value());
 }
 
diff --git a/content/browser/webid/digital_credentials/digital_identity_request_impl.cc b/content/browser/webid/digital_credentials/digital_identity_request_impl.cc
index a924c03b..708f1b3 100644
--- a/content/browser/webid/digital_credentials/digital_identity_request_impl.cc
+++ b/content/browser/webid/digital_credentials/digital_identity_request_impl.cc
@@ -42,6 +42,7 @@
 
 namespace content {
 namespace {
+using base::Value;
 
 constexpr char kOpenid4vpProtocol[] = "openid4vp";
 constexpr char kOpenid4vp10Protocol[] = "openid4vp1.0";
@@ -339,13 +340,12 @@
 
 void DigitalIdentityRequestImpl::CompleteRequest(
     std::optional<std::string> protocol,
-    const base::expected<DigitalIdentityProvider::DigitalCredential,
-                         RequestStatusForMetrics>& response) {
-  CompleteRequestWithStatus(
-      std::move(protocol),
+    base::expected<DigitalIdentityProvider::DigitalCredential,
+                   RequestStatusForMetrics> response) {
+  RequestDigitalIdentityStatus status =
       response.has_value() ? RequestDigitalIdentityStatus::kSuccess
-                           : ToRequestDigitalIdentityStatus(response.error()),
-      response);
+                           : ToRequestDigitalIdentityStatus(response.error());
+  CompleteRequestWithStatus(std::move(protocol), status, std::move(response));
 }
 
 void DigitalIdentityRequestImpl::CompleteRequestWithError(
@@ -357,8 +357,8 @@
 void DigitalIdentityRequestImpl::CompleteRequestWithStatus(
     std::optional<std::string> protocol,
     RequestDigitalIdentityStatus status,
-    const base::expected<DigitalIdentityProvider::DigitalCredential,
-                         RequestStatusForMetrics>& response) {
+    base::expected<DigitalIdentityProvider::DigitalCredential,
+                   RequestStatusForMetrics> response) {
   // Invalidate pending requests in case that the request gets aborted.
   weak_ptr_factory_.InvalidateWeakPtrs();
 
@@ -383,8 +383,9 @@
     // absent, the protocol specified in the original request will be used
     // instead. This fallback mechanism maintains backward compatibility with
     // digital wallets that do not include the protocol in their response.
-    std::move(callback_).Run(
-        status, response->protocol.value_or(protocol.value()), response->data);
+    std::move(callback_).Run(status,
+                             response->protocol.value_or(protocol.value()),
+                             std::move(response->data));
   } else {
     std::move(callback_).Run(status, std::nullopt, std::nullopt);
   }
@@ -601,7 +602,8 @@
         base::BindOnce(&DigitalIdentityRequestImpl::CompleteRequest,
                        weak_ptr_factory_.GetWeakPtr(), protocol,
                        DigitalIdentityProvider::DigitalCredential(
-                           protocol, "fake_test_token")),
+                           protocol, Value(Value::Dict().Set(
+                                         "token", "fake_test_token")))),
         base::Milliseconds(1));
     return;
   }
@@ -655,7 +657,8 @@
         base::BindOnce(&DigitalIdentityRequestImpl::CompleteRequest,
                        weak_ptr_factory_.GetWeakPtr(), protocol,
                        DigitalIdentityProvider::DigitalCredential(
-                           protocol, "fake_test_token")),
+                           protocol, Value(Value::Dict().Set(
+                                         "token", "fake_test_token")))),
         base::Milliseconds(1));
     return;
   }
diff --git a/content/browser/webid/digital_credentials/digital_identity_request_impl.h b/content/browser/webid/digital_credentials/digital_identity_request_impl.h
index aee66cfd..a87d2f4d 100644
--- a/content/browser/webid/digital_credentials/digital_identity_request_impl.h
+++ b/content/browser/webid/digital_credentials/digital_identity_request_impl.h
@@ -102,8 +102,8 @@
   // `status_for_metrics`.
   void CompleteRequest(
       std::optional<std::string> protocol,
-      const base::expected<DigitalIdentityProvider::DigitalCredential,
-                           DigitalIdentityProvider::RequestStatusForMetrics>&
+      base::expected<DigitalIdentityProvider::DigitalCredential,
+                     DigitalIdentityProvider::RequestStatusForMetrics>
           status_for_metrics);
 
   void CompleteRequestWithError(
@@ -112,8 +112,8 @@
   void CompleteRequestWithStatus(
       std::optional<std::string> protocol,
       blink::mojom::RequestDigitalIdentityStatus status,
-      const base::expected<DigitalIdentityProvider::DigitalCredential,
-                           DigitalIdentityProvider::RequestStatusForMetrics>&
+      base::expected<DigitalIdentityProvider::DigitalCredential,
+                     DigitalIdentityProvider::RequestStatusForMetrics>
           response);
 
   std::unique_ptr<DigitalIdentityProvider> provider_;
diff --git a/content/browser/webid/digital_credentials/digital_identity_request_impl_unittest.cc b/content/browser/webid/digital_credentials/digital_identity_request_impl_unittest.cc
index fa8a0a7..7c6ba06 100644
--- a/content/browser/webid/digital_credentials/digital_identity_request_impl_unittest.cc
+++ b/content/browser/webid/digital_credentials/digital_identity_request_impl_unittest.cc
@@ -36,6 +36,7 @@
 using base::ValueView;
 using testing::_;
 using testing::DoAll;
+using testing::Eq;
 using testing::Optional;
 using testing::WithArg;
 
@@ -919,7 +920,7 @@
 
 TEST_F(DigitalIdentityRequestImplTest, ShouldGetAndReturnProtocolInRequest) {
   const std::string kProtocol = "protocol";
-  const std::string kResponseData = R"({"token": "token data"})";
+  const Value kResponseData(Value::Dict().Set("token", "token data"));
 
   DigitalCredentialRequestPtr digital_credential_request =
       DigitalCredentialRequest::New();
@@ -942,14 +943,15 @@
         // to avoid dangling pointers after invoking the callback.
         reset_provider_pointer();
 
-        std::move(callback).Run(DigitalCredential(std::nullopt, kResponseData));
+        std::move(callback).Run(
+            DigitalCredential(std::nullopt, kResponseData.Clone()));
       }));
 
   base::MockCallback<GetCallback> mock_callback;
   // The protocol in the request should be used when invoking the callback,
   // since no protocol was available in the response.
   EXPECT_CALL(mock_callback, Run(RequestDigitalIdentityStatus::kSuccess,
-                                 Optional(kProtocol), Optional(kResponseData)))
+                                 Optional(kProtocol), _))
       .WillOnce(base::test::RunOnceClosure(run_loop.QuitClosure()));
 
   digital_identity_request_impl()->Get(std::move(requests),
@@ -962,7 +964,7 @@
 TEST_F(DigitalIdentityRequestImplTest, ShouldGetAndReturnProtocolInResponse) {
   const std::string kProtocolInRequest = "protocol_in_request";
   const std::string kProtocolInResponse = "protocol_in_response";
-  const std::string kResponseData = R"({"token": "token data"})";
+  const Value kResponseData(Value::Dict().Set("token", "token data"));
 
   DigitalCredentialRequestPtr digital_credential_request =
       DigitalCredentialRequest::New();
@@ -986,14 +988,13 @@
         reset_provider_pointer();
 
         std::move(callback).Run(
-            DigitalCredential(kProtocolInResponse, kResponseData));
+            DigitalCredential(kProtocolInResponse, kResponseData.Clone()));
       }));
 
   base::MockCallback<GetCallback> mock_callback;
   // The protocol in the response should be used when invoking the callback.
-  EXPECT_CALL(mock_callback,
-              Run(RequestDigitalIdentityStatus::kSuccess,
-                  Optional(kProtocolInResponse), Optional(kResponseData)))
+  EXPECT_CALL(mock_callback, Run(RequestDigitalIdentityStatus::kSuccess,
+                                 Optional(kProtocolInResponse), _))
       .WillOnce(base::test::RunOnceClosure(run_loop.QuitClosure()));
 
   digital_identity_request_impl()->Get(std::move(requests),
@@ -1059,7 +1060,7 @@
 
 TEST_F(DigitalIdentityRequestImplTest,
        ShouldErrorWhenMultipleRequestsAndNoProtocolInResponse) {
-  const std::string kResponseData = R"({"token": "token data"})";
+  const Value kResponseData(Value::Dict().Set("token", "token data"));
 
   std::vector<DigitalCredentialRequestPtr> requests;
 
@@ -1082,14 +1083,15 @@
 
   // Simulate a provider that returns a response without a protocol.
   EXPECT_CALL(*mock_digital_identity_provider(), Get)
-      .WillOnce(WithArg<3>([this](DigitalIdentityCallback callback) {
-        // Running the `callback` will destroy the provider, reset the pointer
-        // to avoid dangling pointers after invoking the callback.
-        reset_provider_pointer();
+      .WillOnce(
+          WithArg<3>([this, &kResponseData](DigitalIdentityCallback callback) {
+            // Running the `callback` will destroy the provider, reset the
+            // pointer to avoid dangling pointers after invoking the callback.
+            reset_provider_pointer();
 
-        std::move(callback).Run(DigitalCredential(
-            /*protocol=*/std::nullopt, R"({"token": "token data"})"));
-      }));
+            std::move(callback).Run(DigitalCredential(
+                /*protocol=*/std::nullopt, kResponseData.Clone()));
+          }));
 
   base::MockCallback<GetCallback> mock_callback;
   // The callback should be invoked with an error since the digital wallet
diff --git a/content/browser/webid/webid_browsertest.cc b/content/browser/webid/webid_browsertest.cc
index ee477b4..3b5c720e 100644
--- a/content/browser/webid/webid_browsertest.cc
+++ b/content/browser/webid/webid_browsertest.cc
@@ -1291,8 +1291,10 @@
 // JS API
 IN_PROC_BROWSER_TEST_F(WebIdDigitalCredentialsBrowserTest,
                        NavigatorIdentityApi) {
-  constexpr char kIdentityProviderResponse[] =
-      "&vp_token=token&presentation_submission=bar";
+  base::Value kIdentityProviderResponse =
+      base::JSONReader::Read(
+          R"({"vp_token": "token data" , "presentation_submission":"bar"})")
+          .value();
 
   idp_server()->SetConfigResponseDetails(BuildValidConfigDetails());
   MockDigitalIdentityProvider* digital_identity_provider =
@@ -1322,10 +1324,10 @@
 
   EXPECT_CALL(*digital_identity_provider, Get(_, _, JsonMatches(json), _))
       .WillOnce(WithArg<3>(
-          [kIdentityProviderResponse](
+          [&kIdentityProviderResponse](
               DigitalIdentityProvider::DigitalIdentityCallback callback) {
-            std::move(callback).Run(
-                DigitalCredential("openid4vp", kIdentityProviderResponse));
+            std::move(callback).Run(DigitalCredential(
+                "openid4vp", kIdentityProviderResponse.Clone()));
           }));
 
   EXPECT_EQ(kIdentityProviderResponse, RunDigitalIdentityValidRequest(shell()));
@@ -1335,8 +1337,10 @@
 // navigator.credentials JS API too.
 IN_PROC_BROWSER_TEST_F(WebIdDigitalCredentialsBrowserTest,
                        NavigatorCredentialsApi) {
-  constexpr char kIdentityProviderResponse[] =
-      "&vp_token=token&presentation_submission=bar";
+  base::Value kIdentityProviderResponse =
+      base::JSONReader::Read(
+          R"({"vp_token": "token data" , "presentation_submission":"bar"})")
+          .value();
 
   idp_server()->SetConfigResponseDetails(BuildValidConfigDetails());
   MockDigitalIdentityProvider* digital_identity_provider =
@@ -1366,10 +1370,10 @@
 
   EXPECT_CALL(*digital_identity_provider, Get(_, _, JsonMatches(json), _))
       .WillOnce(WithArg<3>(
-          [kIdentityProviderResponse](
+          [&kIdentityProviderResponse](
               DigitalIdentityProvider::DigitalIdentityCallback callback) {
-            std::move(callback).Run(
-                DigitalCredential("openid4vp", kIdentityProviderResponse));
+            std::move(callback).Run(DigitalCredential(
+                "openid4vp", kIdentityProviderResponse.Clone()));
           }));
 
   std::string script = base::StringPrintf(
@@ -1387,6 +1391,9 @@
       static_cast<MockDigitalIdentityProvider*>(
           test_browser_client_->GetDigitalIdentityProviderForTests());
 
+  base::Value kResponse =
+      base::JSONReader::Read(R"({"token":"test-mdoc"})").value();
+
   EXPECT_CALL(*digital_identity_provider, Get)
       .WillOnce(WithArg<3>(
           [&](DigitalIdentityProvider::DigitalIdentityCallback callback) {
@@ -1395,10 +1402,10 @@
                 "may be outstanding at one time.",
                 ExtractJsError(RunDigitalIdentityValidRequest(shell())));
             std::move(callback).Run(
-                DigitalCredential("openid4vp", "test-mdoc"));
+                DigitalCredential("openid4vp", kResponse.Clone()));
           }));
 
-  EXPECT_EQ("test-mdoc", RunDigitalIdentityValidRequest(shell()));
+  EXPECT_EQ(kResponse, RunDigitalIdentityValidRequest(shell()));
 }
 
 // Test that when the user declines a digital identity request, the error
@@ -1437,8 +1444,9 @@
   EXPECT_CALL(*digital_identity_provider, Get)
       .WillOnce(WithArg<3>(
           [](DigitalIdentityProvider::DigitalIdentityCallback callback) {
-            std::move(callback).Run(
-                DigitalCredential("openid4vp", "test-mdoc"));
+            std::move(callback).Run(DigitalCredential(
+                "openid4vp",
+                base::JSONReader::Read(R"({"token":"test-mdoc"})").value()));
           }));
 
   RunDigitalIdentityValidRequest(shell());
diff --git a/content/public/browser/digital_identity_provider.cc b/content/public/browser/digital_identity_provider.cc
index 4043218f..aea9a10 100644
--- a/content/public/browser/digital_identity_provider.cc
+++ b/content/public/browser/digital_identity_provider.cc
@@ -7,7 +7,7 @@
 namespace content {
 DigitalIdentityProvider::DigitalCredential::DigitalCredential(
     std::optional<std::string> protocol,
-    std::string data)
+    std::optional<base::Value> data)
     : protocol(std::move(protocol)), data(std::move(data)) {}
 DigitalIdentityProvider::DigitalCredential::DigitalCredential(
     DigitalCredential&& other) = default;
diff --git a/content/public/browser/digital_identity_provider.h b/content/public/browser/digital_identity_provider.h
index 2a12bda..75860931 100644
--- a/content/public/browser/digital_identity_provider.h
+++ b/content/public/browser/digital_identity_provider.h
@@ -26,7 +26,8 @@
 class CONTENT_EXPORT DigitalIdentityProvider {
  public:
   struct CONTENT_EXPORT DigitalCredential {
-    DigitalCredential(std::optional<std::string> protocol, std::string data);
+    DigitalCredential(std::optional<std::string> protocol,
+                      std::optional<base::Value> data);
     DigitalCredential(DigitalCredential&& other);
     DigitalCredential& operator=(DigitalCredential&& other);
     DigitalCredential(DigitalCredential& other) = delete;
@@ -34,7 +35,7 @@
     ~DigitalCredential();
 
     std::optional<std::string> protocol;
-    std::string data;
+    std::optional<base::Value> data;
   };
   // Do not reorder or change the values because the enum values are being
   // recorded in metrics.
@@ -80,7 +81,7 @@
       DigitalIdentityInterstitialCallback callback) = 0;
 
   using DigitalIdentityCallback = base::OnceCallback<void(
-      const base::expected<DigitalCredential, RequestStatusForMetrics>&)>;
+      base::expected<DigitalCredential, RequestStatusForMetrics>)>;
 
   // Coordinates the call to present a digital credential between the web and
   // native apps.
diff --git a/content/public/test/mock_captured_surface_controller.cc b/content/public/test/mock_captured_surface_controller.cc
index 80fb0d0..c6c17b9 100644
--- a/content/public/test/mock_captured_surface_controller.cc
+++ b/content/public/test/mock_captured_surface_controller.cc
@@ -9,6 +9,9 @@
 
 namespace content {
 
+using CapturedSurfaceControlResult =
+    ::blink::mojom::CapturedSurfaceControlResult;
+
 MockCapturedSurfaceController::MockCapturedSurfaceController(
     GlobalRenderFrameHostId capturer_rfh_id,
     WebContentsMediaCaptureId captured_wc_id)
@@ -19,15 +22,14 @@
 MockCapturedSurfaceController::~MockCapturedSurfaceController() = default;
 
 void MockCapturedSurfaceController::SetSendWheelResponse(
-    blink::mojom::CapturedSurfaceControlResult send_wheel_result) {
+    CapturedSurfaceControlResult send_wheel_result) {
   send_wheel_result_ = send_wheel_result;
 }
 
 void MockCapturedSurfaceController::SendWheel(
     blink::mojom::CapturedWheelActionPtr action,
-    base::OnceCallback<void(blink::mojom::CapturedSurfaceControlResult)>
-        reply_callback) {
-  std::optional<blink::mojom::CapturedSurfaceControlResult> send_wheel_result;
+    base::OnceCallback<void(CapturedSurfaceControlResult)> reply_callback) {
+  std::optional<CapturedSurfaceControlResult> send_wheel_result;
   std::swap(send_wheel_result_, send_wheel_result);
 
   CHECK(send_wheel_result);
@@ -35,31 +37,28 @@
 }
 
 void MockCapturedSurfaceController::SetUpdateZoomLevelResponse(
-    blink::mojom::CapturedSurfaceControlResult update_zoom_level_result) {
+    CapturedSurfaceControlResult update_zoom_level_result) {
   update_zoom_level_result_ = update_zoom_level_result;
 }
 
 void MockCapturedSurfaceController::UpdateZoomLevel(
     blink::mojom::ZoomLevelAction action,
-    base::OnceCallback<void(blink::mojom::CapturedSurfaceControlResult)>
-        reply_callback) {
+    base::OnceCallback<void(CapturedSurfaceControlResult)> reply_callback) {
   CHECK(update_zoom_level_result_);
-  const blink::mojom::CapturedSurfaceControlResult update_zoom_level_result =
+  const CapturedSurfaceControlResult update_zoom_level_result =
       *update_zoom_level_result_;
   update_zoom_level_result_ = std::nullopt;
   std::move(reply_callback).Run(update_zoom_level_result);
 }
 
 void MockCapturedSurfaceController::SetRequestPermissionResponse(
-    blink::mojom::CapturedSurfaceControlResult request_permission_result) {
+    CapturedSurfaceControlResult request_permission_result) {
   request_permission_result_ = request_permission_result;
 }
 
 void MockCapturedSurfaceController::RequestPermission(
-    base::OnceCallback<void(blink::mojom::CapturedSurfaceControlResult)>
-        reply_callback) {
-  std::optional<blink::mojom::CapturedSurfaceControlResult>
-      request_permission_result;
+    base::OnceCallback<void(CapturedSurfaceControlResult)> reply_callback) {
+  std::optional<CapturedSurfaceControlResult> request_permission_result;
   std::swap(request_permission_result_, request_permission_result);
 
   CHECK(request_permission_result);
diff --git a/content/public/test/mock_captured_surface_controller.h b/content/public/test/mock_captured_surface_controller.h
index c3bb828..a4c21f9 100644
--- a/content/public/test/mock_captured_surface_controller.h
+++ b/content/public/test/mock_captured_surface_controller.h
@@ -13,46 +13,44 @@
 namespace content {
 
 class MockCapturedSurfaceController final : public CapturedSurfaceController {
+ private:
+  using CapturedSurfaceControlResult =
+      ::blink::mojom::CapturedSurfaceControlResult;
+
  public:
   MockCapturedSurfaceController(GlobalRenderFrameHostId capturer_rfh_id,
                                 WebContentsMediaCaptureId captured_wc_id);
 
   ~MockCapturedSurfaceController() override;
 
-  void SetSendWheelResponse(
-      blink::mojom::CapturedSurfaceControlResult send_wheel_result);
+  void SetSendWheelResponse(CapturedSurfaceControlResult send_wheel_result);
 
   // CapturedSurfaceController impl
   MOCK_METHOD(void,
               UpdateCaptureTarget,
               (WebContentsMediaCaptureId),
               (override));
-  void SendWheel(
-      blink::mojom::CapturedWheelActionPtr action,
-      base::OnceCallback<void(blink::mojom::CapturedSurfaceControlResult)>
-          reply_callback) override;
+  void SendWheel(blink::mojom::CapturedWheelActionPtr action,
+                 base::OnceCallback<void(CapturedSurfaceControlResult)>
+                     reply_callback) override;
 
   void SetUpdateZoomLevelResponse(
-      blink::mojom::CapturedSurfaceControlResult update_zoom_level_result);
+      CapturedSurfaceControlResult update_zoom_level_result);
 
-  void UpdateZoomLevel(
-      blink::mojom::ZoomLevelAction action,
-      base::OnceCallback<void(blink::mojom::CapturedSurfaceControlResult)>
-          reply_callback) override;
+  void UpdateZoomLevel(blink::mojom::ZoomLevelAction action,
+                       base::OnceCallback<void(CapturedSurfaceControlResult)>
+                           reply_callback) override;
 
   void SetRequestPermissionResponse(
-      blink::mojom::CapturedSurfaceControlResult request_permission_result);
+      CapturedSurfaceControlResult request_permission_result);
 
-  void RequestPermission(
-      base::OnceCallback<void(blink::mojom::CapturedSurfaceControlResult)>
-          reply_callback) override;
+  void RequestPermission(base::OnceCallback<void(CapturedSurfaceControlResult)>
+                             reply_callback) override;
 
  private:
-  std::optional<blink::mojom::CapturedSurfaceControlResult> send_wheel_result_;
-  std::optional<blink::mojom::CapturedSurfaceControlResult>
-      update_zoom_level_result_;
-  std::optional<blink::mojom::CapturedSurfaceControlResult>
-      request_permission_result_;
+  std::optional<CapturedSurfaceControlResult> send_wheel_result_;
+  std::optional<CapturedSurfaceControlResult> update_zoom_level_result_;
+  std::optional<CapturedSurfaceControlResult> request_permission_result_;
 };
 
 }  // namespace content
diff --git a/docs/how_cc_works.md b/docs/how_cc_works.md
index a5b475cc..b08a2b7 100644
--- a/docs/how_cc_works.md
+++ b/docs/how_cc_works.md
@@ -269,12 +269,13 @@
 
 The compositing mode affects the choice of RasterBufferProvider that cc provides, which manages the raster process and resource management on the raster worker threads:
 
-* BitmapRasterBufferProvider: rasters software bitmaps for software compositing
+* ZeroCopyRasterBufferProvider: rasters software bitmaps (a) for software 
+  compositing into shared memory that is read directly by the software compositor 
+  and (b) for gpu compositing directly into a GpuMemoryBuffer (e.g. IOSurface), 
+  which is memory that can be mapped by CPU and used by the GPU
 
 * OneCopyRasterBufferProvider: rasters software bitmaps for gpu compositing into shared memory, which are then uploaded to gpu memory in the gpu process
 
-* ZeroCopyRasterBufferProvider: rasters software bitmaps for gpu compositing directly into a GpuMemoryBuffer (e.g. IOSurface), which is memory that can be mapped by CPU and used by the GPU
-
 * GpuRasterBufferProvider: rasters gpu textures for gpu compositing over a command buffer via paint commands (for gpu raster)
 
 Note, due to locks on the context, gpu raster is limited to one worker thread at a time, although image decoding can proceed in parallel on other threads.
diff --git a/extensions/common/extension_features.cc b/extensions/common/extension_features.cc
index f63eb21..649af6eb 100644
--- a/extensions/common/extension_features.cc
+++ b/extensions/common/extension_features.cc
@@ -32,10 +32,6 @@
              "ApiPermissionsHostAccessRequests",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
-BASE_FEATURE(kApiPrintingMarginsAndScale,
-             "ApiPrintingMarginsAndScale",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 BASE_FEATURE(kApiUserScriptsExecute,
              "ApiUserScriptsExecute",
              base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/extensions/common/extension_features.h b/extensions/common/extension_features.h
index 6fede66a..2f882dc 100644
--- a/extensions/common/extension_features.h
+++ b/extensions/common/extension_features.h
@@ -53,10 +53,6 @@
 // the permissions API.
 BASE_DECLARE_FEATURE(kApiPermissionsHostAccessRequests);
 
-// Controls whether chrome.Printing API uses margins and scale ticket items when
-// submitting a print job.
-BASE_DECLARE_FEATURE(kApiPrintingMarginsAndScale);
-
 // Controls the availability of executing user scripts programmatically using
 // the userScripts API.
 BASE_DECLARE_FEATURE(kApiUserScriptsExecute);
diff --git a/extensions/common/features/feature_flags.cc b/extensions/common/features/feature_flags.cc
index 4ee8769..60eeedf 100644
--- a/extensions/common/features/feature_flags.cc
+++ b/extensions/common/features/feature_flags.cc
@@ -24,7 +24,6 @@
     &extensions_features::kApiContentSettingsClipboard,
     &extensions_features::kApiEnterpriseKioskInput,
     &extensions_features::kApiPermissionsHostAccessRequests,
-    &extensions_features::kApiPrintingMarginsAndScale,
     &extensions_features::kApiUserScriptsExecute,
     &extensions_features::kApiUserScriptsMultipleWorlds,
     &extensions_features::kApiOdfsConfigPrivate,
diff --git a/ios/PRESUBMIT_test.py b/ios/PRESUBMIT_test.py
index 6d0e2084..ce5c443 100755
--- a/ios/PRESUBMIT_test.py
+++ b/ios/PRESUBMIT_test.py
@@ -316,7 +316,8 @@
                 'test_file.json', [],
                 action='A'),
             PRESUBMIT_test_mocks.MockFile(
-                'ios/chrome/browser/ui/colors/test_file.mm', [], action='M')
+                'ios/chrome/browser/colors/ui_bundled/test_file.mm', [],
+                action='M')
         ]
         results = PRESUBMIT._CheckNewColorIntroduction(self.mock_input,
                                                        self.mock_output)
diff --git a/ios/chrome/browser/DEPS b/ios/chrome/browser/DEPS
index 80383b6a..093d252 100644
--- a/ios/chrome/browser/DEPS
+++ b/ios/chrome/browser/DEPS
@@ -182,11 +182,6 @@
   "+ios/chrome/browser/shared/ui",
   "+ios/chrome/browser/shared/public",
 
-  # ios/chrome/browser should not depend on ios/chrome/browser/ui except
-  # on commands.
-  "-ios/chrome/browser/ui",
-  "-ios/common/ui",
-  "+ios/chrome/browser/ui/commands",
   "+ios/chrome/browser/keyboard/ui_bundled/UIKeyCommand+Chrome.h",
 
   # For tests.
@@ -202,17 +197,12 @@
 
   # Temporary, remove when upstream updated
   "+ios/chrome/browser/popup_menu/ui_bundled/popup_menu_constants.h",
-  "+ios/chrome/browser/ui/page_info/features.h",
-  "+ios/chrome/browser/ui/page_info/page_info_app_interface.h",
 ]
 
 specific_include_rules = {
   ".*test\.mm": [
     "+components/signin/internal/identity_manager/account_capabilities_constants.h",
     "+components/previous_session_info/previous_session_info_private.h",
-    # TODO(crbug.com/40820398): browser should not depend on UI, this is a
-    # blanket exception for tests.
-    "+ios/chrome/browser/ui",
     # Use ios/chrome/browser/authentication/ui_bundled/signin_earl_grey.h instead
     "-ios/chrome/browser/authentication/ui_bundled/signin_earl_grey_app_interface.h",
     # use ios/chrome/browser/bookmarks/ui_bundled/bookmark_earl_grey.h instead
diff --git a/ios/chrome/browser/authentication/ui_bundled/authentication_flow/BUILD.gn b/ios/chrome/browser/authentication/ui_bundled/authentication_flow/BUILD.gn
index 7f760b4a..6fb0627 100644
--- a/ios/chrome/browser/authentication/ui_bundled/authentication_flow/BUILD.gn
+++ b/ios/chrome/browser/authentication/ui_bundled/authentication_flow/BUILD.gn
@@ -15,6 +15,7 @@
     "//base",
     "//components/bookmarks/common",
     "//components/reading_list/features:flags",
+    "//components/signin/core/browser",
     "//components/signin/public/base",
     "//components/signin/public/identity_manager:tribool",
     "//components/sync/base",
diff --git a/ios/chrome/browser/authentication/ui_bundled/authentication_flow/authentication_flow.mm b/ios/chrome/browser/authentication/ui_bundled/authentication_flow/authentication_flow.mm
index 59c70662..e24fa2a 100644
--- a/ios/chrome/browser/authentication/ui_bundled/authentication_flow/authentication_flow.mm
+++ b/ios/chrome/browser/authentication/ui_bundled/authentication_flow/authentication_flow.mm
@@ -16,6 +16,7 @@
 #import "components/policy/core/browser/signin/profile_separation_policies.h"
 #import "components/prefs/pref_service.h"
 #import "components/reading_list/features/reading_list_switches.h"
+#import "components/signin/core/browser/active_primary_accounts_metrics_recorder.h"
 #import "components/signin/public/base/signin_pref_names.h"
 #import "components/signin/public/identity_manager/tribool.h"
 #import "components/sync/base/account_pref_utils.h"
@@ -714,7 +715,14 @@
 - (void)handOverToAuthenticationFlowInProfileStep {
   CHECK(_browserForAuthenticationFlowInProfile);
   BOOL isManagedIdentity = _identityToSignInHostedDomain.length > 0;
+  // If `_wasPrimaryAccountManaged` is unset, then this was a signin, not an
+  // account switch.
   if (_wasPrimaryAccountManaged.has_value()) {
+    if (signin::ActivePrimaryAccountsMetricsRecorder* metricsRecorder =
+            GetApplicationContext()
+                ->GetActivePrimaryAccountsMetricsRecorder()) {
+      metricsRecorder->AccountWasSwitched();
+    }
     RecordAccountSwitchTypeMetric(_wasPrimaryAccountManaged.value(),
                                   isManagedIdentity);
   }
diff --git a/ios/chrome/browser/autofill/ui_bundled/DEPS b/ios/chrome/browser/autofill/ui_bundled/DEPS
index 95ff147..4ac94e5 100644
--- a/ios/chrome/browser/autofill/ui_bundled/DEPS
+++ b/ios/chrome/browser/autofill/ui_bundled/DEPS
@@ -13,7 +13,6 @@
   "+ios/chrome/browser/settings/ui_bundled/autofill/autofill_constants.h",
   "+ios/chrome/browser/settings/ui_bundled/autofill/autofill_settings_profile_edit_table_view_controller_delegate.h",
   "+ios/chrome/browser/settings/ui_bundled/password",
-  "+ios/chrome/browser/ui/alert_view",
   "+ios/chrome/browser/webdata_services/model/web_data_service_factory.h",
 ]
 
diff --git a/ios/chrome/browser/bookmarks/ui_bundled/DEPS b/ios/chrome/browser/bookmarks/ui_bundled/DEPS
index e123a27..fb32dec2 100644
--- a/ios/chrome/browser/bookmarks/ui_bundled/DEPS
+++ b/ios/chrome/browser/bookmarks/ui_bundled/DEPS
@@ -2,7 +2,6 @@
   "+ios/chrome/browser/signin/model",
   "+ios/chrome/browser/sync/model",
   "+ios/chrome/browser/authentication/ui_bundled",
-  "+ios/chrome/browser/ui/legacy_bookmarks",
   "+ios/chrome/browser/popup_menu/ui_bundled/popup_menu_constants.h",
   "+ios/chrome/browser/keyboard/ui_bundled",
   "+ios/chrome/browser/incognito_reauth/ui_bundled",
diff --git a/ios/chrome/browser/browser_state/model/DEPS b/ios/chrome/browser/browser_state/model/DEPS
index e4d643b..7e7414c0f 100644
--- a/ios/chrome/browser/browser_state/model/DEPS
+++ b/ios/chrome/browser/browser_state/model/DEPS
@@ -22,7 +22,6 @@
   # TODO(crbug.com/40820398): Remove this dependency.
   "^browser_state_keyed_service_factories.mm": [
     "+ios/chrome/browser",
-    "-ios/chrome/browser/ui",
     "+ios/chrome/browser/voice/ui_bundled/text_to_speech_playback_controller_factory.h",
   ],
 }
diff --git a/ios/chrome/browser/browser_view/ui_bundled/BUILD.gn b/ios/chrome/browser/browser_view/ui_bundled/BUILD.gn
index 713802a..d52ad638 100644
--- a/ios/chrome/browser/browser_view/ui_bundled/BUILD.gn
+++ b/ios/chrome/browser/browser_view/ui_bundled/BUILD.gn
@@ -167,7 +167,6 @@
     "//ios/chrome/browser/page_info/ui_bundled:coordinator",
     "//ios/chrome/browser/page_info/ui_bundled/requirements",
     "//ios/chrome/browser/parcel_tracking:features",
-    "//ios/chrome/browser/parcel_tracking:opt_in_status",
     "//ios/chrome/browser/parcel_tracking:prefs",
     "//ios/chrome/browser/parcel_tracking:tracking_source",
     "//ios/chrome/browser/passwords/model",
diff --git a/ios/chrome/browser/browser_view/ui_bundled/DEPS b/ios/chrome/browser/browser_view/ui_bundled/DEPS
index d4ffd2f..48ec96c 100644
--- a/ios/chrome/browser/browser_view/ui_bundled/DEPS
+++ b/ios/chrome/browser/browser_view/ui_bundled/DEPS
@@ -102,7 +102,6 @@
   "+ios/chrome/browser/tips_notifications/coordinator",
   "+ios/chrome/browser/toolbar/ui_bundled",
   "+ios/chrome/browser/translate/model/chrome_ios_translate_client.h",
-  "+ios/chrome/browser/ui",
   "+ios/chrome/browser/page_info/ui_bundled",
   "+ios/chrome/browser/unit_conversion/ui_bundled/unit_conversion_coordinator.h",
   "+ios/chrome/browser/url_loading/model",
diff --git a/ios/chrome/browser/collaboration/model/ios_collaboration_controller_delegate.h b/ios/chrome/browser/collaboration/model/ios_collaboration_controller_delegate.h
index c3d978fe..7a5c9885 100644
--- a/ios/chrome/browser/collaboration/model/ios_collaboration_controller_delegate.h
+++ b/ios/chrome/browser/collaboration/model/ios_collaboration_controller_delegate.h
@@ -72,6 +72,15 @@
   // be called to dismiss the join screen.
   void OnCollaborationJoinSuccess(ProceduralBlock dismiss_join_screen);
 
+  // Called when a group is about to be unshared. The unsharing is blocked until
+  // `continuation_block` is called.
+  void WillUnshareGroup(std::optional<tab_groups::LocalTabGroupID> local_id,
+                        void (^continuation_block)(BOOL));
+
+  // Called when the collaboration group is deleted, making the group unshared.
+  void DidUnshareGroup(std::optional<tab_groups::LocalTabGroupID> local_id,
+                       NSError* error);
+
   // Callback called when the user acknowledge the error.
   void ErrorAccepted(ResultCallback result);
 
diff --git a/ios/chrome/browser/collaboration/model/ios_collaboration_controller_delegate.mm b/ios/chrome/browser/collaboration/model/ios_collaboration_controller_delegate.mm
index f3d0af7..8a98797 100644
--- a/ios/chrome/browser/collaboration/model/ios_collaboration_controller_delegate.mm
+++ b/ios/chrome/browser/collaboration/model/ios_collaboration_controller_delegate.mm
@@ -343,6 +343,32 @@
   dismiss_join_screen_callback_ = base::BindOnce(dismiss_join_screen);
 }
 
+void IOSCollaborationControllerDelegate::WillUnshareGroup(
+    std::optional<tab_groups::LocalTabGroupID> local_id,
+    void (^continuation_block)(BOOL)) {
+  if (!local_id.has_value()) {
+    continuation_block(YES);
+  }
+  tab_groups::TabGroupSyncService* tab_group_sync_service =
+      tab_groups::TabGroupSyncServiceFactory::GetForProfile(
+          browser_->GetProfile());
+  tab_group_sync_service->AboutToUnShareTabGroup(
+      local_id.value(), base::BindOnce(continuation_block, YES));
+}
+
+void IOSCollaborationControllerDelegate::DidUnshareGroup(
+    std::optional<tab_groups::LocalTabGroupID> local_id,
+    NSError* error) {
+  if (!local_id.has_value()) {
+    return;
+  }
+  bool success = (error == nil);
+  tab_groups::TabGroupSyncService* tab_group_sync_service =
+      tab_groups::TabGroupSyncServiceFactory::GetForProfile(
+          browser_->GetProfile());
+  tab_group_sync_service->OnTabGroupUnShareComplete(local_id.value(), success);
+}
+
 void IOSCollaborationControllerDelegate::ErrorAccepted(ResultCallback result) {
   if (dismiss_join_screen_callback_) {
     std::move(dismiss_join_screen_callback_).Run();
@@ -505,7 +531,9 @@
           browser_->GetProfile());
   tab_groups::CollaborationId collaboration_id =
       tab_groups::utils::GetTabGroupCollabID(either_id, tab_group_sync_service);
-  if (collaboration_id->empty()) {
+  std::optional<tab_groups::SavedTabGroup> group =
+      tab_group_sync_service->GetGroup(either_id);
+  if (collaboration_id->empty() || !group.has_value()) {
     std::move(result).Run(CollaborationControllerDelegate::Outcome::kFailure);
     return;
   }
@@ -522,6 +550,14 @@
   config.completion = ^(ShareKitFlowOutcome outcome) {
     completion_block(ConvertOutcome(outcome));
   };
+  std::optional<tab_groups::LocalTabGroupID> local_id = group->local_group_id();
+  config.willUnshareGroupBlock = base::CallbackToBlock(
+      base::BindOnce(&IOSCollaborationControllerDelegate::WillUnshareGroup,
+                     weak_ptr_factory_.GetWeakPtr(), local_id));
+
+  config.didUnshareGroupBlock = base::CallbackToBlock(
+      base::BindOnce(&IOSCollaborationControllerDelegate::DidUnshareGroup,
+                     weak_ptr_factory_.GetWeakPtr(), local_id));
 
   session_id_ = share_kit_service_->ManageTabGroup(config);
 }
diff --git a/ios/chrome/browser/commerce/model/BUILD.gn b/ios/chrome/browser/commerce/model/BUILD.gn
index dbcb28fb..e22d29e 100644
--- a/ios/chrome/browser/commerce/model/BUILD.gn
+++ b/ios/chrome/browser/commerce/model/BUILD.gn
@@ -51,7 +51,6 @@
     "//ios/chrome/browser/history/model",
     "//ios/chrome/browser/optimization_guide/model",
     "//ios/chrome/browser/parcel_tracking:features",
-    "//ios/chrome/browser/parcel_tracking:opt_in_status",
     "//ios/chrome/browser/power_bookmarks/model",
     "//ios/chrome/browser/sessions/model",
     "//ios/chrome/browser/shared/model/application_context",
diff --git a/ios/chrome/browser/content_suggestions/ui_bundled/DEPS b/ios/chrome/browser/content_suggestions/ui_bundled/DEPS
index dceda6f..0669d4f 100644
--- a/ios/chrome/browser/content_suggestions/ui_bundled/DEPS
+++ b/ios/chrome/browser/content_suggestions/ui_bundled/DEPS
@@ -14,7 +14,6 @@
   "+ios/chrome/browser/lens/ui_bundled",
   "+ios/chrome/browser/location_bar/ui_bundled/location_bar_constants.h",
   "+ios/chrome/browser/start_surface/ui_bundled",
-  "+ios/chrome/browser/ui/whats_new/whats_new_util.h",
   "+ios/chrome/browser/toolbar/ui_bundled/public",
   "+ios/chrome/browser/push_notification/ui_bundled",
   "+ios/chrome/browser/ntp/model/set_up_list_item_type.h",
diff --git a/ios/chrome/browser/content_suggestions/ui_bundled/magic_stack_half_sheet_mediator.mm b/ios/chrome/browser/content_suggestions/ui_bundled/magic_stack_half_sheet_mediator.mm
index 7d6303f..7b0811c 100644
--- a/ios/chrome/browser/content_suggestions/ui_bundled/magic_stack_half_sheet_mediator.mm
+++ b/ios/chrome/browser/content_suggestions/ui_bundled/magic_stack_half_sheet_mediator.mm
@@ -78,28 +78,28 @@
 }
 
 - (void)disconnect {
+  [_mostVisitedSitesEnabled stop];
+  [_mostVisitedSitesEnabled setObserver:nil];
+  _mostVisitedSitesEnabled = nil;
+
+  [_setUpListDisabled stop];
+  [_setUpListDisabled setObserver:nil];
+  _setUpListDisabled = nil;
+
+  [_safetyCheckDisabled stop];
+  [_safetyCheckDisabled setObserver:nil];
+  _safetyCheckDisabled = nil;
+
+  [_tabResumptionDisabled stop];
+  [_tabResumptionDisabled setObserver:nil];
+  _tabResumptionDisabled = nil;
+
+  [_parcelTrackingDisabled stop];
+  [_parcelTrackingDisabled setObserver:nil];
+  _parcelTrackingDisabled = nil;
+
   _localState = nil;
   _profilePrefs = nil;
-  if (_mostVisitedSitesEnabled) {
-    [_mostVisitedSitesEnabled setObserver:nil];
-    _mostVisitedSitesEnabled = nil;
-  }
-  if (_setUpListDisabled) {
-    [_setUpListDisabled setObserver:nil];
-    _setUpListDisabled = nil;
-  }
-  if (_safetyCheckDisabled) {
-    [_safetyCheckDisabled setObserver:nil];
-    _safetyCheckDisabled = nil;
-  }
-  if (_tabResumptionDisabled) {
-    [_tabResumptionDisabled setObserver:nil];
-    _tabResumptionDisabled = nil;
-  }
-  if (_parcelTrackingDisabled) {
-    [_parcelTrackingDisabled setObserver:nil];
-    _parcelTrackingDisabled = nil;
-  }
 }
 
 - (void)setConsumer:(id<MagicStackHalfSheetConsumer>)consumer {
diff --git a/ios/chrome/browser/content_suggestions/ui_bundled/safety_check/safety_check_magic_stack_mediator.mm b/ios/chrome/browser/content_suggestions/ui_bundled/safety_check/safety_check_magic_stack_mediator.mm
index 5464a900..9881dbb3 100644
--- a/ios/chrome/browser/content_suggestions/ui_bundled/safety_check/safety_check_magic_stack_mediator.mm
+++ b/ios/chrome/browser/content_suggestions/ui_bundled/safety_check/safety_check_magic_stack_mediator.mm
@@ -183,10 +183,7 @@
 
   if (_prefObserverBridge) {
     _prefChangeRegistrar.RemoveAll();
-    if (IsHomeCustomizationEnabled()) {
-      _userPrefChangeRegistrar.RemoveAll();
-    }
-
+    _userPrefChangeRegistrar.RemoveAll();
     _prefObserverBridge.reset();
   }
 
diff --git a/ios/chrome/browser/context_menu/ui_bundled/DEPS b/ios/chrome/browser/context_menu/ui_bundled/DEPS
index ce04317..4430112 100644
--- a/ios/chrome/browser/context_menu/ui_bundled/DEPS
+++ b/ios/chrome/browser/context_menu/ui_bundled/DEPS
@@ -6,7 +6,6 @@
   "+ios/chrome/browser/policy/model/policy_util.h",
   "+ios/chrome/browser/reading_list/model/reading_list_browser_agent.h",
   "+ios/chrome/browser/search_engines/model",
-  "+ios/chrome/browser/ui/image_util",
   "+ios/chrome/browser/incognito_reauth/ui_bundled",
   "+ios/chrome/browser/lens/ui_bundled/lens_availability.h",
   "+ios/chrome/browser/lens/ui_bundled/lens_entrypoint.h",
diff --git a/ios/chrome/browser/flags/DEPS b/ios/chrome/browser/flags/DEPS
index f525aabe..b953d03 100644
--- a/ios/chrome/browser/flags/DEPS
+++ b/ios/chrome/browser/flags/DEPS
@@ -14,8 +14,5 @@
     "+ios/chrome/browser/first_run/ui_bundled",
     "+ios/chrome/browser/ntp/ui_bundled",
   ],
-  "^system_flags.mm": [
-    "+ios/chrome/browser/ui/ui_feature_flags.h",
-  ]
 }
 
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index a8bbe11f..0ffb341 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -1385,24 +1385,13 @@
 
 constexpr flags_ui::FeatureEntry::FeatureParam
     kReaderModeDistillerPageLoadHeuristicAlwaysEnabledParam[] = {
-        {kReaderModeDistillerPageLoadProbabilityName, "1"}};
-const FeatureEntry::FeatureVariation
-    kReaderModePageLoadHeuristicSamplingOptions[] = {
-        {"on all page loads",
-         kReaderModeDistillerPageLoadHeuristicAlwaysEnabledParam,
-         std::size(kReaderModeDistillerPageLoadHeuristicAlwaysEnabledParam),
-         nullptr},
-};
-
-constexpr flags_ui::FeatureEntry::FeatureParam
-    kReaderModeDistillerHeuristicPageLoadDelayDisabledParam[] = {
+        {kReaderModeDistillerPageLoadProbabilityName, "1"},
         {kReaderModeDistillerPageLoadDelayDurationStringName, "0"}};
-const FeatureEntry::FeatureVariation
-    kReaderModeDistillerHeuristicPageLoadDelayOptions[] = {
-        {"with no delay",
-         kReaderModeDistillerHeuristicPageLoadDelayDisabledParam,
-         std::size(kReaderModeDistillerHeuristicPageLoadDelayDisabledParam),
-         nullptr},
+const FeatureEntry::FeatureVariation kReaderModeDistillerHeuristicOptions[] = {
+    {"no sampling with no delay",
+     kReaderModeDistillerPageLoadHeuristicAlwaysEnabledParam,
+     std::size(kReaderModeDistillerPageLoadHeuristicAlwaysEnabledParam),
+     nullptr},
 };
 
 // To add a new entry, add to the end of kFeatureEntries. There are four
@@ -2579,25 +2568,17 @@
      flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(
          autofill::features::kAutofillEnableSupportForHomeAndWork)},
-    {"reader-mode-distiller-heuristic-delay-string",
-     flag_descriptions::kReaderModeDistillerHeuristicPageLoadDelayName,
-     flag_descriptions::kReaderModeDistillerHeuristicPageLoadDelayDescription,
-     flags_ui::kOsIos,
-     FEATURE_WITH_PARAMS_VALUE_TYPE(
-         kEnableReaderModeDistillerHeuristic,
-         kReaderModeDistillerHeuristicPageLoadDelayOptions,
-         "ReaderModeHeuristicPageLoadDelay")},
     {"reader-mode-distiller-heuristic-enabled",
      flag_descriptions::kReaderModeDistillerHeuristicName,
      flag_descriptions::kReaderModeDistillerHeuristicDescription,
-     flags_ui::kOsIos, FEATURE_VALUE_TYPE(kEnableReaderModeDistillerHeuristic)},
-    {"reader-mode-distiller-heuristic-sampling",
-     flag_descriptions::kReaderModeDistillerHeuristicSamplingName,
-     flag_descriptions::kReaderModeDistillerHeuristicSamplingDescription,
      flags_ui::kOsIos,
      FEATURE_WITH_PARAMS_VALUE_TYPE(kEnableReaderModeDistillerHeuristic,
-                                    kReaderModePageLoadHeuristicSamplingOptions,
+                                    kReaderModeDistillerHeuristicOptions,
                                     "ReaderModeHeuristicSampling")},
+    {"reader-mode-distiller-enabled",
+     flag_descriptions::kReaderModeDistillerName,
+     flag_descriptions::kReaderModeDistillerDescription, flags_ui::kOsIos,
+     FEATURE_VALUE_TYPE(kEnableReaderModeDistiller)},
     {"lens-overlay-navigation-history",
      flag_descriptions::kLensOverlayNavigationHistoryName,
      flag_descriptions::kLensOverlayNavigationHistoryDescription,
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
index f9080e3..0bc4ce0 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -1124,24 +1124,16 @@
     "Displays the menu item for the notification controls inside the chrome "
     "settings UI.";
 
+const char kReaderModeDistillerName[] = "Enables Reader Mode distillation";
+const char kReaderModeDistillerDescription[] =
+    "Enables Reader Mode distillation on the current web page.";
+
 const char kReaderModeDistillerHeuristicName[] =
     "Reader Mode distillation trigger heuristic";
 const char kReaderModeDistillerHeuristicDescription[] =
     "Enables Reader Mode distillation heuristic that triggers Reader Mode UI "
     "entry point if available";
 
-const char kReaderModeDistillerHeuristicSamplingName[] =
-    "Reader Mode distiller heuristic sampling";
-const char kReaderModeDistillerHeuristicSamplingDescription[] =
-    "The probability that the Reader Mode heuristic will run on a given page "
-    "load, used for sampling the heuristic on user page loads.";
-
-const char kReaderModeDistillerHeuristicPageLoadDelayName[] =
-    "Reader Mode distiller heuristic page load delay";
-const char kReaderModeDistillerHeuristicPageLoadDelayDescription[] =
-    "The delay (in duration string format) between the page load and the "
-    "heuristic to determine the eligibility of the page for Reader Mode.";
-
 const char kRefactorToolbarsSizeName[] = "Refactor toolbars size";
 const char kRefactorToolbarsSizeDescription[] =
     "When enabled, the toolbars size does not use broadcaster but observers.";
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
index dfd9c57a..6521ab2 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -664,15 +664,12 @@
 extern const char kNotificationSettingsMenuItemName[];
 extern const char kNotificationSettingsMenuItemDescription[];
 
+extern const char kReaderModeDistillerName[];
+extern const char kReaderModeDistillerDescription[];
+
 extern const char kReaderModeDistillerHeuristicName[];
 extern const char kReaderModeDistillerHeuristicDescription[];
 
-extern const char kReaderModeDistillerHeuristicSamplingName[];
-extern const char kReaderModeDistillerHeuristicSamplingDescription[];
-
-extern const char kReaderModeDistillerHeuristicPageLoadDelayName[];
-extern const char kReaderModeDistillerHeuristicPageLoadDelayDescription[];
-
 // Title and description for the flag to refactor the toolbarsSize.
 extern const char kRefactorToolbarsSizeName[];
 extern const char kRefactorToolbarsSizeDescription[];
diff --git a/ios/chrome/browser/fullscreen/ui_bundled/fullscreen_model_unittest.mm b/ios/chrome/browser/fullscreen/ui_bundled/fullscreen_model_unittest.mm
index 7354bac..0fb58f47 100644
--- a/ios/chrome/browser/fullscreen/ui_bundled/fullscreen_model_unittest.mm
+++ b/ios/chrome/browser/fullscreen/ui_bundled/fullscreen_model_unittest.mm
@@ -326,3 +326,19 @@
   EXPECT_FALSE(model()->is_scrolled_to_top());
   EXPECT_TRUE(model()->is_scrolled_to_bottom());
 }
+
+// Tests that after scrolling down a lot to enter fullscreen, scrolling
+// partially up as part of the same drag event exits fullscreen.
+TEST_F(FullscreenModelTest, ScrollDownThenUp) {
+  model()->SetScrollViewIsDragging(true);
+  model()->SetScrollViewIsScrolling(true);
+  EXPECT_EQ(observer().progress(), 1.0);
+  model()->SetYContentOffset(model()->GetYContentOffset() + kToolbarHeight * 3);
+  EXPECT_EQ(observer().progress(), 0);
+  // Simulate a direction change in the swipe.
+  model()->SetYContentOffset(model()->GetYContentOffset() - 5);
+  model()->SetYContentOffset(model()->GetYContentOffset() - kToolbarHeight);
+  EXPECT_EQ(observer().progress(), 1.0);
+  model()->SetScrollViewIsDragging(false);
+  model()->SetScrollViewIsScrolling(false);
+}
diff --git a/ios/chrome/browser/location_bar/ui_bundled/location_bar_coordinator.mm b/ios/chrome/browser/location_bar/ui_bundled/location_bar_coordinator.mm
index fbf03b1..7ccd944c 100644
--- a/ios/chrome/browser/location_bar/ui_bundled/location_bar_coordinator.mm
+++ b/ios/chrome/browser/location_bar/ui_bundled/location_bar_coordinator.mm
@@ -123,7 +123,6 @@
 @property(nonatomic, strong) LocationBarMediator* mediator;
 @property(nonatomic, strong) LocationBarSteadyViewMediator* steadyViewMediator;
 @property(nonatomic, strong) LocationBarViewController* viewController;
-@property(nonatomic, readonly) ProfileIOS* profile;
 @property(nonatomic, readonly) WebStateList* webStateList;
 
 // Tracks calls in progress to -cancelOmniboxEdit to avoid calling it from
@@ -139,10 +138,6 @@
 
 #pragma mark - Accessors
 
-- (ProfileIOS*)profile {
-  return self.browser ? self.browser->GetProfile() : nullptr;
-}
-
 - (WebStateList*)webStateList {
   return self.browser ? self.browser->GetWebStateList() : nullptr;
 }
@@ -176,7 +171,7 @@
 
   self.viewController = [[LocationBarViewController alloc] init];
   self.viewController.incognito = isIncognito;
-  self.viewController.profilePrefs = self.browser->GetProfile()->GetPrefs();
+  self.viewController.profilePrefs = self.profile->GetPrefs();
   self.viewController.delegate = self;
   // TODO(crbug.com/40670043): Use HandlerForProtocol after commands protocol
   // clean up.
@@ -185,8 +180,7 @@
          LensCommands, LensOverlayCommands, OmniboxCommands>>(
       self.browser->GetCommandDispatcher());
   self.viewController.tracker =
-      feature_engagement::TrackerFactory::GetForProfile(
-          self.browser->GetProfile());
+      feature_engagement::TrackerFactory::GetForProfile(self.profile);
   self.viewController.voiceSearchEnabled =
       ios::provider::IsVoiceSearchEnabled();
   self.viewController.layoutGuideCenter =
@@ -287,8 +281,7 @@
                                     OverlayModality::kWebContentArea);
   self.steadyViewMediator.consumer = self;
   self.steadyViewMediator.tracker =
-      feature_engagement::TrackerFactory::GetForProfile(
-          self.browser->GetProfile());
+      feature_engagement::TrackerFactory::GetForProfile(self.profile);
 
   _omniboxFullscreenUIUpdater = std::make_unique<FullscreenUIUpdater>(
       fullscreenController, self.viewController);
diff --git a/ios/chrome/browser/main/model/DEPS b/ios/chrome/browser/main/model/DEPS
index 8bdcb4e..53e6b21 100644
--- a/ios/chrome/browser/main/model/DEPS
+++ b/ios/chrome/browser/main/model/DEPS
@@ -42,12 +42,8 @@
     "+ios/chrome/browser/web_state_list/model/web_usage_enabler/web_usage_enabler_browser_agent.h",
   ],
   "^browser_impl.mm": [
-    "+ios/chrome/browser/ui/commands/command_dispatcher.h",
     "+ios/chrome/browser/shared/coordinator/scene/scene_state.h",
     "+ios/chrome/browser/saved_tab_groups/model/tab_group_service.h",
     "+ios/chrome/browser/saved_tab_groups/model/tab_group_service_factory.h",
   ],
-  "^test_browser.mm": [
-    "+ios/chrome/browser/ui/commands/command_dispatcher.h",
-  ]
 }
diff --git a/ios/chrome/browser/main/ui_bundled/DEPS b/ios/chrome/browser/main/ui_bundled/DEPS
index ab2fe31d..b0f4d4c 100644
--- a/ios/chrome/browser/main/ui_bundled/DEPS
+++ b/ios/chrome/browser/main/ui_bundled/DEPS
@@ -1,5 +1,4 @@
 include_rules = [
-  "+ios/chrome/browser/ui",
   # Use ios/chrome/browser/authentication/ui_bundled/signin_earl_grey.h instead
   "-ios/chrome/browser/authentication/ui_bundled/signin_earl_grey_app_interface.h",
   # use ios/chrome/browser/bookmarks/ui_bundled/bookmark_earl_grey.h instead
diff --git a/ios/chrome/browser/overlays/model/public/web_content_area/DEPS b/ios/chrome/browser/overlays/model/public/web_content_area/DEPS
index 1221943..3364af97 100644
--- a/ios/chrome/browser/overlays/model/public/web_content_area/DEPS
+++ b/ios/chrome/browser/overlays/model/public/web_content_area/DEPS
@@ -1,17 +1,10 @@
 specific_include_rules = {
   # TODO(crbug.com/40820398): Remove these dependencies.
-  "^http_auth_overlay.mm": [
-    "+ios/chrome/browser/ui/elements/text_field_configuration.h",
-  ],
   "^java_script_dialog_overlay.mm": [
     "+ios/chrome/browser/dialogs/ui_bundled/java_script_dialog_blocking_state.h",
-    "+ios/chrome/browser/ui/elements/text_field_configuration.h",
   ],
   "^java_script_dialog_overlay_utils.mm": [
     "+ios/chrome/browser/dialogs/ui_bundled/java_script_dialog_blocking_state.h",
   ],
-  "^java_script_prompt_dialog_overlay.mm": [
-    "+ios/chrome/browser/ui/elements/text_field_configuration.h",
-  ],
 }
 
diff --git a/ios/chrome/browser/parcel_tracking/BUILD.gn b/ios/chrome/browser/parcel_tracking/BUILD.gn
index ec7aaab..05fdc45 100644
--- a/ios/chrome/browser/parcel_tracking/BUILD.gn
+++ b/ios/chrome/browser/parcel_tracking/BUILD.gn
@@ -19,17 +19,6 @@
   ]
 }
 
-source_set("opt_in_status") {
-  sources = [
-    "parcel_tracking_opt_in_status.h",
-    "parcel_tracking_opt_in_status.mm",
-  ]
-  deps = [
-    "//components/prefs",
-    "//ios/chrome/browser/shared/model/prefs:pref_names",
-  ]
-}
-
 source_set("prefs") {
   sources = [
     "parcel_tracking_prefs.h",
diff --git a/ios/chrome/browser/parcel_tracking/parcel_tracking_opt_in_status.h b/ios/chrome/browser/parcel_tracking/parcel_tracking_opt_in_status.h
deleted file mode 100644
index 250147bf8..0000000
--- a/ios/chrome/browser/parcel_tracking/parcel_tracking_opt_in_status.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_PARCEL_TRACKING_PARCEL_TRACKING_OPT_IN_STATUS_H_
-#define IOS_CHROME_BROWSER_PARCEL_TRACKING_PARCEL_TRACKING_OPT_IN_STATUS_H_
-
-class PrefService;
-
-// Enum for the different values of the parcel tracking opt-in status.
-enum class IOSParcelTrackingOptInStatus {
-  kNeverTrack = 0,
-  kAlwaysTrack = 1,
-  kAskToTrack = 2,
-  kStatusNotSet = 3,
-  kMaxValue = kStatusNotSet,
-};
-
-// Logs the user's parcel tracking opt-in status.
-void RecordParcelTrackingOptInStatus(PrefService* pref_service);
-
-#endif  // IOS_CHROME_BROWSER_PARCEL_TRACKING_PARCEL_TRACKING_OPT_IN_STATUS_H_
diff --git a/ios/chrome/browser/parcel_tracking/parcel_tracking_opt_in_status.mm b/ios/chrome/browser/parcel_tracking/parcel_tracking_opt_in_status.mm
deleted file mode 100644
index 97a5c51..0000000
--- a/ios/chrome/browser/parcel_tracking/parcel_tracking_opt_in_status.mm
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/parcel_tracking/parcel_tracking_opt_in_status.h"
-
-#import "base/metrics/histogram_functions.h"
-#import "components/prefs/pref_service.h"
-#import "ios/chrome/browser/shared/model/prefs/pref_names.h"
-
-void RecordParcelTrackingOptInStatus(PrefService* pref_service) {
-  IOSParcelTrackingOptInStatus status =
-      static_cast<IOSParcelTrackingOptInStatus>(
-          pref_service->GetInteger(prefs::kIosParcelTrackingOptInStatus));
-  base::UmaHistogramEnumeration("IOS.ParcelTracking.OptInStatus", status);
-}
diff --git a/ios/chrome/browser/passwords/model/DEPS b/ios/chrome/browser/passwords/model/DEPS
index bfa91861..78077298 100644
--- a/ios/chrome/browser/passwords/model/DEPS
+++ b/ios/chrome/browser/passwords/model/DEPS
@@ -16,8 +16,5 @@
     "+ios/chrome/browser/shared/ui/util/rtl_geometry.h",
     "+ios/chrome/browser/shared/ui/util/uikit_ui_util.h",
   ],
-  "^password_controller.mm": [
-    "+ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator.h",
-  ],
 
 }
diff --git a/ios/chrome/browser/popup_menu/ui_bundled/DEPS b/ios/chrome/browser/popup_menu/ui_bundled/DEPS
index 65370708..584fa8a 100644
--- a/ios/chrome/browser/popup_menu/ui_bundled/DEPS
+++ b/ios/chrome/browser/popup_menu/ui_bundled/DEPS
@@ -4,10 +4,8 @@
   "+ios/chrome/browser/bubble/ui_bundled",
   "+ios/chrome/browser/lens/ui_bundled/lens_entrypoint.h",
   "+ios/chrome/browser/ntp/shared/metrics/feed_metrics_recorder.h",
-  "+ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_tile_constants.h",
   "+ios/chrome/browser/reading_list/ui_bundled",
   "+ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/pinned_tabs/features.h",
-  "+ios/chrome/browser/ui/whats_new/whats_new_util.h",
   "+ios/chrome/browser/presenters/ui_bundled",
   "+ios/chrome/browser/keyboard/ui_bundled/UIKeyCommand+Chrome.h",
   "+ios/chrome/browser/settings/ui_bundled",
diff --git a/ios/chrome/browser/promos_manager/ui_bundled/DEPS b/ios/chrome/browser/promos_manager/ui_bundled/DEPS
index 234d920..ce61536 100644
--- a/ios/chrome/browser/promos_manager/ui_bundled/DEPS
+++ b/ios/chrome/browser/promos_manager/ui_bundled/DEPS
@@ -8,7 +8,6 @@
   "+ios/chrome/browser/post_restore_signin/ui_bundled",
   "+ios/chrome/browser/signin/model",
   "+ios/chrome/browser/sync/model/sync_service_factory.h",
-  "+ios/chrome/browser/ui/app_store_rating",
   "+ios/chrome/browser/whats_new/coordinator",
   "+ios/chrome/browser/authentication/ui_bundled/signin/promo",
 ]
diff --git a/ios/chrome/browser/reader_mode/model/features.h b/ios/chrome/browser/reader_mode/model/features.h
index 9c79e2ea..7dba8be 100644
--- a/ios/chrome/browser/reader_mode/model/features.h
+++ b/ios/chrome/browser/reader_mode/model/features.h
@@ -12,6 +12,9 @@
 // an approximation of when the Reader Mode UI will be available.
 BASE_DECLARE_FEATURE(kEnableReaderModeDistillerHeuristic);
 
+// Feature to enable Reader Mode page distillation.
+BASE_DECLARE_FEATURE(kEnableReaderModeDistiller);
+
 // Name to configure the page load probability.
 extern const char kReaderModeDistillerPageLoadProbabilityName[];
 // Configurable rate from (0, 1] at which to trigger the distiller heuristic.
diff --git a/ios/chrome/browser/reader_mode/model/features.mm b/ios/chrome/browser/reader_mode/model/features.mm
index 8951ebf..e68f8ff 100644
--- a/ios/chrome/browser/reader_mode/model/features.mm
+++ b/ios/chrome/browser/reader_mode/model/features.mm
@@ -12,6 +12,10 @@
              "EnableReaderModeDistillerHeuristic",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+BASE_FEATURE(kEnableReaderModeDistiller,
+             "EnableReaderModeDistiller",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 const char kReaderModeDistillerPageLoadProbabilityName[] =
     "reader-mode-distiller-page-load-probability";
 
diff --git a/ios/chrome/browser/reader_mode/model/reader_mode_tab_helper.mm b/ios/chrome/browser/reader_mode/model/reader_mode_tab_helper.mm
index 59e2953..f5ef660 100644
--- a/ios/chrome/browser/reader_mode/model/reader_mode_tab_helper.mm
+++ b/ios/chrome/browser/reader_mode/model/reader_mode_tab_helper.mm
@@ -123,6 +123,10 @@
     ReaderModeHeuristicResult result) {
   UMA_HISTOGRAM_ENUMERATION(kReaderModeHeuristicResultHistogram, result);
 
+  if (!base::FeatureList::IsEnabled(kEnableReaderModeDistiller)) {
+    return;
+  }
+
   // Gets the instance of the WebFramesManager from `web_state_` that can
   // execute the DOM distiller JavaScript in the isolated content world.
   web::WebFramesManager* web_frames_manager =
diff --git a/ios/chrome/browser/reader_mode/model/reader_mode_tab_helper_unittest.mm b/ios/chrome/browser/reader_mode/model/reader_mode_tab_helper_unittest.mm
index 6ae5799..2204dab 100644
--- a/ios/chrome/browser/reader_mode/model/reader_mode_tab_helper_unittest.mm
+++ b/ios/chrome/browser/reader_mode/model/reader_mode_tab_helper_unittest.mm
@@ -164,12 +164,15 @@
 // Tests that histograms related to distillation results are recorded after the
 // JavaScript execution.
 TEST_F(ReaderModeTabHelperTest, TriggerDistillerJs) {
-  scoped_feature_list_.InitAndEnableFeatureWithParameters(
-      kEnableReaderModeDistillerHeuristic,
-      {
-          {kReaderModeDistillerPageLoadProbabilityName, "1.0"},
-          {kReaderModeDistillerPageLoadDelayDurationStringName, "0"},
-      });
+  scoped_feature_list_.InitWithFeaturesAndParameters(
+      /*enabled_features=*/
+      {{kEnableReaderModeDistillerHeuristic,
+        {
+            {kReaderModeDistillerPageLoadProbabilityName, "1.0"},
+            {kReaderModeDistillerPageLoadDelayDurationStringName, "0"},
+        }},
+       {kEnableReaderModeDistiller, {}}},
+      /*disabled_features=*/{});
 
   auto test_web_state = std::make_unique<web::FakeWebState>();
   auto frames_manager = std::make_unique<web::FakeWebFramesManager>();
diff --git a/ios/chrome/browser/safe_mode/ui_bundled/DEPS b/ios/chrome/browser/safe_mode/ui_bundled/DEPS
index 6142441..638b6db 100644
--- a/ios/chrome/browser/safe_mode/ui_bundled/DEPS
+++ b/ios/chrome/browser/safe_mode/ui_bundled/DEPS
@@ -1,5 +1,4 @@
 include_rules = [
   "+ios/chrome/browser/crash_report/model/crash_helper.h",
   "+ios/chrome/browser/crash_report/model/crash_loop_detection_util.h",
-  "+ios/chrome/browser/ui/fancy_ui/primary_action_button.h",
 ]
diff --git a/ios/chrome/browser/search_engine_choice/ui_bundled/DEPS b/ios/chrome/browser/search_engine_choice/ui_bundled/DEPS
index 5de7da70..dc581d20 100644
--- a/ios/chrome/browser/search_engine_choice/ui_bundled/DEPS
+++ b/ios/chrome/browser/search_engine_choice/ui_bundled/DEPS
@@ -2,7 +2,6 @@
   "+ios/chrome/browser/favicon/model/favicon_loader.h",
   "+ios/chrome/browser/first_run/ui_bundled/first_run_screen_delegate.h",
   "+ios/chrome/browser/first_run/model/first_run_metrics.h",
-  "+ios/chrome/browser/ui/scoped_iphone_portrait_only",
   "+ios/chrome/browser/search_engine_choice/ui_bundled",
   "+ios/chrome/browser/settings/ui_bundled/settings_table_view_controller_constants.h",
   "+ios/chrome/browser/settings/ui_bundled/cells/settings_cells_constants.h",
diff --git a/ios/chrome/browser/settings/ui_bundled/downloads/save_to_photos/DEPS b/ios/chrome/browser/settings/ui_bundled/downloads/save_to_photos/DEPS
deleted file mode 100644
index d2c4378..0000000
--- a/ios/chrome/browser/settings/ui_bundled/downloads/save_to_photos/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
-  "+ios/chrome/browser/ui/account_picker/account_picker_selection/account_picker_selection_screen_identity_item_configurator.h",
-]
\ No newline at end of file
diff --git a/ios/chrome/browser/settings/ui_bundled/google_services/manage_accounts/legacy_accounts_table_egtest.mm b/ios/chrome/browser/settings/ui_bundled/google_services/manage_accounts/legacy_accounts_table_egtest.mm
index 1da678c..02a3867 100644
--- a/ios/chrome/browser/settings/ui_bundled/google_services/manage_accounts/legacy_accounts_table_egtest.mm
+++ b/ios/chrome/browser/settings/ui_bundled/google_services/manage_accounts/legacy_accounts_table_egtest.mm
@@ -186,10 +186,11 @@
       selectElementWithMatcher:chrome_test_util::ButtonWithAccessibilityLabel(
                                    fakeIdentity.userEmail)]
       performAction:grey_tap()];
-  [[EarlGrey
-      selectElementWithMatcher:
-          chrome_test_util::ButtonWithAccessibilityLabel(
-              l10n_util::GetNSString(IDS_IOS_MANAGE_YOUR_GOOGLE_ACCOUNT_TITLE))]
+  [[EarlGrey selectElementWithMatcher:
+                 grey_allOf(chrome_test_util::ButtonWithAccessibilityLabel(
+                                l10n_util::GetNSString(
+                                    IDS_IOS_MANAGE_YOUR_GOOGLE_ACCOUNT_TITLE)),
+                            grey_sufficientlyVisible(), nil)]
       performAction:grey_tap()];
   [ChromeEarlGreyUI waitForAppToIdle];
 
@@ -267,10 +268,12 @@
         selectElementWithMatcher:chrome_test_util::ButtonWithAccessibilityLabel(
                                      fakeIdentity.userEmail)]
         performAction:grey_tap()];
-    [[EarlGrey selectElementWithMatcher:
-                   chrome_test_util::ButtonWithAccessibilityLabel(
-                       l10n_util::GetNSString(
-                           IDS_IOS_MANAGE_YOUR_GOOGLE_ACCOUNT_TITLE))]
+    [[EarlGrey
+        selectElementWithMatcher:
+            grey_allOf(chrome_test_util::ButtonWithAccessibilityLabel(
+                           l10n_util::GetNSString(
+                               IDS_IOS_MANAGE_YOUR_GOOGLE_ACCOUNT_TITLE)),
+                       grey_sufficientlyVisible(), nil)]
         performAction:grey_tap()];
     [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
                                             kFakeAccountDetailsViewIdentifier)]
diff --git a/ios/chrome/browser/settings/ui_bundled/google_services/manage_sync_settings_mediator.mm b/ios/chrome/browser/settings/ui_bundled/google_services/manage_sync_settings_mediator.mm
index 936cc9d..ce170a0e 100644
--- a/ios/chrome/browser/settings/ui_bundled/google_services/manage_sync_settings_mediator.mm
+++ b/ios/chrome/browser/settings/ui_bundled/google_services/manage_sync_settings_mediator.mm
@@ -498,6 +498,7 @@
   item.text =
       GetNSString(IDS_IOS_GOOGLE_ACCOUNT_SETTINGS_MANAGE_GOOGLE_ACCOUNT_ITEM);
   item.textColor = [UIColor colorNamed:kBlueColor];
+  item.accessibilityTraits |= UIAccessibilityTraitButton;
   [model addItem:item
       toSectionWithIdentifier:ManageAndSignOutSectionIdentifier];
 
@@ -507,6 +508,7 @@
     item.text =
         GetNSString(IDS_IOS_GOOGLE_ACCOUNT_SETTINGS_MANAGE_STORAGE_ITEM);
     item.textColor = [UIColor colorNamed:kBlueColor];
+    item.accessibilityTraits |= UIAccessibilityTraitButton;
     [model addItem:item
         toSectionWithIdentifier:ManageAndSignOutSectionIdentifier];
   }
@@ -515,6 +517,7 @@
   item = [[TableViewTextItem alloc] initWithType:ManageAccountsItemType];
   item.text = GetNSString(IDS_IOS_GOOGLE_ACCOUNT_SETTINGS_MANAGE_ACCOUNTS_ITEM);
   item.textColor = [UIColor colorNamed:kBlueColor];
+  item.accessibilityTraits |= UIAccessibilityTraitButton;
   [model addItem:item
       toSectionWithIdentifier:ManageAndSignOutSectionIdentifier];
 
@@ -525,6 +528,7 @@
     item = [[TableViewTextItem alloc] initWithType:SignOutItemType];
     item.text = GetNSString(IDS_IOS_GOOGLE_ACCOUNT_SETTINGS_SIGN_OUT_ITEM);
     item.textColor = [UIColor colorNamed:kBlueColor];
+    item.accessibilityTraits |= UIAccessibilityTraitButton;
     [model addItem:item
         toSectionWithIdentifier:ManageAndSignOutSectionIdentifier];
 
diff --git a/ios/chrome/browser/share_kit/model/share_kit_manage_configuration.h b/ios/chrome/browser/share_kit/model/share_kit_manage_configuration.h
index 47b9aef..263a7112 100644
--- a/ios/chrome/browser/share_kit/model/share_kit_manage_configuration.h
+++ b/ios/chrome/browser/share_kit/model/share_kit_manage_configuration.h
@@ -11,6 +11,8 @@
 enum class ShareKitFlowOutcome;
 class TabGroup;
 
+typedef void (^ShareKitShouldUnshareGroupBlock)(BOOL shouldDelete);
+
 // Configuration object for managing a shared group.
 @interface ShareKitManageConfiguration : NSObject
 
@@ -32,6 +34,16 @@
 // Executed when the manage flow ended.
 @property(nonatomic, copy) void (^completion)(ShareKitFlowOutcome outcome);
 
+// The completion block to be called when the user requests to delete the group,
+// to know if the deletion should proceed or not, providing an opportunity to
+// act before the collaboration group is deleted.
+@property(nonatomic, copy) void (^willUnshareGroupBlock)
+    (ShareKitShouldUnshareGroupBlock continuationBlock);
+
+// The completion block to be called when the collaboration group has been
+// successfully deleted.
+@property(nonatomic, copy) void (^didUnshareGroupBlock)(NSError* error);
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_SHARE_KIT_MODEL_SHARE_KIT_MANAGE_CONFIGURATION_H_
diff --git a/ios/chrome/browser/shared/model/prefs/BUILD.gn b/ios/chrome/browser/shared/model/prefs/BUILD.gn
index 620cebf..85837ed7 100644
--- a/ios/chrome/browser/shared/model/prefs/BUILD.gn
+++ b/ios/chrome/browser/shared/model/prefs/BUILD.gn
@@ -118,7 +118,6 @@
     "//ios/chrome/browser/ntp/model:set_up_list_prefs",
     "//ios/chrome/browser/ntp/shared/metrics:constants",
     "//ios/chrome/browser/ntp_tiles/model/tab_resumption:tab_resumption_prefs",
-    "//ios/chrome/browser/parcel_tracking:opt_in_status",
     "//ios/chrome/browser/parcel_tracking:prefs",
     "//ios/chrome/browser/photos/model:policy",
     "//ios/chrome/browser/policy/model:policy_util",
diff --git a/ios/chrome/browser/shared/model/prefs/DEPS b/ios/chrome/browser/shared/model/prefs/DEPS
index 76fd346..c9532b5 100644
--- a/ios/chrome/browser/shared/model/prefs/DEPS
+++ b/ios/chrome/browser/shared/model/prefs/DEPS
@@ -37,7 +37,6 @@
   # TODO(crbug.com/40820398): Remove this dependency.
   "^browser_prefs.mm": [
     "+ios/chrome/browser/bookmarks/ui_bundled",
-    "+ios/chrome/browser/ui",
     "-ios/chrome/browser/authentication/ui_bundled/signin_earl_grey_app_interface.h",
     "+ios/chrome/browser/metrics/model/constants.h",
     "+ios/chrome/browser/upgrade/model/upgrade_constants.h",
diff --git a/ios/chrome/browser/shared/model/prefs/browser_prefs.mm b/ios/chrome/browser/shared/model/prefs/browser_prefs.mm
index 6f25508..84468eb8 100644
--- a/ios/chrome/browser/shared/model/prefs/browser_prefs.mm
+++ b/ios/chrome/browser/shared/model/prefs/browser_prefs.mm
@@ -105,7 +105,6 @@
 #import "ios/chrome/browser/ntp/model/set_up_list_prefs.h"
 #import "ios/chrome/browser/ntp/shared/metrics/feed_metrics_constants.h"
 #import "ios/chrome/browser/ntp_tiles/model/tab_resumption/tab_resumption_prefs.h"
-#import "ios/chrome/browser/parcel_tracking/parcel_tracking_opt_in_status.h"
 #import "ios/chrome/browser/parcel_tracking/parcel_tracking_prefs.h"
 #import "ios/chrome/browser/photos/model/photos_policy.h"
 #import "ios/chrome/browser/policy/model/policy_util.h"
@@ -176,6 +175,16 @@
 inline constexpr char kNumberOfProfiles[] = "profile.profiles_created";
 inline constexpr char kLastActiveProfiles[] = "profile.last_active_profiles";
 
+// Deprecated 03/2025.
+inline constexpr char kIosParcelTrackingOptInPromptDisplayLimitMet[] =
+    "ios.parcel_tracking.opt_in_prompt_displayed";
+inline constexpr char kIosParcelTrackingOptInStatus[] =
+    "ios.parcel_tracking.opt_in_status";
+inline constexpr char kIosParcelTrackingOptInPromptSwipedDown[] =
+    "ios.parcel_tracking.opt_in_prompt_swiped_down";
+inline constexpr char kIosParcelTrackingPolicyEnabled[] =
+    "ios.parcel_tracking.policy_enabled";
+
 // Helper function migrating the preference `pref_name` of type "int" from
 // `defaults` to `pref_service`.
 void MigrateIntegerPreferenceFromUserDefaults(std::string_view pref_name,
@@ -470,7 +479,7 @@
   registry->RegisterIntegerPref(prefs::kBrowserSigninPolicy,
                                 static_cast<int>(BrowserSigninMode::kEnabled));
   registry->RegisterBooleanPref(prefs::kAppStoreRatingPolicyEnabled, true);
-  registry->RegisterBooleanPref(prefs::kIosParcelTrackingPolicyEnabled, true);
+  registry->RegisterBooleanPref(kIosParcelTrackingPolicyEnabled, true);
 
   registry->RegisterBooleanPref(prefs::kLensCameraAssistedSearchPolicyAllowed,
                                 true);
@@ -829,13 +838,11 @@
   registry->RegisterIntegerPref(policy::policy_prefs::kDownloadRestrictions, 0);
 
   // Preferences related to parcel tracking.
-  registry->RegisterBooleanPref(
-      prefs::kIosParcelTrackingOptInPromptDisplayLimitMet, false);
-  registry->RegisterIntegerPref(
-      prefs::kIosParcelTrackingOptInStatus,
-      static_cast<int>(IOSParcelTrackingOptInStatus::kStatusNotSet));
-  registry->RegisterBooleanPref(prefs::kIosParcelTrackingOptInPromptSwipedDown,
+  // Deprecated 03/2025.
+  registry->RegisterBooleanPref(kIosParcelTrackingOptInPromptDisplayLimitMet,
                                 false);
+  registry->RegisterIntegerPref(kIosParcelTrackingOptInStatus, -1);
+  registry->RegisterBooleanPref(kIosParcelTrackingOptInPromptSwipedDown, false);
 
   // Register prefs used to skip too frequent History Sync Opt-In prompt.
   history_sync::RegisterProfilePrefs(registry);
@@ -1070,6 +1077,9 @@
 
   // Added 02/2025.
   prefs->ClearPref(set_up_list_prefs::kDisabled);
+
+  // Added 03/2025.
+  prefs->ClearPref(kIosParcelTrackingPolicyEnabled);
 }
 
 // This method should be periodically pruned of year+ old migrations.
@@ -1229,6 +1239,11 @@
   // Added 03/2025.
   MigrateIntegerPrefFromLocalStatePrefsToProfilePrefs(
       prefs::kHomeCustomizationMagicStackSafetyCheckIssuesCount, prefs);
+
+  // Added 03/2025.
+  prefs->ClearPref(kIosParcelTrackingOptInPromptDisplayLimitMet);
+  prefs->ClearPref(kIosParcelTrackingOptInStatus);
+  prefs->ClearPref(kIosParcelTrackingOptInPromptSwipedDown);
 }
 
 void MigrateObsoleteUserDefault() {
diff --git a/ios/chrome/browser/shared/model/prefs/pref_names.h b/ios/chrome/browser/shared/model/prefs/pref_names.h
index 0cecab1..d2732cb 100644
--- a/ios/chrome/browser/shared/model/prefs/pref_names.h
+++ b/ios/chrome/browser/shared/model/prefs/pref_names.h
@@ -284,25 +284,6 @@
     kIosMagicStackSegmentationTabResumptionImpressionsSinceFreshness[] =
         "ios.magic_stack_segmentation.tab_resumption_freshness";
 
-// Boolean to represent if the parcel tracking opt-in prompt has met its display
-// limit for the user. Was previously kIosParcelTrackingOptInPromptDisplayed.
-inline constexpr char kIosParcelTrackingOptInPromptDisplayLimitMet[] =
-    "ios.parcel_tracking.opt_in_prompt_displayed";
-
-// Integer that maps to IOSParcelTrackingOptInStatus, the enum type of the
-// user's preference for automatically tracking parcels.
-inline constexpr char kIosParcelTrackingOptInStatus[] =
-    "ios.parcel_tracking.opt_in_status";
-
-// Boolean to represent if the user has swiped down on the parcel trackinf
-// opt-in prompt.
-inline constexpr char kIosParcelTrackingOptInPromptSwipedDown[] =
-    "ios.parcel_tracking.opt_in_prompt_swiped_down";
-
-// Boolean to represent if Parcel Tracking is enabled for enterprise users.
-inline constexpr char kIosParcelTrackingPolicyEnabled[] =
-    "ios.parcel_tracking.policy_enabled";
-
 // The number of consecutive times the user dismissed the password bottom sheet.
 // This gets reset to 0 whenever the user selects a password from the bottom
 // sheet or from the keyboard accessory.
diff --git a/ios/chrome/browser/shared/public/DEPS b/ios/chrome/browser/shared/public/DEPS
index 685688ca..1c3e27c 100644
--- a/ios/chrome/browser/shared/public/DEPS
+++ b/ios/chrome/browser/shared/public/DEPS
@@ -1,7 +1,4 @@
 include_rules = [
-  # TODO(crbug.com/40259387): Remove this include once the folders have been
-  # moved.
-  "+ios/chrome/browser/ui",
   # Use ios/chrome/browser/authentication/ui_bundled/signin_earl_grey.h instead
   "-ios/chrome/browser/authentication/ui_bundled/signin_earl_grey_app_interface.h",
   "+ios/chrome/browser",
diff --git a/ios/chrome/browser/shared/public/features/features.mm b/ios/chrome/browser/shared/public/features/features.mm
index 3b37c48a..b6c373e 100644
--- a/ios/chrome/browser/shared/public/features/features.mm
+++ b/ios/chrome/browser/shared/public/features/features.mm
@@ -534,6 +534,9 @@
              base::FEATURE_DISABLED_BY_DEFAULT);
 
 bool IsTabGroupIndicatorEnabled() {
+  if (ui::GetDeviceFormFactor() != ui::DEVICE_FORM_FACTOR_TABLET) {
+    return true;
+  }
   return IsTabGroupInGridEnabled() &&
          base::FeatureList::IsEnabled(kTabGroupIndicator);
 }
diff --git a/ios/chrome/browser/shared/ui/DEPS b/ios/chrome/browser/shared/ui/DEPS
index 77cfaf6..55b86be 100644
--- a/ios/chrome/browser/shared/ui/DEPS
+++ b/ios/chrome/browser/shared/ui/DEPS
@@ -1,7 +1,4 @@
 include_rules = [
-  # TODO(crbug.com/40259387): Remove this include once the folders have been
-  # moved.
-  "+ios/chrome/browser/ui",
   # Use ios/chrome/browser/authentication/ui_bundled/signin_earl_grey.h instead
   "-ios/chrome/browser/authentication/ui_bundled/signin_earl_grey_app_interface.h",
   # use ios/chrome/browser/bookmarks/ui_bundled/bookmark_earl_grey.h instead
diff --git a/ios/chrome/browser/shared/ui/util/terms_util_unittest.mm b/ios/chrome/browser/shared/ui/util/terms_util_unittest.mm
index 652e15b3..ff41c0f 100644
--- a/ios/chrome/browser/shared/ui/util/terms_util_unittest.mm
+++ b/ios/chrome/browser/shared/ui/util/terms_util_unittest.mm
@@ -104,7 +104,8 @@
   NSUInteger numberOfMissingFiles = [incorrectFallback count];
   EXPECT_EQ(numberOfMissingFiles, 0U);
   if (numberOfMissingFiles) {
-    NSLog(@"Add the following file%@ to ios/chrome/browser/ui/BUILD.gn",
+    NSLog(@"Add the following file%@ to "
+          @"components/resources/terms_resources.filelist",
           numberOfMissingFiles > 1 ? @"s" : @"");
     for (NSString* language in incorrectFallback) {
       NSLog(@"  terms_%@.html", language);
diff --git a/ios/chrome/browser/spotlight_debugger/ui_bundled/spotlight_debugger_coordinator.mm b/ios/chrome/browser/spotlight_debugger/ui_bundled/spotlight_debugger_coordinator.mm
index f070ac5d..1440201 100644
--- a/ios/chrome/browser/spotlight_debugger/ui_bundled/spotlight_debugger_coordinator.mm
+++ b/ios/chrome/browser/spotlight_debugger/ui_bundled/spotlight_debugger_coordinator.mm
@@ -33,7 +33,7 @@
 - (void)start {
   [super start];
 
-  ProfileIOS* profile = self.browser->GetProfile();
+  ProfileIOS* profile = self.profile;
   self.viewController = [[SpotlightDebuggerViewController alloc]
       initWithPrefService:profile->GetPrefs()];
   self.viewController.delegate = self;
diff --git a/ios/chrome/browser/tab_switcher/ui_bundled/DEPS b/ios/chrome/browser/tab_switcher/ui_bundled/DEPS
index 35ba3ff..b4586e4 100644
--- a/ios/chrome/browser/tab_switcher/ui_bundled/DEPS
+++ b/ios/chrome/browser/tab_switcher/ui_bundled/DEPS
@@ -1,6 +1,4 @@
 include_rules = [
-  "+ios/chrome/browser/ui",
-
   "+ios/chrome/browser/bookmarks/model",
   "+ios/chrome/browser/bookmarks/ui_bundled/home",
   "+ios/chrome/browser/bring_android_tabs/model",
diff --git a/ios/chrome/browser/ui/DEPS b/ios/chrome/browser/ui/DEPS
deleted file mode 100644
index fa65a1d..0000000
--- a/ios/chrome/browser/ui/DEPS
+++ /dev/null
@@ -1,18 +0,0 @@
-include_rules = [
-  "+ios/chrome/browser",
-
-  # Use ios/chrome/browser/authentication/ui_bundled/signin_earl_grey.h instead
-  "-ios/chrome/browser/authentication/ui_bundled/signin_earl_grey_app_interface.h",
-
-  # Subfolders have to explicitly declare their dependences.
-  # Avoid adding top-level deps, prefer to use ios/c/b/shared if needed.
-  "-ios/chrome/browser/ui",
-]
-
-specific_include_rules = {
-  # web::HttpServer is deprecated in favor of net::EmbeddedTestServer.
-  # TODO:(crbug.com/891834) Remove this exception.
-  "browser_view_controller_egtest\.mm": [
-    "+ios/web/public/test/http_server",
-  ],
-}
diff --git a/ios/chrome/browser/ui/OWNERS b/ios/chrome/browser/ui/OWNERS
deleted file mode 100644
index e1552a0..0000000
--- a/ios/chrome/browser/ui/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-# Please prefer to use more specific OWNERS where possible. Don't
-# be reluctant to re-delegate to another OWNER, when a change seems
-# like it needs extra review, or is related to the Omnibox.
-marq@chromium.org
-rohitrao@chromium.org
-gambard@chromium.org
diff --git a/ios/chrome/browser/ui/omnibox/BUILD.gn b/ios/chrome/browser/ui/omnibox/BUILD.gn
deleted file mode 100644
index e008427..0000000
--- a/ios/chrome/browser/ui/omnibox/BUILD.gn
+++ /dev/null
@@ -1,383 +0,0 @@
-# Copyright 2017 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-source_set("omnibox") {
-  sources = [
-    "omnibox_controller_delegate.h",
-    "omnibox_focus_delegate.h",
-    "web_location_bar.cc",
-    "web_location_bar.h",
-  ]
-  deps = [
-    "//base",
-    "//components/omnibox/browser",
-    "//components/search_engines",
-    "//ui/base",
-  ]
-}
-
-source_set("omnibox_popup_shared") {
-  sources = [
-    "omnibox_constants.h",
-    "omnibox_constants.mm",
-    "omnibox_keyboard_delegate.h",
-  ]
-}
-
-# This util file must be separate from the below
-# omnibox_util file because it is used in showcase. This
-# means that its dependencies should be limited, avoiding
-# components code.
-source_set("omnibox_suggestion_icon_util") {
-  sources = [
-    "omnibox_suggestion_icon_util.h",
-    "omnibox_suggestion_icon_util.mm",
-  ]
-  deps = [
-    "//base",
-    "//ios/chrome/browser/shared/ui/symbols",
-    "//ios/chrome/browser/shared/ui/symbols:buildflags",
-  ]
-}
-
-# See the comment above on omnibox_suggestion_icon_util
-# for why these two targets are separated.
-source_set("omnibox_util") {
-  sources = [
-    "omnibox_metrics_helper.h",
-    "omnibox_metrics_helper.mm",
-    "omnibox_text_change_delegate.h",
-    "omnibox_text_field_delegate.h",
-    "omnibox_util.h",
-    "omnibox_util.mm",
-  ]
-  deps = [
-    ":features",
-    ":omnibox_suggestion_icon_util",
-    "//base",
-    "//components/omnibox/browser",
-    "//components/safe_browsing/core/common:common",
-    "//components/security_state/core",
-    "//ios/chrome/browser/shared/public/features",
-    "//ios/chrome/browser/shared/ui/symbols",
-    "//third_party/omnibox_proto",
-  ]
-  public_deps = [
-    ":omnibox_icon_type_constants",
-    "//ios/chrome/app/theme",
-  ]
-}
-
-# This target can also be used on EG2 tests, so it should only contain constants
-source_set("omnibox_icon_type_constants") {
-  sources = [
-    "omnibox_icon_type.h",
-    "omnibox_icon_type.mm",
-  ]
-  deps = [
-    "//base",
-    "//ios/chrome/browser/shared/ui/symbols",
-  ]
-}
-
-source_set("omnibox_internal") {
-  sources = [
-    "chrome_omnibox_client_ios.h",
-    "chrome_omnibox_client_ios.mm",
-    "fake_suggestions_database.cc",
-    "fake_suggestions_database.h",
-    "omnibox_consumer.h",
-    "omnibox_container_view.h",
-    "omnibox_container_view.mm",
-    "omnibox_coordinator.h",
-    "omnibox_coordinator.mm",
-    "omnibox_mediator.h",
-    "omnibox_mediator.mm",
-    "omnibox_return_key_forwarding_delegate.h",
-    "omnibox_return_key_forwarding_delegate.mm",
-    "omnibox_text_field_ios.h",
-    "omnibox_text_field_ios.mm",
-    "omnibox_text_field_paste_delegate.h",
-    "omnibox_text_field_paste_delegate.mm",
-    "omnibox_thumbnail_button.h",
-    "omnibox_thumbnail_button.mm",
-    "omnibox_view_consumer.h",
-    "omnibox_view_controller.h",
-    "omnibox_view_controller.mm",
-    "omnibox_view_ios.h",
-    "omnibox_view_ios.mm",
-    "text_field_view_containing.h",
-    "web_location_bar_impl.h",
-    "web_location_bar_impl.mm",
-    "zero_suggest_prefetch_helper.h",
-    "zero_suggest_prefetch_helper.mm",
-  ]
-  deps = [
-    ":features",
-    ":omnibox",
-    ":omnibox_popup_shared",
-    ":omnibox_suggestion_icon_util",
-    ":omnibox_util",
-    "//base",
-    "//components/favicon/ios",
-    "//components/feature_engagement/public",
-    "//components/open_from_clipboard:",
-    "//components/open_from_clipboard:open_from_clipboard_impl",
-    "//components/resources",
-    "//components/search_engines",
-    "//components/security_state/core",
-    "//components/strings",
-    "//ios/chrome/app/strings",
-    "//ios/chrome/browser/autocomplete/model",
-    "//ios/chrome/browser/bookmarks/model",
-    "//ios/chrome/browser/bookmarks/model:model_utils",
-    "//ios/chrome/browser/default_browser/model:default_browser_interest_signals",
-    "//ios/chrome/browser/default_promo/ui_bundled:coordinator",
-    "//ios/chrome/browser/favicon/model",
-    "//ios/chrome/browser/feature_engagement/model",
-    "//ios/chrome/browser/fullscreen/ui_bundled",
-    "//ios/chrome/browser/https_upgrades/model",
-    "//ios/chrome/browser/intents/model:model_donation_helper",
-    "//ios/chrome/browser/lens/ui_bundled:lens_entrypoint",
-    "//ios/chrome/browser/location_bar/ui_bundled:constants",
-    "//ios/chrome/browser/main/ui_bundled:default_browser_scene_agent",
-    "//ios/chrome/browser/net/model",
-    "//ios/chrome/browser/ntp/model",
-    "//ios/chrome/browser/ntp/shared/metrics:home_metrics",
-    "//ios/chrome/browser/orchestrator/ui_bundled:ui_bundled",
-    "//ios/chrome/browser/prerender/model",
-    "//ios/chrome/browser/search_engines/model",
-    "//ios/chrome/browser/search_engines/model:search_engines_util",
-    "//ios/chrome/browser/sessions/model",
-    "//ios/chrome/browser/shared/coordinator/chrome_coordinator",
-    "//ios/chrome/browser/shared/coordinator/layout_guide",
-    "//ios/chrome/browser/shared/coordinator/scene:scene_state_header",
-    "//ios/chrome/browser/shared/model/browser",
-    "//ios/chrome/browser/shared/model/profile",
-    "//ios/chrome/browser/shared/model/url:constants",
-    "//ios/chrome/browser/shared/public/commands",
-    "//ios/chrome/browser/shared/public/features",
-    "//ios/chrome/browser/shared/public/features:system_flags",
-    "//ios/chrome/browser/shared/ui/elements",
-    "//ios/chrome/browser/shared/ui/symbols",
-    "//ios/chrome/browser/shared/ui/util",
-    "//ios/chrome/browser/shared/ui/util:omnibox_util",
-    "//ios/chrome/browser/shared/ui/util:util_swift",
-    "//ios/chrome/browser/toolbar/ui_bundled/public:constants",
-    "//ios/chrome/browser/ui/omnibox/popup",
-    "//ios/chrome/browser/ui/omnibox/popup:popup_ui_protocols",
-    "//ios/chrome/browser/url_loading/model",
-    "//ios/chrome/common",
-    "//ios/chrome/common/ui/colors",
-    "//ios/chrome/common/ui/favicon:favicon",
-    "//ios/chrome/common/ui/favicon:favicon_constants",
-    "//ios/chrome/common/ui/util",
-    "//ios/chrome/common/ui/util:dynamic_type_util",
-    "//ios/chrome/common/ui/util:image_util",
-    "//ios/components/security_interstitials/https_only_mode",
-    "//ios/public/provider/chrome/browser/branded_images:branded_images_api",
-    "//ios/public/provider/chrome/browser/lens:lens_api",
-    "//ios/web/common:uikit",
-    "//ios/web/public",
-    "//net",
-    "//skia",
-    "//ui/base",
-    "//ui/gfx",
-    "//ui/gfx/geometry",
-    "//url",
-  ]
-  public_deps = [
-    ":omnibox_icon_type_constants",
-    "//components/omnibox/browser",
-  ]
-  frameworks = [
-    "CoreText.framework",
-    "MobileCoreServices.framework",
-    "QuartzCore.framework",
-    "UIKit.framework",
-    "UniformTypeIdentifiers.framework",
-  ]
-}
-
-source_set("eg_app_support+eg2") {
-  configs += [ "//build/config/ios:xctest_config" ]
-  testonly = true
-  sources = [
-    "omnibox_app_interface.h",
-    "omnibox_app_interface.mm",
-    "test_fake_suggestions_service.cc",
-    "test_fake_suggestions_service.h",
-  ]
-  deps = [
-    ":omnibox_internal",
-    ":resources_fake_suggestions_tests",
-    "//base",
-    "//components/google/core/common",
-    "//components/history/core/browser",
-    "//components/omnibox/browser",
-    "//components/search_engines",
-    "//components/variations:variations",
-    "//ios/chrome/browser/autocomplete/model",
-    "//ios/chrome/browser/history/model",
-    "//ios/chrome/browser/search_engines/model",
-    "//ios/chrome/browser/search_engines/model:template_url_service_factory",
-    "//ios/chrome/browser/shared/model/profile",
-    "//ios/chrome/browser/ui/omnibox/popup:popup_ui",
-    "//ios/chrome/test/app:test_support",
-    "//ios/testing:nserror_support",
-    "//ios/testing/earl_grey:eg_app_support+eg2",
-    "//ios/third_party/earl_grey2:app_framework+link",
-    "//ios/web/public",
-    "//ios/web/public/navigation",
-    "//net:test_support",
-    "//services/network:test_support",
-    "//ui/base",
-    "//ui/base:test_support",
-  ]
-}
-source_set("eg_test_support+eg2") {
-  configs += [ "//build/config/ios:xctest_config" ]
-  testonly = true
-  sources = [
-    "omnibox_app_interface.h",
-    "omnibox_app_interface_stub.mm",
-    "omnibox_earl_grey.h",
-    "omnibox_earl_grey.mm",
-    "omnibox_matchers.h",
-    "omnibox_matchers.mm",
-    "omnibox_test_util.h",
-    "omnibox_test_util.mm",
-  ]
-  deps = [
-    "//base/test:test_support",
-    "//ios/chrome/app/strings",
-    "//ios/chrome/browser/ui/omnibox/popup:popup_accessibility_identifier_constants",
-    "//ios/chrome/test/earl_grey:eg_test_support+eg2",
-    "//ios/testing/earl_grey:eg_test_support+eg2",
-    "//ios/testing/earl_grey:launch_configuration",
-    "//net:test_support",
-    "//ui/base",
-  ]
-}
-
-source_set("eg2_tests") {
-  configs += [ "//build/config/ios:xctest_config" ]
-  testonly = true
-  sources = [
-    "omnibox_edit_egtest.mm",
-    "omnibox_egtest.mm",
-  ]
-  deps = [
-    ":eg_test_support+eg2",
-    ":features",
-    "//components/feature_engagement/public",
-    "//components/omnibox/common",
-    "//components/strings:components_strings_grit",
-    "//ios/chrome/app/strings",
-    "//ios/chrome/browser/content_suggestions/ui_bundled:content_suggestions_constant",
-    "//ios/chrome/browser/iph_for_new_chrome_user/model:features",
-    "//ios/chrome/browser/shared/model/prefs:pref_names",
-    "//ios/chrome/browser/shared/public/features",
-    "//ios/chrome/browser/toolbar/ui_bundled/public:constants",
-    "//ios/chrome/browser/ui/omnibox/popup:popup_accessibility_identifier_constants",
-    "//ios/chrome/test/earl_grey:eg_test_support+eg2",
-    "//ios/chrome/test/earl_grey:switches",
-    "//ios/testing/earl_grey:eg_test_support+eg2",
-    "//ios/web/public/test:element_selector",
-    "//net:test_support",
-    "//ui/base",
-  ]
-  frameworks = [ "UIKit.framework" ]
-}
-
-source_set("test_support") {
-  testonly = true
-  sources = [
-    "test_web_location_bar.cc",
-    "test_web_location_bar.h",
-  ]
-  deps = [
-    ":omnibox",
-    "//base",
-    "//components/omnibox/browser:location_bar",
-    "//ios/web/public",
-    "//url",
-  ]
-  frameworks = [ "UIKit.framework" ]
-}
-
-source_set("unit_tests") {
-  testonly = true
-  sources = [
-    "chrome_omnibox_client_ios_unittest.mm",
-    "fake_suggestions_database_unittest.cc",
-    "omnibox_text_field_ios_unittest.mm",
-    "zero_suggest_prefetch_helper_unittest.mm",
-  ]
-  deps = [
-    ":features",
-    ":omnibox",
-    ":omnibox_internal",
-    ":resources_unit_tests",
-    ":test_support",
-    "//base",
-    "//base/test:test_support",
-    "//components/bookmarks/browser",
-    "//components/feature_engagement/public",
-    "//components/feature_engagement/test:test_support",
-    "//components/omnibox/browser:test_support",
-    "//components/search_engines",
-    "//components/search_engines:test_support",
-    "//ios/chrome/app/strings",
-    "//ios/chrome/browser/autocomplete/model",
-    "//ios/chrome/browser/main/model",
-    "//ios/chrome/browser/shared/model/browser/test:test_support",
-    "//ios/chrome/browser/shared/model/paths",
-    "//ios/chrome/browser/shared/model/profile/test",
-    "//ios/chrome/browser/shared/model/url:constants",
-    "//ios/chrome/browser/shared/model/web_state_list",
-    "//ios/chrome/browser/shared/model/web_state_list/test:test_support",
-    "//ios/chrome/browser/shared/ui/util",
-    "//ios/chrome/test:block_cleanup_test",
-    "//ios/testing:nserror_support",
-    "//ios/web/common:uikit",
-    "//ios/web/public/test/fakes",
-    "//testing/gtest",
-    "//third_party/ocmock",
-    "//ui/base",
-  ]
-}
-
-bundle_data("resources_unit_tests") {
-  visibility = [ ":unit_tests" ]
-  testonly = true
-  sources = [ "//ios/chrome/test/data/omnibox/selected_ranges.txt" ]
-  outputs = [ "{{bundle_resources_dir}}/" +
-              "ios/chrome/test/data/omnibox/{{source_file_part}}" ]
-}
-
-bundle_data("resources_fake_suggestions_tests") {
-  visibility = [ ":eg_app_support+eg2" ]
-  testonly = true
-  sources = [
-    "//ios/chrome/test/data/omnibox/fake_suggestion_actions.json",
-    "//ios/chrome/test/data/omnibox/fake_suggestions_pedal.json",
-    "//ios/chrome/test/data/omnibox/fake_suggestions_sample.json",
-  ]
-  outputs = [ "{{bundle_resources_dir}}/" +
-              "{{source_root_relative_dir}}/{{source_file_part}}" ]
-}
-
-source_set("features") {
-  sources = [
-    "omnibox_ui_features.cc",
-    "omnibox_ui_features.h",
-  ]
-  public_deps = [ "//base" ]
-  deps = [
-    "//components/omnibox/common",
-    "//ios/chrome/browser/shared/public/features",
-    "//ui/base",
-  ]
-}
diff --git a/ios/chrome/browser/ui/omnibox/DEPS b/ios/chrome/browser/ui/omnibox/DEPS
deleted file mode 100644
index 6152657..0000000
--- a/ios/chrome/browser/ui/omnibox/DEPS
+++ /dev/null
@@ -1,13 +0,0 @@
-include_rules = [
-  "+ios/chrome/browser/location_bar/ui_bundled",
-  "+ios/chrome/browser/lens/ui_bundled/lens_entrypoint.h",
-  "+ios/chrome/browser/orchestrator/ui_bundled",
-  "+ios/chrome/browser/ntp/shared/metrics/home_metrics.h",
-  "+ios/chrome/browser/toolbar/ui_bundled/public",
-]
-
-specific_include_rules = {
-  "^omnibox_coordinator.mm": [
-    "+ios/chrome/browser/bubble/ui_bundled/bubble_presenter.h",
-  ],
-}
diff --git a/ios/chrome/browser/ui/toolbar/DEPS b/ios/chrome/browser/ui/toolbar/DEPS
deleted file mode 100644
index 9b05968..0000000
--- a/ios/chrome/browser/ui/toolbar/DEPS
+++ /dev/null
@@ -1,16 +0,0 @@
-include_rules = [
-  "+ios/chrome/browser/infobars/ui_bundled/test_infobar_delegate.h",
-  "+ios/chrome/browser/menu/ui_bundled",
-  "+ios/chrome/browser/popup_menu/ui_bundled/public",
-  "+ios/chrome/browser/fullscreen/ui_bundled",
-  "+ios/chrome/browser/location_bar/ui_bundled",
-  "+ios/chrome/browser/omnibox/ui_bundled",
-  "+ios/chrome/browser/orchestrator/ui_bundled",
-  "+ios/chrome/browser/keyboard/ui_bundled/key_command_actions.h",
-  "+ios/chrome/browser/keyboard/ui_bundled/UIKeyCommand+Chrome.h",
-  "+ios/chrome/browser/lens/ui_bundled",
-  "+ios/chrome/browser/ntp/ui_bundled/new_tab_page_controller_delegate.h",
-  "+ios/chrome/browser/sharing/ui_bundled",
-  "+ios/chrome/browser/ntp/ui_bundled/new_tab_page_util.h",
-  "+ios/chrome/browser/content_suggestions/ui_bundled/content_suggestions_collection_utils.h",
-]
diff --git a/ios/chrome/browser/url_loading/model/DEPS b/ios/chrome/browser/url_loading/model/DEPS
index 3bb6048..b36425d8 100644
--- a/ios/chrome/browser/url_loading/model/DEPS
+++ b/ios/chrome/browser/url_loading/model/DEPS
@@ -14,7 +14,6 @@
   "^url_loading_browser_agent.mm": [
     "+ios/chrome/browser/incognito_reauth/ui_bundled/incognito_reauth_scene_agent.h",
     "+ios/chrome/browser/ntp/ui_bundled/new_tab_page_util.h",
-    "+ios/chrome/browser/ui/ui_feature_flags.h",
   ],
 }
 
diff --git a/ios/chrome/browser/web/model/DEPS b/ios/chrome/browser/web/model/DEPS
index 9c8aee0..7c1e52b77 100644
--- a/ios/chrome/browser/web/model/DEPS
+++ b/ios/chrome/browser/web/model/DEPS
@@ -53,9 +53,6 @@
   "page_placeholder_tab_helper.h": [
     "+ios/chrome/browser/shared/ui/elements/top_aligned_image_view.h",
   ],
-  "browser_about_rewriter.cc": [
-    "+ios/chrome/browser/ui/ui_feature_flags.h",
-  ],
   # web::HttpServer is deprecated in favor of net::EmbeddedTestServer.
   # TODO:(crbug.com/891834) Remove this exception.
   "browsing_egtest\.mm": [
diff --git a/ios/chrome/content_widget_extension/DEPS b/ios/chrome/content_widget_extension/DEPS
index 63350d20..af8e828 100644
--- a/ios/chrome/content_widget_extension/DEPS
+++ b/ios/chrome/content_widget_extension/DEPS
@@ -1,6 +1,5 @@
 include_rules = [
   "-url",
-  "+ios/chrome/browser/ui/util",
   "+ios/chrome/browser/favicon/ui_bundled",
   "+ios/chrome/browser/ntp/ui_bundled",
 ]
diff --git a/ios/chrome/search_widget_extension/DEPS b/ios/chrome/search_widget_extension/DEPS
index 2547b11..5349816 100644
--- a/ios/chrome/search_widget_extension/DEPS
+++ b/ios/chrome/search_widget_extension/DEPS
@@ -1,5 +1,4 @@
 include_rules = [
   "+components/open_from_clipboard",
-  "+ios/chrome/browser/ui/util",
   "-url",
 ]
diff --git a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1
index fed5c6f..be01ec3 100644
--- a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-901bb803930e9a504d62bcd493af266b5e108ffe
\ No newline at end of file
+68ed93b10e07493c94f8188dd76365563e1f5434
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1
index a3548c60..50b9118 100644
--- a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@
-fa82ef144476f6785c23e168c403a8028f1a280b
\ No newline at end of file
+9dc60be1af6cccff0dcc10550f37a0378f0fdf60
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
index 9098c2f..ac994003 100644
--- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-3b9ce6b2dc854dd7af16d99ddce531507afca4ee
\ No newline at end of file
+78e6ecfb61630ae24c8902e06bca2a284c45139c
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1
index 4965f831..6a87df5 100644
--- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@
-38aa6805fe597132b668767c53b1e142f17fac8d
\ No newline at end of file
+0c76940398bdd1ad44ea72493d58221f1cab03a0
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
index e59acd1..969d848f 100644
--- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-272cf1eb687d2275e72b30075c17c0c12b36da33
\ No newline at end of file
+de11ab0104bfd218c3917bb95adc996b6d548f84
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1
index 6f55bdc..58e35ff 100644
--- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@
-bd799aae8a3cfc45b2ce2c065484e7762998d213
\ No newline at end of file
+92c1a212a4b6fb09c73289f43353275c7dead092
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1
index f7cffa2..ad1582e 100644
--- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-859459326cea6c07c14bc2e760e9ec428062104c
\ No newline at end of file
+6fefcb72e8d55f2f289a9d6859a11613b0eb1f2f
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1
index 57b97d0..11527b9 100644
--- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@
-b22125901e4cf546280180c599552b63c03c239d
\ No newline at end of file
+6600d7029002375a9445f8413a39ad19cf02cdaa
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1
index 97fec076..e8882bbc 100644
--- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-67b8b428b7b188328367f67350e149a0207e0544
\ No newline at end of file
+a60a7b2381f0cf8e24dcd91c6d948684cfc1b997
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1
index 93541d9..7262751 100644
--- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@
-a2e5d222b99e99ea674045b1aa78d2611cbfb7fb
\ No newline at end of file
+b0866c27b56fab238c72f74daa31f2bc3b66b687
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
index 0b14e96..d42aac9 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-bbaf1e6e5df37da0c69d082fe7a7bb617db5566e
\ No newline at end of file
+b11641def3538ebd64444085f598e120fc72c83c
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1
index 28ad1f9..2cc47438 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@
-a38fab0547f9af9ad9013010614f9c5b57ffa7ce
\ No newline at end of file
+56e8416741baf75f0ab2e5239ee81ef80b07d2ec
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
index 1a5d572..ee60ab7b 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-d3db7ea6d7e1e60c5a57a9352a654d2f07dba5cd
\ No newline at end of file
+befb3c67809522c6775999916101961582666d25
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1
index f61266b..288c325a 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@
-caf4c0038b996f89d857492b39fc13aeab5640fa
\ No newline at end of file
+e0e05e01ae3d834270d84e6507d7603fd5badb1b
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
index e0931aef..12243289 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-0ea1bd22731d7601eb5c7cac5038e51d8eb30ff6
\ No newline at end of file
+b91b5cd49b95fc43e6a8d4b524b2d48f6f304ba1
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1
index 8560684..549e83e 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@
-d1afa5c93ce3f56a984dd8f0c89ea17d34b63778
\ No newline at end of file
+b5f517b85bcd137159feadb304ab87e546d28a3a
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
index 9a41446d..777f861 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-b1a695416d4c41c9f341d23c6bc822ee0ffd6d60
\ No newline at end of file
+731ea59b6e4443eb52da4738ffbe01afcc92f10a
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1
index 49d47806..55b3c43 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@
-763e90bdd0b3bfbdb03a1d1319abaf667136b3c8
\ No newline at end of file
+ebad14f8f58b30c94c5ed6a6237cbbf9f648e0ac
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
index a5fd17f8..90d42c0 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-42c0f39f608c65a220a1497d4f5d2331c5d0d8b5
\ No newline at end of file
+be709cc0e2759dacbb990e439129d65b24ede987
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
index 189bbb9..810cd71 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-cae5cce2c5087f873a481bbfba99faddb58d2958
\ No newline at end of file
+0e4d37c268ddcaad009591c4fdbcb3fd1d8062ca
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
index c28a432..cd2c5bbe 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-28a22e6e97fb649409a229da89416c0a43b2edc6
\ No newline at end of file
+e0da9d519703e8f01405d09464aa4f05ada9a1a5
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1
index 268f84d..b00b583 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@
-5a4709243343a47176f5246b31d111e71e71ef09
\ No newline at end of file
+5bad32b1f2c7402eced7f3f601689b474aa7af12
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
index f16f34e..e5da1d615 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-688452611f4d16134436849a8d22ad8d5344389e
\ No newline at end of file
+b5266f541de423fb61a199ab62a30007f26590eb
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1
index 6fb856c7..188e9a2 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@
-a3672a1198a78fdd2ef9321c82d0aae1540d00c4
\ No newline at end of file
+b1cce7371e2f292291f6828fcf8dff2a8c675c76
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
index c4b53e9..3f8a98cf 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-5434793ec9fdbc16b5a41963a3c07b9b9a5214ab
\ No newline at end of file
+03907d8b6fa9ec22bf06ba3026359f683dca46a7
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1
index e259cb0c..73eb4ff0 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@
-71bfc14b5314b55535000c071b04e0fc15cd383f
\ No newline at end of file
+614e9c912ee87c5106473f8cd52bb6797bd42f1e
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
index ed7dbfd..313d6a6 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-fcd1b013c954852c13508d29239c5a28b6356f1c
\ No newline at end of file
+1f998f77054252125df162486bfed11ccf065034
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1
index 1df077fb..3b3240f5 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@
-dd51d1515fede77725530a991831b8ea4bcfbca8
\ No newline at end of file
+b963dfd9075fcb10ac4a743fd7676377ae1047d3
\ No newline at end of file
diff --git a/ios_internal b/ios_internal
index 34b7776..5246c29 160000
--- a/ios_internal
+++ b/ios_internal
@@ -1 +1 @@
-Subproject commit 34b77766e5677df1c0699fb97f42071a468ab696
+Subproject commit 5246c294f4718ee3ff4b0003ab484359423f9818
diff --git a/net/dns/host_resolver_manager_service_endpoint_request_impl.cc b/net/dns/host_resolver_manager_service_endpoint_request_impl.cc
index 81340d0..9cb8b7a 100644
--- a/net/dns/host_resolver_manager_service_endpoint_request_impl.cc
+++ b/net/dns/host_resolver_manager_service_endpoint_request_impl.cc
@@ -357,7 +357,13 @@
   }
 
   if (is_stale && stale_allowed_while_refreshing) {
-    stale_endpoints_ = results.ConvertToServiceEndpoints(host_.GetPort());
+    // Allow using stale results only when there is no network change.
+    // TODO(crbug.com/383174960): This also exclude results that are obtained
+    // from the same network but the device got disconnected/connected events.
+    // Ideally we should be able to use such results.
+    if (results.network_changes() == host_cache()->network_changes()) {
+      stale_endpoints_ = results.ConvertToServiceEndpoints(host_.GetPort());
+    }
     if (!stale_endpoints_.empty()) {
       net_log_.AddEvent(
           NetLogEventType::HOST_RESOLVER_SERVICE_ENDPOINTS_STALE_RESULTS, [&] {
diff --git a/net/dns/host_resolver_manager_unittest.cc b/net/dns/host_resolver_manager_unittest.cc
index 6752b27a..3f1ea9a 100644
--- a/net/dns/host_resolver_manager_unittest.cc
+++ b/net/dns/host_resolver_manager_unittest.cc
@@ -535,7 +535,7 @@
       resolve_context_->host_cache(), key,
       HostCache::Entry(OK, std::move(endpoints), /*aliases=*/{},
                        HostCache::Entry::SOURCE_UNKNOWN),
-      base::Seconds(1));
+      kDefaultTtl);
 }
 
 const std::pair<const HostCache::Key, HostCache::Entry>*
diff --git a/net/dns/host_resolver_manager_unittest.h b/net/dns/host_resolver_manager_unittest.h
index d90a1b1..5b278ec 100644
--- a/net/dns/host_resolver_manager_unittest.h
+++ b/net/dns/host_resolver_manager_unittest.h
@@ -31,6 +31,7 @@
 class HostResolverManagerTest : public TestWithTaskEnvironment {
  public:
   static const int kDefaultPort = 80;
+  static inline constexpr base::TimeDelta kDefaultTtl = base::Seconds(1);
 
   explicit HostResolverManagerTest(
       base::test::TaskEnvironment::TimeSource time_source =
diff --git a/net/dns/host_resolver_service_endpoint_request_unittest.cc b/net/dns/host_resolver_service_endpoint_request_unittest.cc
index 83462e3..5a1b899 100644
--- a/net/dns/host_resolver_service_endpoint_request_unittest.cc
+++ b/net/dns/host_resolver_service_endpoint_request_unittest.cc
@@ -87,6 +87,7 @@
   // ServiceEndpointRequest::Delegate overrides:
 
   void OnServiceEndpointsUpdated() override {
+    ++on_updated_call_count_;
     if (on_updated_callback_) {
       std::move(on_updated_callback_).Run();
     }
@@ -157,6 +158,8 @@
     return finished_endpoints_;
   }
 
+  size_t on_updated_call_count() const { return on_updated_call_count_; }
+
  private:
   void SetFinishedResult(int rv) {
     CHECK(!finished_result_);
@@ -172,6 +175,8 @@
   std::optional<int> finished_result_;
   std::vector<ServiceEndpoint> finished_endpoints_;
 
+  size_t on_updated_call_count_ = 0;
+
   base::OnceClosure wait_for_finished_callback_;
   base::OnceClosure on_updated_callback_;
   base::OnceClosure on_finished_callback_;
@@ -340,6 +345,11 @@
     PopulateCache(key, std::move(endpoints));
   }
 
+  void AdvanceTickClockToExpirePopulatedCacheEntries() {
+    // PopulateCache() uses kDefaultTtl for TTL.
+    FastForwardBy(kDefaultTtl);
+  }
+
  private:
   base::test::ScopedFeatureList feature_list_;
 
@@ -1217,7 +1227,7 @@
   std::vector<IPEndPoint> stale_endpoints = {stale_endpoint1, stale_endpoint2};
 
   PopulateCacheForUrl("https://4slow_ok", stale_endpoints);
-  MakeCacheStale();
+  AdvanceTickClockToExpirePopulatedCacheEntries();
 
   ResolveHostParameters parameters;
   parameters.cache_usage = HostResolver::ResolveHostParameters::CacheUsage::
@@ -1243,6 +1253,39 @@
   EXPECT_FALSE(requester.request()->GetStaleInfo());
 }
 
+TEST_F(HostResolverServiceEndpointRequestTest,
+       StaleDisallowedAsIntermediateForNetworkChange) {
+  UseIpv4DelayedDnsRules("4slow_ok");
+  IPEndPoint fresh_endpoint1 = MakeIPEndPoint("127.0.0.1", 443);
+  IPEndPoint fresh_endpoint2 = MakeIPEndPoint("::1", 443);
+
+  IPEndPoint stale_endpoint1 = MakeIPEndPoint("192.0.2.1", 443);
+  IPEndPoint stale_endpoint2 = MakeIPEndPoint("2001:db8::1", 443);
+  std::vector<IPEndPoint> stale_endpoints = {stale_endpoint1, stale_endpoint2};
+
+  PopulateCacheForUrl("https://4slow_ok", stale_endpoints);
+  // This simulates a network change.
+  MakeCacheStale();
+
+  ResolveHostParameters parameters;
+  parameters.cache_usage = HostResolver::ResolveHostParameters::CacheUsage::
+      STALE_ALLOWED_WHILE_REFRESHING;
+  Requester requester =
+      CreateRequester("https://4slow_ok", std::move(parameters));
+  int rv = requester.Start();
+  EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+  mock_dns_client_->CompleteDelayedTransactions();
+  requester.WaitForFinished();
+  EXPECT_THAT(requester.finished_result(), Optional(IsOk()));
+  EXPECT_THAT(requester.finished_endpoints(),
+              ElementsAre(ExpectServiceEndpoint(ElementsAre(fresh_endpoint1),
+                                                ElementsAre(fresh_endpoint2))));
+  EXPECT_FALSE(requester.request()->GetStaleInfo());
+  // There should be no update callback call.
+  EXPECT_EQ(requester.on_updated_call_count(), 0u);
+}
+
 TEST_F(HostResolverServiceEndpointRequestTest, StaleAllowed) {
   UseIpv4DelayedDnsRules("4slow_ok");
 
@@ -1251,7 +1294,7 @@
   std::vector<IPEndPoint> stale_endpoints = {stale_endpoint1, stale_endpoint2};
 
   PopulateCacheForUrl("https://4slow_ok", stale_endpoints);
-  MakeCacheStale();
+  AdvanceTickClockToExpirePopulatedCacheEntries();
 
   ResolveHostParameters parameters;
   parameters.cache_usage =
@@ -1302,7 +1345,7 @@
   std::vector<IPEndPoint> stale_endpoints = {stale_endpoint1, stale_endpoint2};
 
   PopulateCacheForUrl("https://ok", stale_endpoints);
-  MakeCacheStale();
+  AdvanceTickClockToExpirePopulatedCacheEntries();
 
   ResolveHostParameters parameters;
   parameters.cache_usage =
@@ -1326,7 +1369,7 @@
   std::vector<IPEndPoint> stale_endpoints = {stale_endpoint1, stale_endpoint2};
 
   PopulateCacheForUrl("https://ok", stale_endpoints);
-  MakeCacheStale();
+  AdvanceTickClockToExpirePopulatedCacheEntries();
 
   ResolveHostParameters parameters;
   parameters.cache_usage = HostResolver::ResolveHostParameters::CacheUsage::
@@ -1349,7 +1392,7 @@
   std::vector<IPEndPoint> stale_endpoints = {stale_endpoint1, stale_endpoint2};
 
   PopulateCacheForUrl("https://ok", stale_endpoints);
-  MakeCacheStale();
+  AdvanceTickClockToExpirePopulatedCacheEntries();
 
   ResolveHostParameters parameters;
   parameters.cache_usage = HostResolver::ResolveHostParameters::CacheUsage::
@@ -1389,7 +1432,7 @@
   std::vector<IPEndPoint> stale_endpoints = {stale_endpoint1, stale_endpoint2};
 
   PopulateCacheForUrl("https://4slow_ok", stale_endpoints);
-  MakeCacheStale();
+  AdvanceTickClockToExpirePopulatedCacheEntries();
 
   ResolveHostParameters parameters;
   parameters.cache_usage = HostResolver::ResolveHostParameters::CacheUsage::
@@ -1442,7 +1485,7 @@
   std::vector<IPEndPoint> stale_endpoints = {stale_endpoint1, stale_endpoint2};
 
   PopulateCacheForUrl("https://6slow_ok", stale_endpoints);
-  MakeCacheStale();
+  AdvanceTickClockToExpirePopulatedCacheEntries();
 
   ResolveHostParameters parameters;
   parameters.cache_usage = HostResolver::ResolveHostParameters::CacheUsage::
@@ -1489,7 +1532,7 @@
   SetDnsRules(std::move(rules));
 
   PopulateCacheForUrl("https://ok", {stale_endpoint});
-  MakeCacheStale();
+  AdvanceTickClockToExpirePopulatedCacheEntries();
 
   ResolveHostParameters parameters;
   parameters.cache_usage =
@@ -1522,7 +1565,7 @@
   SetDnsRules(std::move(rules));
 
   PopulateCacheForUrl("https://ok", {stale_endpoint}, /*secure=*/true);
-  MakeCacheStale();
+  AdvanceTickClockToExpirePopulatedCacheEntries();
   PopulateCacheForUrl("https://ok", {fresh_endpoint}, /*secure=*/false);
 
   mock_dns_client_->set_preset_endpoint(
diff --git a/net/http/no_vary_search_cache.cc b/net/http/no_vary_search_cache.cc
index 2ef2ccd..3ba467a7 100644
--- a/net/http/no_vary_search_cache.cc
+++ b/net/http/no_vary_search_cache.cc
@@ -342,6 +342,7 @@
 
 std::optional<NoVarySearchCache::LookupResult> NoVarySearchCache::Lookup(
     const HttpRequestInfo& request) {
+  SCOPED_UMA_HISTOGRAM_TIMER_MICROS("HttpCache.NoVarySearch.LookupTime");
   const GURL& url = request.url;
   if (!URLIsAcceptable(url)) {
     return std::nullopt;
diff --git a/printing/printing_features.cc b/printing/printing_features.cc
index 04751a844..abf345e 100644
--- a/printing/printing_features.cc
+++ b/printing/printing_features.cc
@@ -18,6 +18,12 @@
 BASE_FEATURE(kAddPrinterViaPrintscanmgr,
              "AddPrinterViaPrintscanmgr",
              base::FEATURE_ENABLED_BY_DEFAULT);
+
+// Controls whether chrome.printing API uses margins and scale ticket items when
+// submitting a print job.
+BASE_FEATURE(kApiPrintingMarginsAndScale,
+             "ApiPrintingMarginsAndScale",
+             base::FEATURE_DISABLED_BY_DEFAULT);
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC)
diff --git a/printing/printing_features.h b/printing/printing_features.h
index ede78b160..8ab4099 100644
--- a/printing/printing_features.h
+++ b/printing/printing_features.h
@@ -19,6 +19,9 @@
 #if BUILDFLAG(IS_CHROMEOS)
 COMPONENT_EXPORT(PRINTING_BASE)
 BASE_DECLARE_FEATURE(kAddPrinterViaPrintscanmgr);
+
+COMPONENT_EXPORT(PRINTING_BASE)
+BASE_DECLARE_FEATURE(kApiPrintingMarginsAndScale);
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC)
diff --git a/services/audio/mixing_graph_impl.cc b/services/audio/mixing_graph_impl.cc
index ddc3a5d..c49b40e 100644
--- a/services/audio/mixing_graph_impl.cc
+++ b/services/audio/mixing_graph_impl.cc
@@ -24,7 +24,7 @@
     const media::AudioParameters& input_params,
     const media::AudioParameters& output_params) {
   return std::make_unique<media::LoopbackAudioConverter>(
-      input_params, output_params, /*disable_fifo=*/true);
+      input_params, output_params, /*disable_fifo=*/false);
 }
 
 // Clamps all samples to the interval [-1, 1].
@@ -90,7 +90,7 @@
       create_converter_cb_(std::move(create_converter_cb)),
       overtime_logger_(
           std::make_unique<OvertimeLogger>(output_params.GetBufferDuration())),
-      main_converter_(output_params, output_params, /*disable_fifo=*/true) {}
+      main_converter_(output_params, output_params, /*disable_fifo=*/false) {}
 
 MixingGraphImpl::~MixingGraphImpl() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
@@ -135,12 +135,18 @@
   DCHECK(input_params.format() ==
          media::AudioParameters::AUDIO_PCM_LOW_LATENCY);
 
-  // Resampler input format is the same as output except sample rate.
+  // Resampler input format is the same as output except sample rate and frames
+  // per buffer.
   media::AudioParameters resampler_input_params(output_params_);
   resampler_input_params.set_sample_rate(input_params.sample_rate());
+  resampler_input_params.set_frames_per_buffer(
+      input_params.frames_per_buffer());
 
   // Channel mixer input format is the same as resampler input except channel
   // layout and channel count.
+  // TODO(crbug.com/406869460): Consider using full input parameters for
+  // channel mixer. This might allow AudioConverter to optimize (e.g., downmix)
+  // before resampling.
   media::AudioParameters channel_mixer_input_params(
       resampler_input_params.format(), input_params.channel_layout_config(),
       resampler_input_params.sample_rate(),
diff --git a/services/audio/sync_mixing_graph_input.cc b/services/audio/sync_mixing_graph_input.cc
index 59970d4..de1f20c2 100644
--- a/services/audio/sync_mixing_graph_input.cc
+++ b/services/audio/sync_mixing_graph_input.cc
@@ -35,6 +35,8 @@
 
   glitch_info_accumulator_.Add(glitch_info);
 
+  // TODO(crbug.com/406867864): Consider removing the unnecessary FIFO if the
+  // render call can directly handle all buffer size variations.
   if (!fifo_ && audio_bus->frames() != params_.frames_per_buffer()) {
     fifo_ = std::make_unique<media::AudioPullFifo>(
         params_.channels(), params_.frames_per_buffer(),
diff --git a/services/network/public/cpp/content_decoding_interceptor.cc b/services/network/public/cpp/content_decoding_interceptor.cc
index d914140..d24656c4 100644
--- a/services/network/public/cpp/content_decoding_interceptor.cc
+++ b/services/network/public/cpp/content_decoding_interceptor.cc
@@ -229,6 +229,10 @@
 };
 }  // namespace
 
+// static
+bool ContentDecodingInterceptor::
+    force_mojo_create_data_pipe_failure_for_testing_ = false;
+
 void ContentDecodingInterceptor::Intercept(
     const std::vector<net::SourceStreamType>& types,
     network::mojom::URLLoaderClientEndpointsPtr& endpoints,
@@ -280,7 +284,8 @@
   // side.
   std::move(swap_callback).Run(endpoints, pipe_consumer_handle);
 
-  if (mojo_result != MOJO_RESULT_OK) {
+  if (mojo_result != MOJO_RESULT_OK ||
+      force_mojo_create_data_pipe_failure_for_testing_) {
     mojo::Remote<network::mojom::URLLoaderClient> client(
         std::move(url_loader_client));
     client->OnComplete(
@@ -298,4 +303,10 @@
           std::move(url_loader_receiver), worker_task_runner));
 }
 
+// static
+void ContentDecodingInterceptor::SetForceMojoCreateDataPipeFailureForTesting(
+    bool value) {
+  force_mojo_create_data_pipe_failure_for_testing_ = value;
+}
+
 }  // namespace network
diff --git a/services/network/public/cpp/content_decoding_interceptor.h b/services/network/public/cpp/content_decoding_interceptor.h
index a2810e5c..ba95341 100644
--- a/services/network/public/cpp/content_decoding_interceptor.h
+++ b/services/network/public/cpp/content_decoding_interceptor.h
@@ -65,6 +65,15 @@
           void(network::mojom::URLLoaderClientEndpointsPtr& endpoints,
                mojo::ScopedDataPipeConsumerHandle& body)> swap_callback,
       scoped_refptr<base::SequencedTaskRunner> worker_task_runner);
+
+  // For testing purposes only. If set to true, the creation of the Mojo data
+  // pipe within this class's methods will be forced to fail, simulating an
+  // insufficient resources error (`net::ERR_INSUFFICIENT_RESOURCES`).
+  static void SetForceMojoCreateDataPipeFailureForTesting(bool value);
+
+ private:
+  // Backing flag for the test utility above. Defined in the .cc file.
+  static bool force_mojo_create_data_pipe_failure_for_testing_;
 };
 
 }  // namespace network
diff --git a/services/network/public/cpp/content_decoding_interceptor_unittest.cc b/services/network/public/cpp/content_decoding_interceptor_unittest.cc
index 56bdb72..60597b3 100644
--- a/services/network/public/cpp/content_decoding_interceptor_unittest.cc
+++ b/services/network/public/cpp/content_decoding_interceptor_unittest.cc
@@ -496,4 +496,58 @@
   run_loop.Run();
 }
 
+// Verifies the behavior when the interceptor fails to create its internal Mojo
+// data pipe, simulating a resource exhaustion scenario.
+TEST_F(ContentDecodingInterceptorTest, CreateDataPipeFailure) {
+  ContentDecodingInterceptor::SetForceMojoCreateDataPipeFailureForTesting(true);
+
+  const std::string_view file_name = kBrotliTestFile;
+  const std::vector<net::SourceStreamType> types = {
+      net::SourceStreamType::kBrotli};
+
+  const std::string test_data = ReadTestData(file_name);
+  const std::string expected_data = ReadTestData(kOriginalTestFile);
+
+  mojo::ScopedDataPipeProducerHandle source_producer;
+  mojo::ScopedDataPipeConsumerHandle consumer;
+  CreatePipe(test_data.size(), source_producer, consumer);
+
+  mojo::PendingReceiver<network::mojom::URLLoader> url_loader_receiver;
+  mojo::Remote<network::mojom::URLLoaderClient> url_loader_client_remote;
+  auto endpoints = network::mojom::URLLoaderClientEndpoints::New(
+      url_loader_receiver.InitWithNewPipeAndPassRemote(),
+      url_loader_client_remote.BindNewPipeAndPassReceiver());
+
+  ContentDecodingInterceptor::Intercept(
+      types, endpoints, consumer,
+      base::ThreadPool::CreateSequencedTaskRunner(
+          {base::TaskPriority::USER_BLOCKING}));
+
+  // The data write operation should fail.
+  EXPECT_EQ(source_producer->WriteAllData(base::as_byte_span(test_data)),
+            MOJO_RESULT_FAILED_PRECONDITION);
+  // Finish the data.
+  source_producer.reset();
+
+  // Send OnComplete with OK.
+  url_loader_client_remote->OnComplete(
+      network::URLLoaderCompletionStatus(net::OK));
+
+  base::RunLoop run_loop;
+  testing::NiceMock<network::MockURLLoaderClient> client;
+  EXPECT_CALL(client, OnComplete)
+      .WillOnce([&](::network::URLLoaderCompletionStatus st) {
+        // OnComplete must be caled with ERR_INSUFFICIENT_RESOURCES.
+        EXPECT_EQ(st.error_code, net::ERR_INSUFFICIENT_RESOURCES);
+        EXPECT_EQ(st.decoded_body_length, 0u);
+        run_loop.Quit();
+      });
+  mojo::Receiver<network::mojom::URLLoaderClient> client_receiver(
+      &client, std::move(endpoints->url_loader_client));
+  run_loop.Run();
+
+  ContentDecodingInterceptor::SetForceMojoCreateDataPipeFailureForTesting(
+      false);
+}
+
 }  // namespace network
diff --git a/testing/iossim/iossim.mm b/testing/iossim/iossim.mm
index fab323f4..d243526 100644
--- a/testing/iossim/iossim.mm
+++ b/testing/iossim/iossim.mm
@@ -681,11 +681,18 @@
   }
 
   if (!sdk_version) {
-    float sdk = 0;
+    NSString* highest_sdk = @"0";
+
     for (NSDictionary* runtime in Runtimes(simctl_list, platform_type)) {
-      sdk = fmax(sdk, [runtime[@"version"] floatValue]);
+      NSString* runtime_version = runtime[@"version"];
+      if (!highest_sdk ||
+          [runtime_version compare:highest_sdk
+                           options:NSNumericSearch] == NSOrderedDescending) {
+        highest_sdk = runtime_version;
+      }
     }
-    sdk_version = [NSString stringWithFormat:@"%0.1f", sdk];
+
+    sdk_version = highest_sdk;
   }
 
   NSRange range;
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index ea6adda..aafb67f 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -12630,9 +12630,9 @@
             ],
             "experiments": [
                 {
-                    "name": "BelowOmniboxWithButtons",
+                    "name": "Enabled",
                     "params": {
-                        "tab-group-indicator-below-omnibox": "true",
+                        "tab-group-indicator-below-omnibox": "false",
                         "tab-group-indicator-buttons": "true",
                         "tab-group-indicator-visible": "true"
                     },
@@ -13083,7 +13083,25 @@
             ]
         }
     ],
-    "InvalidationsWithDirectMessagesPerPlatform": [
+    "InvalidationWithDirectMessagesCbcm": [
+        {
+            "platforms": [
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "CbcmPolicyInvalidationWithDirectMessagesEnabled",
+                        "CbcmRemoteCommandsInvalidationWithDirectMessagesEnabled"
+                    ]
+                }
+            ]
+        }
+    ],
+    "InvalidationWithDirectMessagesChromeOs": [
         {
             "platforms": [
                 "chromeos"
@@ -13096,26 +13114,42 @@
                         "DeviceLocalAccountPolicyInvalidationWithDirectMessagesEnabled",
                         "DevicePolicyInvalidationWithDirectMessagesEnabled",
                         "DeviceRemoteCommandsInvalidationWithDirectMessagesEnabled",
-                        "UserCertProvisioningInvalidationWithDirectMessagesEnabled",
-                        "UserPolicyInvalidationWithDirectMessagesEnabled",
-                        "UserRemoteCommandsInvalidationWithDirectMessagesEnabled"
+                        "UserCertProvisioningInvalidationWithDirectMessagesEnabled"
                     ]
                 }
             ]
-        },
+        }
+    ],
+    "InvalidationWithDirectMessagesUserPolicy": [
         {
             "platforms": [
+                "chromeos",
                 "linux",
                 "mac",
                 "windows"
             ],
             "experiments": [
                 {
-                    "name": "BrowserPolicyUserRemoteCommands",
+                    "name": "Enabled",
                     "enable_features": [
-                        "CbcmPolicyInvalidationWithDirectMessagesEnabled",
-                        "CbcmRemoteCommandsInvalidationWithDirectMessagesEnabled",
-                        "UserPolicyInvalidationWithDirectMessagesEnabled",
+                        "UserPolicyInvalidationWithDirectMessagesEnabled"
+                    ]
+                }
+            ]
+        }
+    ],
+    "InvalidationWithDirectMessagesUserRemoteCommands": [
+        {
+            "platforms": [
+                "chromeos",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
                         "UserRemoteCommandsInvalidationWithDirectMessagesEnabled"
                     ]
                 }
@@ -17638,17 +17672,17 @@
             ],
             "experiments": [
                 {
-                    "name": "Enabled_V1",
+                    "name": "EnabledeWithSummarizeSelected",
                     "enable_features": [
                         "MahiPanelResizable",
+                        "MahiSummarizeSelected",
                         "Pompano"
                     ]
                 },
                 {
-                    "name": "Enabled_M136",
+                    "name": "EnabledWithoutSummarizeSelected",
                     "enable_features": [
                         "MahiPanelResizable",
-                        "MahiSummarizeSelected",
                         "Pompano"
                     ]
                 }
diff --git a/third_party/android_deps/autorolled/VERSION.txt b/third_party/android_deps/autorolled/VERSION.txt
index 4b21543..a8c2132 100644
--- a/third_party/android_deps/autorolled/VERSION.txt
+++ b/third_party/android_deps/autorolled/VERSION.txt
@@ -1 +1 @@
-e07745a49a3cfbc
\ No newline at end of file
+8ce8a3dcfcdaa35
\ No newline at end of file
diff --git a/third_party/android_deps/autorolled/bill_of_materials.json b/third_party/android_deps/autorolled/bill_of_materials.json
index 1ca075b..989be716 100644
--- a/third_party/android_deps/autorolled/bill_of_materials.json
+++ b/third_party/android_deps/autorolled/bill_of_materials.json
@@ -387,12 +387,12 @@
     {
         "name": "credentials",
         "group": "androidx.credentials",
-        "version": "1.5.0"
+        "version": "1.6.0-SNAPSHOT"
     },
     {
         "name": "credentials-play-services-auth",
         "group": "androidx.credentials",
-        "version": "1.5.0"
+        "version": "1.6.0-SNAPSHOT"
     },
     {
         "name": "cursoradapter",
diff --git a/third_party/android_deps/autorolled/build.gradle b/third_party/android_deps/autorolled/build.gradle
index 2957096..e243179b 100644
--- a/third_party/android_deps/autorolled/build.gradle
+++ b/third_party/android_deps/autorolled/build.gradle
@@ -91,8 +91,8 @@
 versionCache['androidx.core:core-viewtree'] = '1.1.0-SNAPSHOT'
 versionCache['androidx.credentials.registry:registry-provider'] = '1.0.0-SNAPSHOT'
 versionCache['androidx.credentials.registry:registry-provider-play-services'] = '1.0.0-SNAPSHOT'
-versionCache['androidx.credentials:credentials'] = '1.5.0'
-versionCache['androidx.credentials:credentials-play-services-auth'] = '1.5.0'
+versionCache['androidx.credentials:credentials'] = '1.6.0-SNAPSHOT'
+versionCache['androidx.credentials:credentials-play-services-auth'] = '1.6.0-SNAPSHOT'
 versionCache['androidx.cursoradapter:cursoradapter'] = '1.1.0-SNAPSHOT'
 versionCache['androidx.customview:customview'] = '1.2.0-SNAPSHOT'
 versionCache['androidx.customview:customview-poolingcontainer'] = '1.1.0-SNAPSHOT'
diff --git a/third_party/angle b/third_party/angle
index 7fb1ac4..799d301 160000
--- a/third_party/angle
+++ b/third_party/angle
@@ -1 +1 @@
-Subproject commit 7fb1ac40706f4717fc4f04d1aca207066041ce3c
+Subproject commit 799d301f76944d4bf3a124c4ddf8e5bf19037357
diff --git a/third_party/blink/public/mojom/speculation_rules/speculation_rules.mojom b/third_party/blink/public/mojom/speculation_rules/speculation_rules.mojom
index 08966da..b4ddc10 100644
--- a/third_party/blink/public/mojom/speculation_rules/speculation_rules.mojom
+++ b/third_party/blink/public/mojom/speculation_rules/speculation_rules.mojom
@@ -99,5 +99,13 @@
   // and it is optional as both null and empty are valid values. Null and empty
   // string will be stored as they are into the vector.
   // Explainer: https://github.com/WICG/nav-speculation/blob/main/speculation-rules-tags.md
+  //
+  // Mapping:
+  // - An empty string tag is represented as
+  //   - empty `WTF::String` in blink/
+  //   - empty `std::string` in content/
+  // - No tag (null tag) is represented as
+  //   - null `WTF::String` in blink/
+  //   - nullopt `std::optional<std::string>` in content/
   array<string?> tags;
 };
diff --git a/third_party/blink/public/mojom/webid/digital_identity_request.mojom b/third_party/blink/public/mojom/webid/digital_identity_request.mojom
index 880c4c6..7d12e533 100644
--- a/third_party/blink/public/mojom/webid/digital_identity_request.mojom
+++ b/third_party/blink/public/mojom/webid/digital_identity_request.mojom
@@ -58,7 +58,7 @@
   Get(array<DigitalCredentialRequest> digital_credential_requests, GetRequestFormat format) =>
       (RequestDigitalIdentityStatus status,
       string? protocol,
-      string? token);
+      mojo_base.mojom.Value? token);
 
   // Requests a token to be generated, given a DigitalCredentialRequest.
   // Returns:
@@ -71,7 +71,7 @@
   Create(DigitalCredentialRequest digital_credential_request) =>
       (RequestDigitalIdentityStatus status,
       string? protocol,
-      string? token);
+      mojo_base.mojom.Value? token);
 
   // Aborts the pending request, if any.
   Abort();
diff --git a/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc b/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc
index 452f4f4..9611ba64 100644
--- a/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc
@@ -1313,32 +1313,29 @@
                           const CSSParserContext& context,
                           const CSSParserLocalContext&,
                           HeapVector<CSSPropertyValue, 64>& properties) const {
-  static const double kUnsetValue = -1;
-  double flex_grow = kUnsetValue;
-  double flex_shrink = kUnsetValue;
-  CSSValue* flex_basis = nullptr;
+  const CSSValue* flex_grow = nullptr;
+  const CSSValue* flex_shrink = nullptr;
+  const CSSValue* flex_basis = nullptr;
 
   if (stream.Peek().Id() == CSSValueID::kNone) {
-    flex_grow = 0;
-    flex_shrink = 0;
+    flex_grow =
+        CSSNumericLiteralValue::Create(0, CSSPrimitiveValue::UnitType::kNumber);
+    flex_shrink = flex_grow;
     flex_basis = CSSIdentifierValue::Create(CSSValueID::kAuto);
     stream.ConsumeIncludingWhitespace();
   } else {
     for (;;) {
       CSSParserSavePoint savepoint(stream);
-      double num;
-      if (css_parsing_utils::ConsumeNumberRaw_DO_NOT_USE(stream, context,
-                                                         num)) {
-        if (num < 0) {
-          break;
-        }
-        if (flex_grow == kUnsetValue) {
+      if (const CSSPrimitiveValue* num = css_parsing_utils::ConsumeNumber(
+              stream, context, CSSPrimitiveValue::ValueRange::kNonNegative)) {
+        if (!flex_grow) {
           flex_grow = num;
           savepoint.Release();
-        } else if (flex_shrink == kUnsetValue) {
+        } else if (!flex_shrink) {
           flex_shrink = num;
           savepoint.Release();
-        } else if (!num && !flex_basis) {
+        } else if (!flex_basis && num->IsNumericLiteralValue() &&
+                   num->GetDoubleValue() == 0) {
           // Unitless zero is a valid <'flex-basis'>. All other <length>s
           // must have some unit, and are handled by the other branch.
           flex_basis = CSSNumericLiteralValue::Create(
@@ -1367,10 +1364,11 @@
           // <'flex-basis'> may not appear between <'flex-grow'> and
           // <'flex-shrink'>. We therefore ensure that grow and shrink are
           // either both set, or both unset, once <'flex-basis'> is seen.
-          if (flex_grow != kUnsetValue && flex_shrink == kUnsetValue) {
-            flex_shrink = 1;
+          if (flex_grow && !flex_shrink) {
+            flex_shrink = CSSNumericLiteralValue::Create(
+                1, CSSPrimitiveValue::UnitType::kNumber);
           }
-          DCHECK_EQ(flex_grow == kUnsetValue, flex_shrink == kUnsetValue);
+          DCHECK_EQ(!flex_grow, !flex_shrink);
           savepoint.Release();
         } else {
           break;
@@ -1379,14 +1377,16 @@
         break;
       }
     }
-    if (flex_grow == kUnsetValue && flex_shrink == kUnsetValue && !flex_basis) {
+    if (!flex_grow && !flex_shrink && !flex_basis) {
       return false;
     }
-    if (flex_grow == kUnsetValue) {
-      flex_grow = 1;
+    if (!flex_grow) {
+      flex_grow = CSSNumericLiteralValue::Create(
+          1, CSSPrimitiveValue::UnitType::kNumber);
     }
-    if (flex_shrink == kUnsetValue) {
-      flex_shrink = 1;
+    if (!flex_shrink) {
+      flex_shrink = CSSNumericLiteralValue::Create(
+          1, CSSPrimitiveValue::UnitType::kNumber);
     }
     if (!flex_basis) {
       flex_basis = CSSNumericLiteralValue::Create(
@@ -1395,17 +1395,11 @@
   }
 
   css_parsing_utils::AddProperty(
-      CSSPropertyID::kFlexGrow, CSSPropertyID::kFlex,
-      *CSSNumericLiteralValue::Create(ClampTo<float>(flex_grow),
-                                      CSSPrimitiveValue::UnitType::kNumber),
-      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
-      properties);
+      CSSPropertyID::kFlexGrow, CSSPropertyID::kFlex, *flex_grow, important,
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
   css_parsing_utils::AddProperty(
-      CSSPropertyID::kFlexShrink, CSSPropertyID::kFlex,
-      *CSSNumericLiteralValue::Create(ClampTo<float>(flex_shrink),
-                                      CSSPrimitiveValue::UnitType::kNumber),
-      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
-      properties);
+      CSSPropertyID::kFlexShrink, CSSPropertyID::kFlex, *flex_shrink, important,
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
 
   css_parsing_utils::AddProperty(
       CSSPropertyID::kFlexBasis, CSSPropertyID::kFlex, *flex_basis, important,
diff --git a/third_party/blink/renderer/core/css/resolver/style_adjuster.cc b/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
index 1c33f5ea..9e251098 100644
--- a/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
@@ -162,7 +162,16 @@
   if (!element) {
     return true;
   }
-  const Element* parent = element->ParentOrShadowHostElement();
+  const Element* parent;
+  if (RuntimeEnabledFeatures::RubyFieldsetCrashFixEnabled()) {
+    parent = FlatTreeTraversal::ParentElement(*element);
+    while (parent &&
+           parent->GetComputedStyle()->Display() == EDisplay::kContents) {
+      parent = FlatTreeTraversal::ParentElement(*parent);
+    }
+  } else {
+    parent = element->ParentOrShadowHostElement();
+  }
   return !IsA<HTMLFieldSetElement>(parent) && !IsA<HTMLMediaElement>(parent);
 }
 
diff --git a/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc b/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc
index 3f771b3..d8940d8b0 100644
--- a/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc
+++ b/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc
@@ -325,13 +325,14 @@
 
   // Check that all hashes present in the integrity metadata are allowed
   // by the relevant policy:
-  for (const IntegrityMetadataPair& hash : integrity_metadata.hashes) {
+  for (const IntegrityMetadata& hash : integrity_metadata.hashes) {
     // Convert the hash from integrity metadata format to CSP format.
     network::mojom::blink::CSPHashSourcePtr csp_hash =
         network::mojom::blink::CSPHashSource::New();
-    csp_hash->algorithm = hash.second;
-    if (!ParseBase64Digest(hash.first, csp_hash->value))
+    csp_hash->algorithm = hash.algorithm;
+    if (!ParseBase64Digest(hash.digest, csp_hash->value)) {
       return false;
+    }
     // All integrity hashes must be listed in the CSP.
     if (!CSPSourceListAllowHash(*directive, *csp_hash))
       return false;
@@ -339,12 +340,12 @@
 
   // Now check that all public keys present in the integrity metadata are
   // allowed by the relevant policy:
-  for (const IntegrityMetadataPair& key : integrity_metadata.public_keys) {
+  for (const IntegrityMetadata& key : integrity_metadata.public_keys) {
     // Convert the hash from integrity metadata format to CSP format.
     network::mojom::blink::CSPHashSourcePtr csp_hash =
         network::mojom::blink::CSPHashSource::New();
-    csp_hash->algorithm = key.second;
-    if (!ParseBase64Digest(key.first, csp_hash->value)) {
+    csp_hash->algorithm = key.algorithm;
+    if (!ParseBase64Digest(key.digest, csp_hash->value)) {
       return false;
     }
     // All integrity hashes must be listed in the CSP.
diff --git a/third_party/blink/renderer/core/layout/forms/layout_fieldset_test.cc b/third_party/blink/renderer/core/layout/forms/layout_fieldset_test.cc
index 5b4ae02..f36e78c 100644
--- a/third_party/blink/renderer/core/layout/forms/layout_fieldset_test.cc
+++ b/third_party/blink/renderer/core/layout/forms/layout_fieldset_test.cc
@@ -20,8 +20,7 @@
 </fieldset>)HTML");
   UpdateAllLifecyclePhasesForTest();
 
-  Node* text =
-      GetDocument().QuerySelector(AtomicString("small"))->nextSibling();
+  Node* text = QuerySelector("small")->nextSibling();
   ASSERT_TRUE(IsA<Text>(text));
   text->remove();
   UpdateAllLifecyclePhasesForTest();
diff --git a/third_party/blink/renderer/core/layout/inline/inline_cursor_test.cc b/third_party/blink/renderer/core/layout/inline/inline_cursor_test.cc
index 0c65e1ff..f3da61a 100644
--- a/third_party/blink/renderer/core/layout/inline/inline_cursor_test.cc
+++ b/third_party/blink/renderer/core/layout/inline/inline_cursor_test.cc
@@ -420,8 +420,7 @@
 TEST_F(InlineCursorTest, MoveToEndOfLineWithNoCharsLtr) {
   SetBodyContent(
       "<textarea rows=\"3\" cols=\"50\">foo&#10;&#10;bar</textarea>");
-  const auto& textarea =
-      ToTextControl(*GetDocument().QuerySelector(AtomicString("textarea")));
+  const auto& textarea = ToTextControl(*QuerySelector("textarea"));
   const LayoutObject* textarea_layout =
       textarea.InnerEditorElement()->GetLayoutObject();
   const LayoutBlockFlow& block_flow = *To<LayoutBlockFlow>(textarea_layout);
@@ -442,8 +441,7 @@
   SetBodyContent(
       "<textarea rows=\"3\" cols=\"50\" "
       "dir=\"rtl\">foo&#10;&#10;bar</textarea>");
-  const auto& textarea =
-      ToTextControl(*GetDocument().QuerySelector(AtomicString("textarea")));
+  const auto& textarea = ToTextControl(*QuerySelector("textarea"));
   const LayoutObject* textarea_layout =
       textarea.InnerEditorElement()->GetLayoutObject();
   const LayoutBlockFlow& block_flow = *To<LayoutBlockFlow>(textarea_layout);
diff --git a/third_party/blink/renderer/core/layout/inline/inline_node_test.cc b/third_party/blink/renderer/core/layout/inline/inline_node_test.cc
index 606a71e..496f8e1 100644
--- a/third_party/blink/renderer/core/layout/inline/inline_node_test.cc
+++ b/third_party/blink/renderer/core/layout/inline/inline_node_test.cc
@@ -1288,9 +1288,7 @@
             "<pre id=container>foo<span dir=rtl>\nbar</span></pre>");
   EXPECT_EQ(String(u"foo\u2067\u2069\n\u2067bar\u2069"), GetText());
 
-  GetDocument()
-      .QuerySelector(AtomicString("span"))
-      ->removeAttribute(html_names::kDirAttr);
+  QuerySelector("span")->removeAttribute(html_names::kDirAttr);
   UpdateAllLifecyclePhasesForTest();
 
   // The bidi control characters around '\n' should not preserve
@@ -1302,9 +1300,7 @@
             "<pre id=container>foo<span dir=ltr>\nbar</span></pre>");
   EXPECT_EQ(String(u"foo\u2066\u2069\n\u2066bar\u2069"), GetText());
 
-  GetDocument()
-      .QuerySelector(AtomicString("span"))
-      ->removeAttribute(html_names::kDirAttr);
+  QuerySelector("span")->removeAttribute(html_names::kDirAttr);
   UpdateAllLifecyclePhasesForTest();
 
   // The bidi control characters around '\n' should not preserve
@@ -1329,9 +1325,7 @@
   SetupHtml("t", "<div id=t><span style=white-space:pre><br></span> </div>");
   EXPECT_EQ("\n", GetText());
 
-  GetDocument()
-      .QuerySelector(AtomicString("span"))
-      ->removeAttribute(html_names::kStyleAttr);
+  QuerySelector("span")->removeAttribute(html_names::kStyleAttr);
   UpdateAllLifecyclePhasesForTest();
   EXPECT_EQ("\n", GetText());
 }
@@ -1340,9 +1334,7 @@
   SetupHtml("t", "<div id=t><span style=white-space:pre>\n</span> </div>");
   EXPECT_EQ("\n", GetText());
 
-  GetDocument()
-      .QuerySelector(AtomicString("span"))
-      ->removeAttribute(html_names::kStyleAttr);
+  QuerySelector("span")->removeAttribute(html_names::kStyleAttr);
   UpdateAllLifecyclePhasesForTest();
   EXPECT_EQ("", GetText());
 }
diff --git a/third_party/blink/renderer/core/layout/inline/line_breaker.cc b/third_party/blink/renderer/core/layout/inline/line_breaker.cc
index e1d1cf4..e718720 100644
--- a/third_party/blink/renderer/core/layout/inline/line_breaker.cc
+++ b/third_party/blink/renderer/core/layout/inline/line_breaker.cc
@@ -3445,6 +3445,8 @@
   sub_line_breaker.OverrideAvailableWidth(limit);
   sub_line_breaker.NextLine(&sub_line_info);
   if (disallow_auto_wrap) {
+    // If this check fails, a forced break or a block-in-inline might
+    // appear unexpectedly.
     CHECK(sub_line_breaker.IsAtEnd());
   }
   return sub_line_info;
diff --git a/third_party/blink/renderer/core/layout/layout_inline_test.cc b/third_party/blink/renderer/core/layout/layout_inline_test.cc
index d06ee7e..0da570f8 100644
--- a/third_party/blink/renderer/core/layout/layout_inline_test.cc
+++ b/third_party/blink/renderer/core/layout/layout_inline_test.cc
@@ -204,8 +204,8 @@
   const PhysicalOffset hit_location(18, 15);
   HitTestLocation location(hit_location);
 
-  Element* div = GetDocument().QuerySelector(AtomicString("div"));
-  Element* span = GetDocument().QuerySelector(AtomicString("span"));
+  Element* div = QuerySelector("div");
+  Element* span = QuerySelector("span");
   Node* text = span->firstChild();
 
   // Shouldn't hit anything in SPAN as it's in another paint layer
@@ -299,7 +299,7 @@
   {
     PhysicalOffset hit_location(13, 33);
     HitTestLocation location(hit_location);
-    Node* target = GetDocument().QuerySelector(AtomicString("img"));
+    Node* target = QuerySelector("img");
 
     HitTestResult hit_result(hit_request, location);
     bool hit_outcome =
diff --git a/third_party/blink/renderer/core/layout/layout_multi_column_set_test.cc b/third_party/blink/renderer/core/layout/layout_multi_column_set_test.cc
index f9ba757..ad61b7a7 100644
--- a/third_party/blink/renderer/core/layout/layout_multi_column_set_test.cc
+++ b/third_party/blink/renderer/core/layout/layout_multi_column_set_test.cc
@@ -34,11 +34,11 @@
 <div class=c7><div class=c13></div><map class=c4></map></div>
 <h1 class=c3><button></button></h1>)HTML");
   // Triggers scroll anchoring.
-  GetDocument().QuerySelector(AtomicString("button"))->Focus();
+  QuerySelector("button")->Focus();
   UpdateAllLifecyclePhasesForTest();
 
   // Reattach c13.
-  Element* target = GetDocument().QuerySelector(AtomicString(".c13"));
+  Element* target = QuerySelector(".c13");
   auto* parent = target->parentNode();
   parent->removeChild(target);
   parent->insertBefore(target, parent->firstChild());
diff --git a/third_party/blink/renderer/core/layout/layout_shift_tracker_test.cc b/third_party/blink/renderer/core/layout/layout_shift_tracker_test.cc
index b5c35f52..32bb5e7 100644
--- a/third_party/blink/renderer/core/layout/layout_shift_tracker_test.cc
+++ b/third_party/blink/renderer/core/layout/layout_shift_tracker_test.cc
@@ -94,9 +94,8 @@
               stroke="black" stroke-width="3" fill="red" />
     </svg>
   )HTML");
-  GetDocument()
-      .QuerySelector(AtomicString("circle"))
-      ->setAttribute(svg_names::kCxAttr, AtomicString("100"));
+  QuerySelector("circle")->setAttribute(svg_names::kCxAttr,
+                                        AtomicString("100"));
   UpdateAllLifecyclePhasesForTest();
   EXPECT_FLOAT_EQ(0, GetLayoutShiftTracker().Score());
 }
diff --git a/third_party/blink/renderer/core/layout/layout_text_test.cc b/third_party/blink/renderer/core/layout/layout_text_test.cc
index 25076483..d8ef130 100644
--- a/third_party/blink/renderer/core/layout/layout_text_test.cc
+++ b/third_party/blink/renderer/core/layout/layout_text_test.cc
@@ -1126,7 +1126,7 @@
 TEST_F(LayoutTextTest, WordBreakElement) {
   SetBasicBody("foo <wbr> bar");
 
-  const Element* wbr = GetDocument().QuerySelector(AtomicString("wbr"));
+  const Element* wbr = QuerySelector("wbr");
   DCHECK(wbr->GetLayoutObject()->IsText());
   const auto* layout_wbr = To<LayoutText>(wbr->GetLayoutObject());
 
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 8986db6..52f3944 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
@@ -53,6 +53,12 @@
     const SVGLayoutInfo& layout_info) {
   NOT_DESTROYED();
   DCHECK(NeedsLayout());
+  if (layout_info.viewport_changed && HasViewportDependence() &&
+      IsSVGTransformableContainer()) {
+    // TODO: This will be called if any descendant has a viewport dependency,
+    // not just if this container has one.
+    SetNeedsTransformUpdate();
+  }
 
   SVGTransformChange transform_change = SVGTransformChange::kNone;
   // Update the local transform in subclasses.
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc
index 9cdbae0..5f5a6bc 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc
@@ -330,6 +330,10 @@
 SVGLayoutResult LayoutSVGShape::UpdateSVGLayout(
     const SVGLayoutInfo& layout_info) {
   NOT_DESTROYED();
+  if (layout_info.viewport_changed && HasViewportDependence()) {
+    // TODO: Only invalidate the shape if it depends on the viewport.
+    SetNeedsShapeUpdate();
+  }
 
   // The cached stroke may be affected by the ancestor transform, and so needs
   // to be cleared regardless of whether the shape or bounds have changed.
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
index d2b1ae4..3aa84ac5 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
@@ -217,6 +217,11 @@
 SVGLayoutResult LayoutSVGText::UpdateSVGLayout(
     const SVGLayoutInfo& layout_info) {
   NOT_DESTROYED();
+  // If the screen scaling factor changed we need to update the text
+  // metrics. Ditto for a viewport change (see below).
+  if (layout_info.scale_factor_changed || layout_info.viewport_changed) {
+    SetNeedsTextMetricsUpdate();
+  }
 
   // If the root layout size changed (eg. window size changes), or the screen
   // scale factor has changed, then recompute the on-screen font size. Since
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 46adf3b3..0e05a95 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
@@ -95,6 +95,20 @@
   return bounds;
 }
 
+bool ShouldForceLayoutChild(const SVGLayoutInfo& layout_info,
+                            const LayoutObject& child) {
+  if (layout_info.force_layout) {
+    return true;
+  }
+  if (layout_info.scale_factor_changed) {
+    return true;
+  }
+  if (layout_info.viewport_changed && child.HasViewportDependence()) {
+    return true;
+  }
+  return false;
+}
+
 }  // namespace
 
 // static
@@ -118,32 +132,8 @@
 
   for (LayoutObject* child = children_.FirstChild(); child;
        child = child->NextSibling()) {
-    bool force_child_layout = layout_info.force_layout;
-
-    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 (auto* text = DynamicTo<LayoutSVGText>(child)) {
-        text->SetNeedsTextMetricsUpdate();
-      }
-      force_child_layout = true;
-    }
-
-    if (layout_info.viewport_changed && child->HasViewportDependence()) {
-      if (auto* shape = DynamicTo<LayoutSVGShape>(*child)) {
-        shape->SetNeedsShapeUpdate();
-      } else if (auto* text = DynamicTo<LayoutSVGText>(*child)) {
-        text->SetNeedsTextMetricsUpdate();
-      } else if (auto* container =
-                     DynamicTo<LayoutSVGTransformableContainer>(*child)) {
-        container->SetNeedsTransformUpdate();
-      }
-
-      force_child_layout = true;
-    }
-
     DCHECK(!child->IsSVGRoot());
-    if (force_child_layout) {
+    if (ShouldForceLayoutChild(layout_info, *child)) {
       child->SetNeedsLayout(layout_invalidation_reason::kSvgChanged,
                             kMarkOnlyThis);
     }
diff --git a/third_party/blink/renderer/core/paint/view_painter.cc b/third_party/blink/renderer/core/paint/view_painter.cc
index c735ae0..e78d1a5 100644
--- a/third_party/blink/renderer/core/paint/view_painter.cc
+++ b/third_party/blink/renderer/core/paint/view_painter.cc
@@ -341,6 +341,7 @@
       background_image_offset = PhysicalOffset(paint_rect.origin());
     } else {
       background_image_offset = -root_object->FirstFragment().PaintOffset();
+      background_image_offset += PhysicalOffset(paint_rect.origin());
     }
 
     if (box_fragment_.GetBoxType() == PhysicalFragment::kPageContainer) {
diff --git a/third_party/blink/renderer/modules/credentialmanagement/digital_credential.cc b/third_party/blink/renderer/modules/credentialmanagement/digital_credential.cc
index 738455d..95b1ed6 100644
--- a/third_party/blink/renderer/modules/credentialmanagement/digital_credential.cc
+++ b/third_party/blink/renderer/modules/credentialmanagement/digital_credential.cc
@@ -11,11 +11,11 @@
 }  // anonymous namespace
 
 DigitalCredential* DigitalCredential::Create(const String& protocol,
-                                             const String& data) {
+                                             ScriptObject data) {
   return MakeGarbageCollected<DigitalCredential>(protocol, data);
 }
 
-DigitalCredential::DigitalCredential(const String& protocol, const String& data)
+DigitalCredential::DigitalCredential(const String& protocol, ScriptObject data)
     : Credential(/* id = */ "", kDigitalCredentialType),
       protocol_(protocol),
       data_(data) {}
@@ -24,4 +24,9 @@
   return true;
 }
 
+void DigitalCredential::Trace(Visitor* visitor) const {
+  visitor->Trace(data_);
+  Credential::Trace(visitor);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/credentialmanagement/digital_credential.h b/third_party/blink/renderer/modules/credentialmanagement/digital_credential.h
index e9f5d1a..d762062 100644
--- a/third_party/blink/renderer/modules/credentialmanagement/digital_credential.h
+++ b/third_party/blink/renderer/modules/credentialmanagement/digital_credential.h
@@ -5,6 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_CREDENTIALMANAGEMENT_DIGITAL_CREDENTIAL_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_CREDENTIALMANAGEMENT_DIGITAL_CREDENTIAL_H_
 
+#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
 #include "third_party/blink/renderer/modules/credentialmanagement/credential.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
@@ -15,20 +16,21 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static DigitalCredential* Create(const String& protocol, const String& data);
+  static DigitalCredential* Create(const String& protocol, ScriptObject data);
 
-  explicit DigitalCredential(const String& protocol, const String& data);
+  explicit DigitalCredential(const String& protocol, ScriptObject data);
 
   // Credential:
   bool IsDigitalCredential() const override;
+  void Trace(Visitor* visitor) const override;
 
   // DigitalCredential.idl
   const String& protocol() const { return protocol_; }
-  const String& data() const { return data_; }
+  const ScriptObject& data() const { return data_; }
 
  private:
   const String protocol_;
-  const String data_;
+  ScriptObject data_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/credentialmanagement/digital_credential.idl b/third_party/blink/renderer/modules/credentialmanagement/digital_credential.idl
index b2180a85..3d8d88be 100644
--- a/third_party/blink/renderer/modules/credentialmanagement/digital_credential.idl
+++ b/third_party/blink/renderer/modules/credentialmanagement/digital_credential.idl
@@ -13,5 +13,5 @@
   readonly attribute USVString protocol;
 
   // https://wicg.github.io/digital-identities/#dom-digitalcredential-data
-  [SameObject] readonly attribute USVString data;
+  [SameObject] readonly attribute object data;
 };
diff --git a/third_party/blink/renderer/modules/credentialmanagement/digital_identity_credential.cc b/third_party/blink/renderer/modules/credentialmanagement/digital_identity_credential.cc
index d024d53..cfded9d 100644
--- a/third_party/blink/renderer/modules/credentialmanagement/digital_identity_credential.cc
+++ b/third_party/blink/renderer/modules/credentialmanagement/digital_identity_credential.cc
@@ -18,6 +18,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_union_object_string.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_credential_creation_options.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_credential_request_options.h"
@@ -95,11 +96,30 @@
   return output;
 }
 
+// Converts a base::Value to a ScriptObject.
+// Returns an empty ScriptObject on failure.
+ScriptObject ValueToScriptObject(ScriptState* script_state,
+                                 std::optional<base::Value> response) {
+  if (!response.has_value()) {
+    return ScriptObject();
+  }
+  std::unique_ptr<WebV8ValueConverter> converter =
+      Platform::Current()->CreateWebV8ValueConverter();
+  ScriptState::Scope script_state_scope(script_state);
+  v8::Local<v8::Value> v8_response =
+      converter->ToV8Value(response.value(), script_state->GetContext());
+  if (v8_response.IsEmpty() || !v8_response->IsObject()) {
+    // Parsed value is not an object.
+    return ScriptObject();
+  }
+  return ScriptObject(script_state->GetIsolate(), v8_response);
+}
+
 void OnCompleteRequest(ScriptPromiseResolver<IDLNullable<Credential>>* resolver,
                        std::unique_ptr<ScopedAbortState> scoped_abort_state,
                        RequestDigitalIdentityStatus status,
                        const WTF::String& protocol,
-                       const WTF::String& token) {
+                       std::optional<base::Value> token) {
   switch (status) {
     case RequestDigitalIdentityStatus::kErrorTooManyRequests: {
       resolver->Reject(MakeGarbageCollected<DOMException>(
@@ -146,8 +166,9 @@
       UseCounter::Count(resolver->GetExecutionContext(),
                         WebFeature::kIdentityDigitalCredentialsSuccess);
 
-      DigitalCredential* credential =
-          DigitalCredential::Create(protocol, token);
+      DigitalCredential* credential = DigitalCredential::Create(
+          protocol,
+          ValueToScriptObject(resolver->GetScriptState(), std::move(token)));
       resolver->Resolve(credential);
       return;
     }
diff --git a/third_party/blink/renderer/modules/credentialmanagement/digital_identity_credential_test.cc b/third_party/blink/renderer/modules/credentialmanagement/digital_identity_credential_test.cc
index b56f473..bec9c15 100644
--- a/third_party/blink/renderer/modules/credentialmanagement/digital_identity_credential_test.cc
+++ b/third_party/blink/renderer/modules/credentialmanagement/digital_identity_credential_test.cc
@@ -72,8 +72,10 @@
 
   void Create(blink::mojom::DigitalCredentialRequestPtr request,
               CreateCallback callback) override {
+    // Return a Value::String instead of a Dict because V8ValueConverterForTest
+    // doesn't support converting Dict.
     std::move(callback).Run(mojom::RequestDigitalIdentityStatus::kSuccess,
-                            "protocol", "token");
+                            "protocol", base::Value("token"));
   }
 
   void Abort() override {}
@@ -162,9 +164,11 @@
     ON_CALL(mock_request_, Get)
         .WillByDefault(
             WithArg<2>([](mojom::DigitalIdentityRequest::GetCallback callback) {
+              // Return a Value::String instead of a Dict because
+              // V8ValueConverterForTest doesn't support converting Dict.
               std::move(callback).Run(
                   mojom::RequestDigitalIdentityStatus::kSuccess, "protocol",
-                  "token");
+                  base::Value("token"));
             }));
   }
 
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc
index 47834d8..b600d5c 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc
@@ -172,17 +172,17 @@
     return SnapshotInternal(swap_texture_->GetHandle(), swap_buffers_->Size());
   }
 
-  // If there is no current texture, we need to get the information of the last
-  // texture reserved, that contains the last mailbox, create a new texture for
-  // it, and use it to create the resource provider.
-  auto mailbox_texture = swap_buffers_->GetLastWebGPUMailboxTexture();
-  if (!mailbox_texture) {
+  // If there is no current texture, return a snapshot of the front buffer if
+  // possible.
+  auto front_buffer_texture = GetFrontBufferMailboxTexture();
+  if (!front_buffer_texture) {
     return nullptr;
   }
 
-  return SnapshotInternal(mailbox_texture->GetTexture(),
-                          gfx::Size(mailbox_texture->GetTexture().GetWidth(),
-                                    mailbox_texture->GetTexture().GetHeight()));
+  return SnapshotInternal(
+      front_buffer_texture->GetTexture(),
+      gfx::Size(front_buffer_texture->GetTexture().GetWidth(),
+                front_buffer_texture->GetTexture().GetHeight()));
 }
 
 bool GPUCanvasContext::PaintRenderingResultsToCanvas(
@@ -213,27 +213,11 @@
     // on Linux backings and enable the below codepath.
     return false;
 #else
-    auto front_buffer_si = swap_buffers_->GetFrontBufferSharedImage();
-    if (!front_buffer_si) {
+    // Create a WebGPU texture backed by the front buffer's SharedImage.
+    front_buffer_texture = GetFrontBufferMailboxTexture();
+    if (!front_buffer_texture) {
       return false;
     }
-    wgpu::TextureUsage front_buffer_usage =
-        wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding;
-    wgpu::DawnTextureInternalUsageDescriptor front_buffer_usage_desc = {{
-        .internalUsage = front_buffer_usage,
-    }};
-    wgpu::TextureDescriptor desc = {
-        .size = {base::checked_cast<uint32_t>(front_buffer_si->size().width()),
-                 base::checked_cast<uint32_t>(
-                     front_buffer_si->size().height())},
-        .format = swap_buffers_->TextureFormat(),
-    };
-    desc.nextInChain = &front_buffer_usage_desc;
-
-    // Create a WebGPU texture backed by the front buffer's SharedImage.
-    front_buffer_texture = WebGPUMailboxTexture::FromExistingSharedImage(
-        device_->GetDawnControlClient(), device_->GetHandle(), desc,
-        front_buffer_si, swap_buffers_->GetFrontBufferSyncToken());
 
     texture = front_buffer_texture->GetTexture();
 #endif
@@ -721,6 +705,29 @@
   return texture_.Get();
 }
 
+scoped_refptr<WebGPUMailboxTexture>
+GPUCanvasContext::GetFrontBufferMailboxTexture() {
+  auto front_buffer_si = swap_buffers_->GetFrontBufferSharedImage();
+  if (!front_buffer_si) {
+    return nullptr;
+  }
+  wgpu::TextureUsage front_buffer_usage =
+      wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding;
+  wgpu::DawnTextureInternalUsageDescriptor front_buffer_usage_desc = {{
+      .internalUsage = front_buffer_usage,
+  }};
+  wgpu::TextureDescriptor desc = {
+      .size = {base::checked_cast<uint32_t>(front_buffer_si->size().width()),
+               base::checked_cast<uint32_t>(front_buffer_si->size().height())},
+      .format = swap_buffers_->TextureFormat(),
+  };
+  desc.nextInChain = &front_buffer_usage_desc;
+
+  return WebGPUMailboxTexture::FromExistingSharedImage(
+      device_->GetDawnControlClient(), device_->GetHandle(), desc,
+      front_buffer_si, swap_buffers_->GetFrontBufferSyncToken());
+}
+
 void GPUCanvasContext::ReplaceDrawingBuffer(bool destroy_swap_buffers) {
   if (swap_texture_) {
     DCHECK(swap_buffers_);
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.h b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.h
index 2b22cdb..8b3f4a6bc 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.h
+++ b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.h
@@ -113,6 +113,7 @@
   void SetNeedsCompositingUpdate() override;
 
  private:
+  scoped_refptr<WebGPUMailboxTexture> GetFrontBufferMailboxTexture();
   void DetachSwapBuffers();
   void ReplaceDrawingBuffer(bool destroy_swap_buffers);
   void InitializeAlphaModePipeline(wgpu::TextureFormat format);
diff --git a/third_party/blink/renderer/platform/geometry/layout_point.h b/third_party/blink/renderer/platform/geometry/layout_point.h
index 2d36e5f38..826ed141 100644
--- a/third_party/blink/renderer/platform/geometry/layout_point.h
+++ b/third_party/blink/renderer/platform/geometry/layout_point.h
@@ -58,6 +58,8 @@
   // instead.
   LayoutPoint(double, double) = delete;
 
+  bool operator==(const LayoutPoint&) const = default;
+
   constexpr LayoutUnit X() const { return x_; }
   constexpr LayoutUnit Y() const { return y_; }
 
@@ -67,15 +69,6 @@
   LayoutUnit x_, y_;
 };
 
-ALWAYS_INLINE constexpr bool operator==(const LayoutPoint& a,
-                                        const LayoutPoint& b) {
-  return a.X() == b.X() && a.Y() == b.Y();
-}
-
-constexpr bool operator!=(const LayoutPoint& a, const LayoutPoint& b) {
-  return !(a == b);
-}
-
 PLATFORM_EXPORT std::ostream& operator<<(std::ostream&, const LayoutPoint&);
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
index 18e61fc..9fa19d6 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
@@ -781,6 +781,13 @@
     }
   }
 
+  void SetResourceRecyclingEnabled(bool value) override {
+    resource_recycling_enabled_ = value;
+    if (!resource_recycling_enabled_) {
+      ClearRecycledResources();
+    }
+  }
+
   void RecycleResource(scoped_refptr<CanvasResource>&& resource) {
     // We don't want to keep an arbitrary large number of canvases.
     if (canvas_resources_.size() >
@@ -877,7 +884,7 @@
     resource()->OnMemoryDump(pmd, path);
 
     std::string cached_path = path + "/cached";
-    for (const auto& canvas_resource : CanvasResources()) {
+    for (const auto& canvas_resource : canvas_resources_) {
       auto* resource_pointer = static_cast<CanvasResourceSharedImage*>(
           canvas_resource.resource.get());
       // In single buffered mode, `resource_` is not removed from
@@ -893,6 +900,7 @@
   // recycling.
   static constexpr int kMaxRecycledCanvasResources = 3;
 
+  bool resource_recycling_enabled_ = true;
   base::WeakPtr<WebGraphicsSharedImageInterfaceProvider>
       shared_image_interface_provider_;
   const bool is_accelerated_;
@@ -1951,12 +1959,6 @@
   return &Image::SharedCCDecodeCache(kRGBA_F16_SkColorType);
 }
 
-void CanvasResourceProvider::SetResourceRecyclingEnabled(bool value) {
-  resource_recycling_enabled_ = value;
-  if (!resource_recycling_enabled_)
-    ClearRecycledResources();
-}
-
 void CanvasResourceProvider::ClearRecycledResources() {
   canvas_resources_.clear();
 }
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
index cf2e81a..9bf780a4 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
@@ -215,9 +215,12 @@
     NOTREACHED();
   }
 
+  // CanvasResourceProviderSharedImage overrides these methods as part of
+  // implementing resource recycling.
   virtual void OnResourceReturnedFromCompositor(
       scoped_refptr<CanvasResource>&&) {}
-  void SetResourceRecyclingEnabled(bool);
+  virtual void SetResourceRecyclingEnabled(bool) {}
+
   void ClearRecycledResources();
 
   SkSurface* GetSkSurface() const;
@@ -420,7 +423,6 @@
   WTF::Vector<UnusedResource> canvas_resources_;
   int num_inflight_resources_ = 0;
   int max_inflight_resources_ = 0;
-  bool resource_recycling_enabled_ = true;
   base::OneShotTimer unused_resources_reclaim_timer_;
 
  private:
diff --git a/third_party/blink/renderer/platform/loader/fetch/integrity_metadata.cc b/third_party/blink/renderer/platform/loader/fetch/integrity_metadata.cc
index 67e9b88d..83a3fc9c 100644
--- a/third_party/blink/renderer/platform/loader/fetch/integrity_metadata.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/integrity_metadata.cc
@@ -6,19 +6,19 @@
 
 namespace blink {
 
-void IntegrityMetadataSet::Insert(const IntegrityMetadataPair& pair) {
-  switch (pair.second) {
+void IntegrityMetadataSet::Insert(IntegrityMetadata item) {
+  switch (item.algorithm) {
     case IntegrityAlgorithm::kSha256:
     case IntegrityAlgorithm::kSha384:
     case IntegrityAlgorithm::kSha512:
-      if (!hashes.Contains(pair)) {
-        hashes.push_back(std::move(pair));
+      if (!hashes.Contains(item)) {
+        hashes.push_back(std::move(item));
       }
       break;
 
     case IntegrityAlgorithm::kEd25519:
-      if (!public_keys.Contains(pair)) {
-        public_keys.push_back(std::move(pair));
+      if (!public_keys.Contains(item)) {
+        public_keys.push_back(std::move(item));
       }
       break;
   }
@@ -26,13 +26,6 @@
 
 IntegrityMetadata::IntegrityMetadata(WTF::String digest,
                                      IntegrityAlgorithm algorithm)
-    : digest_(digest), algorithm_(algorithm) {}
-
-IntegrityMetadata::IntegrityMetadata(IntegrityMetadataPair pair)
-    : digest_(pair.first), algorithm_(pair.second) {}
-
-IntegrityMetadataPair IntegrityMetadata::ToPair() const {
-  return IntegrityMetadataPair(digest_, algorithm_);
-}
+    : digest(std::move(digest)), algorithm(algorithm) {}
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/loader/fetch/integrity_metadata.h b/third_party/blink/renderer/platform/loader/fetch/integrity_metadata.h
index 569087b..45d9cef 100644
--- a/third_party/blink/renderer/platform/loader/fetch/integrity_metadata.h
+++ b/third_party/blink/renderer/platform/loader/fetch/integrity_metadata.h
@@ -16,10 +16,19 @@
 
 namespace blink {
 
-class IntegrityMetadata;
-
 using IntegrityAlgorithm = network::mojom::blink::IntegrityAlgorithm;
-using IntegrityMetadataPair = std::pair<String, IntegrityAlgorithm>;
+
+struct PLATFORM_EXPORT IntegrityMetadata {
+  IntegrityMetadata() = default;
+  IntegrityMetadata(String digest, IntegrityAlgorithm);
+
+  bool operator==(const IntegrityMetadata& other) const {
+    return this->digest == other.digest && this->algorithm == other.algorithm;
+  }
+
+  String digest;
+  IntegrityAlgorithm algorithm;
+};
 
 // Contains the result of SRI's "Parse Metadata" algorithm:
 //
@@ -27,10 +36,10 @@
 struct PLATFORM_EXPORT IntegrityMetadataSet {
   IntegrityMetadataSet() = default;
   bool empty() const { return hashes.empty() && public_keys.empty(); }
-  WTF::Vector<IntegrityMetadataPair> hashes;
-  WTF::Vector<IntegrityMetadataPair> public_keys;
+  WTF::Vector<IntegrityMetadata> hashes;
+  WTF::Vector<IntegrityMetadata> public_keys;
 
-  void Insert(const IntegrityMetadataPair& pair);
+  void Insert(IntegrityMetadata pair);
 
   bool operator==(const IntegrityMetadataSet& other) const {
     return this->hashes == other.hashes &&
@@ -38,26 +47,6 @@
   }
 };
 
-class PLATFORM_EXPORT IntegrityMetadata {
-  STACK_ALLOCATED();
-
- public:
-  IntegrityMetadata() = default;
-  IntegrityMetadata(String digest, IntegrityAlgorithm);
-  IntegrityMetadata(IntegrityMetadataPair);
-
-  String Digest() const { return digest_; }
-  void SetDigest(const String& digest) { digest_ = digest; }
-  IntegrityAlgorithm Algorithm() const { return algorithm_; }
-  void SetAlgorithm(IntegrityAlgorithm algorithm) { algorithm_ = algorithm; }
-
-  IntegrityMetadataPair ToPair() const;
-
- private:
-  String digest_;
-  IntegrityAlgorithm algorithm_;
-};
-
 enum class ResourceIntegrityDisposition : uint8_t {
   kNotChecked = 0,
   kNetworkError,
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_request.cc b/third_party/blink/renderer/platform/loader/fetch/resource_request.cc
index aea66cb..8b005bd2 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_request.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_request.cc
@@ -471,7 +471,7 @@
 void ResourceRequestHead::SetExpectedPublicKeys(
     const IntegrityMetadataSet& metadata) {
   for (const auto& public_key : metadata.public_keys) {
-    expected_public_keys_.push_back(public_key.first);
+    expected_public_keys_.push_back(public_key.digest);
   }
 }
 
diff --git a/third_party/blink/renderer/platform/loader/subresource_integrity.cc b/third_party/blink/renderer/platform/loader/subresource_integrity.cc
index 260d828..4537a4a 100644
--- a/third_party/blink/renderer/platform/loader/subresource_integrity.cc
+++ b/third_party/blink/renderer/platform/loader/subresource_integrity.cc
@@ -230,7 +230,7 @@
 }
 
 bool SubresourceIntegrity::CheckHashesImpl(
-    const WTF::Vector<IntegrityMetadataPair>& hashes,
+    const WTF::Vector<IntegrityMetadata>& hashes,
     const SegmentedBuffer* buffer,
     const KURL& resource_url,
     const FeatureContext* feature_context,
@@ -268,13 +268,13 @@
   // Then we loop through the asserted hashes, ignoring any that don't use
   // the strongest algorithm asserted:
   for (const IntegrityMetadata& metadata : hashes) {
-    if (metadata.Algorithm() != strongest_algorithm) {
+    if (metadata.algorithm != strongest_algorithm) {
       continue;
     }
 
     // And finally decode the metadata's digest for comparison.
     Vector<char> decoded_metadata;
-    Base64Decode(metadata.Digest(), decoded_metadata);
+    Base64Decode(metadata.digest, decoded_metadata);
     DigestValue expected_value;
     expected_value.AppendSpan(base::as_byte_span(decoded_metadata));
 
@@ -311,14 +311,14 @@
 }
 
 bool SubresourceIntegrity::CheckSignaturesImpl(
-    const WTF::Vector<IntegrityMetadataPair>& integrity_pairs,
+    const WTF::Vector<IntegrityMetadata>& integrity_list,
     const KURL& resource_url,
     const String& raw_headers,
     IntegrityReport& integrity_report) {
   // This implements steps 6 and 8.3 of
   // https://wicg.github.io/signature-based-sri/#matching.
   //
-  if (integrity_pairs.empty()) {
+  if (integrity_list.empty()) {
     return true;
   }
 
@@ -344,7 +344,7 @@
 
   // This would be caught below, but we'll exit early for unsigned resources
   // so we can provide a better error message in the console.
-  if (signatures.empty() && !integrity_pairs.empty()) {
+  if (signatures.empty() && !integrity_list.empty()) {
     integrity_report.AddConsoleErrorMessage(
         "Subresource Integrity: The resource at `" +
         resource_url.ElidedString() +
@@ -353,8 +353,8 @@
     return false;
   }
 
-  for (const IntegrityMetadata& metadata : integrity_pairs) {
-    String public_key = metadata.Digest();
+  for (const IntegrityMetadata& metadata : integrity_list) {
+    String public_key = metadata.digest;
     for (const auto& signature : signatures) {
       if (signature->keyid == public_key) {
         return true;
@@ -370,7 +370,7 @@
 }
 
 IntegrityAlgorithm SubresourceIntegrity::FindBestAlgorithm(
-    const WTF::Vector<IntegrityMetadataPair>& metadata_pairs) {
+    const WTF::Vector<IntegrityMetadata>& metadata_list) {
   // Find the "strongest" algorithm in the set. (This relies on
   // IntegrityAlgorithm declaration order matching the "strongest" order, so
   // make the compiler check this assumption first.)
@@ -380,12 +380,13 @@
                 "of the integrity algorithms.");
 
   // metadata_set is non-empty, so we are guaranteed to always have a result.
-  DCHECK(!metadata_pairs.empty());
+  DCHECK(!metadata_list.empty());
   return std::max_element(
-             metadata_pairs.begin(), metadata_pairs.end(),
-             [](const IntegrityMetadataPair& a,
-                const IntegrityMetadataPair& b) { return a.second < b.second; })
-      ->second;
+             metadata_list.begin(), metadata_list.end(),
+             [](const IntegrityMetadata& a, const IntegrityMetadata& b) {
+               return a.algorithm < b.algorithm;
+             })
+      ->algorithm;
 }
 
 SubresourceIntegrity::AlgorithmParseResult
@@ -529,7 +530,7 @@
       }
     }
 
-    IntegrityMetadata integrity_metadata(digest, algorithm);
+    IntegrityMetadata integrity_metadata(std::move(digest), algorithm);
     if (integrity_report) {
       if (IsHashingAlgorithm(algorithm)) {
         integrity_report->AddUseCount(WebFeature::kSRIHashAssertion);
@@ -537,7 +538,7 @@
         integrity_report->AddUseCount(WebFeature::kSRIPublicKeyAssertion);
       }
     }
-    metadata_set.Insert(std::move(integrity_metadata.ToPair()));
+    metadata_set.Insert(std::move(integrity_metadata));
   }
 }
 
@@ -588,7 +589,7 @@
 
     for (const auto& key : integrity_metadata.public_keys) {
       Vector<char> decoded_key;
-      if (!Base64Decode(key.first, decoded_key) || decoded_key.size() != 32u) {
+      if (!Base64Decode(key.digest, decoded_key) || decoded_key.size() != 32u) {
         // TODO(391907163): Log an error for invalid public key digests.
         continue;
       }
diff --git a/third_party/blink/renderer/platform/loader/subresource_integrity.h b/third_party/blink/renderer/platform/loader/subresource_integrity.h
index 98c7b2a..d4f69e4 100644
--- a/third_party/blink/renderer/platform/loader/subresource_integrity.h
+++ b/third_party/blink/renderer/platform/loader/subresource_integrity.h
@@ -101,7 +101,7 @@
       HashMap<HashAlgorithm, String>* computed_hashes);
 
   // Handles hash validation during SRI checks.
-  static bool CheckHashesImpl(const WTF::Vector<IntegrityMetadataPair>&,
+  static bool CheckHashesImpl(const WTF::Vector<IntegrityMetadata>&,
                               const SegmentedBuffer*,
                               const KURL&,
                               const FeatureContext*,
@@ -109,7 +109,7 @@
                               HashMap<HashAlgorithm, String>* computed_hashes);
 
   // Handles signature-based matching during SRI checks
-  static bool CheckSignaturesImpl(const WTF::Vector<IntegrityMetadataPair>&,
+  static bool CheckSignaturesImpl(const WTF::Vector<IntegrityMetadata>&,
                                   const KURL& resource_url,
                                   const String& raw_headers,
                                   IntegrityReport&);
@@ -118,7 +118,7 @@
   using AlgorithmParseResult = base::expected<size_t, AlgorithmParseError>;
 
   static IntegrityAlgorithm FindBestAlgorithm(
-      const WTF::Vector<IntegrityMetadataPair>&);
+      const WTF::Vector<IntegrityMetadata>&);
 
   static bool CheckSubresourceIntegrityDigest(const IntegrityMetadata&,
                                               const SegmentedBuffer* buffer);
diff --git a/third_party/blink/renderer/platform/loader/subresource_integrity_test.cc b/third_party/blink/renderer/platform/loader/subresource_integrity_test.cc
index 05f35a1..5896cbd 100644
--- a/third_party/blink/renderer/platform/loader/subresource_integrity_test.cc
+++ b/third_party/blink/renderer/platform/loader/subresource_integrity_test.cc
@@ -72,12 +72,12 @@
 constexpr char kUnsupportedHashFunctionIntegrity[] =
     "sha1-JfLW308qMPKfb4DaHpUBEESwuPc=";
 
-auto CompareIntegrityMetadataPair = [](const IntegrityMetadataPair& a,
-                                       const IntegrityMetadataPair& b) {
-  if (a.first != b.first) {
-    return WTF::CodeUnitCompareLessThan(a.first, b.first);
+auto CompareIntegrityMetadata = [](const IntegrityMetadata& a,
+                                   const IntegrityMetadata& b) {
+  if (a.digest != b.digest) {
+    return WTF::CodeUnitCompareLessThan(a.digest, b.digest);
   }
-  return a.second < b.second;
+  return a.algorithm < b.algorithm;
 };
 
 }  // namespace
@@ -155,8 +155,8 @@
     EXPECT_EQ(1u, metadata_set.hashes.size());
     if (metadata_set.hashes.size() > 0) {
       IntegrityMetadata metadata = *metadata_set.hashes.begin();
-      EXPECT_EQ(expected_digest, metadata.Digest());
-      EXPECT_EQ(expected_algorithm, metadata.Algorithm());
+      EXPECT_EQ(expected_digest, metadata.digest);
+      EXPECT_EQ(expected_algorithm, metadata.algorithm);
     }
   }
 
@@ -165,7 +165,7 @@
       base::span<const IntegrityMetadata> expected_metadata) {
     IntegrityMetadataSet expected_metadata_set;
     for (const auto& expected : expected_metadata) {
-      expected_metadata_set.Insert(std::move(expected.ToPair()));
+      expected_metadata_set.Insert(std::move(expected));
     }
     IntegrityMetadataSet metadata_set;
     SubresourceIntegrity::ParseIntegrityAttribute(
@@ -580,7 +580,7 @@
       IntegrityAlgorithm::kEd25519,
   };
 
-  WTF::Vector<IntegrityMetadataPair> alg_set;
+  WTF::Vector<IntegrityMetadata> alg_set;
   for (IntegrityAlgorithm alg : algs) {
     SCOPED_TRACE(alg);
 
@@ -589,7 +589,7 @@
 
     // Check that each algorithm in the test cases is stronger than the
     // previously-tested algorithms.
-    alg_set.push_back(std::make_pair("", alg));
+    alg_set.push_back(IntegrityMetadata("", alg));
     EXPECT_EQ(alg, SubresourceIntegrity::FindBestAlgorithm(alg_set));
   }
 }
@@ -639,8 +639,8 @@
       ASSERT_EQ(1u, metadata_set.public_keys.size());
 
       IntegrityMetadata metadata = *metadata_set.public_keys.begin();
-      EXPECT_EQ(digest, metadata.Digest());
-      EXPECT_EQ(IntegrityAlgorithm::kEd25519, metadata.Algorithm());
+      EXPECT_EQ(digest, metadata.digest);
+      EXPECT_EQ(IntegrityAlgorithm::kEd25519, metadata.algorithm);
     } else {
       ASSERT_EQ(0u, metadata_set.public_keys.size());
     }
@@ -649,8 +649,8 @@
   // Evalutes whether the given string is parsed into a set of IntegrityMetadata
   // items that contains each of the items in |hashes| and |public_keys|.
   void ValidateMultipleItems(const String& integrity_attribute,
-                             const Vector<IntegrityMetadataPair>& hashes,
-                             const Vector<IntegrityMetadataPair>& public_keys) {
+                             const Vector<IntegrityMetadata>& hashes,
+                             const Vector<IntegrityMetadata>& public_keys) {
     IntegrityMetadataSet metadata_set;
     SubresourceIntegrity::ParseIntegrityAttribute(
         integrity_attribute, metadata_set, /*feature_context=*/nullptr);
@@ -729,20 +729,20 @@
 }
 
 TEST_P(SubresourceIntegritySignatureTest, ParseMultipleSignatures) {
-  Vector<IntegrityMetadataPair> signature_pairs = {
-      std::make_pair("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
-                     IntegrityAlgorithm::kEd25519),
-      std::make_pair("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=",
-                     IntegrityAlgorithm::kEd25519),
-      std::make_pair("CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC=",
-                     IntegrityAlgorithm::kEd25519),
+  Vector<IntegrityMetadata> signature_pairs = {
+      IntegrityMetadata("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
+                        IntegrityAlgorithm::kEd25519),
+      IntegrityMetadata("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=",
+                        IntegrityAlgorithm::kEd25519),
+      IntegrityMetadata("CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC=",
+                        IntegrityAlgorithm::kEd25519),
   };
 
   do {
     StringBuilder attribute;
     for (const auto& pair : signature_pairs) {
-      attribute.Append(AlgorithmToPrefix(pair.second));
-      attribute.Append(pair.first);
+      attribute.Append(AlgorithmToPrefix(pair.algorithm));
+      attribute.Append(pair.digest);
       attribute.Append(' ');
     }
     SCOPED_TRACE(attribute.ToString());
@@ -757,40 +757,41 @@
     ValidateMultipleItems(attribute.ToString() + " ed25519-???", {},
                           signature_pairs);
   } while (std::next_permutation(signature_pairs.begin(), signature_pairs.end(),
-                                 CompareIntegrityMetadataPair));
+                                 CompareIntegrityMetadata));
 }
 
 TEST_P(SubresourceIntegritySignatureTest, ParseBoth) {
-  Vector<IntegrityMetadataPair> hash_pairs = {
+  Vector<IntegrityMetadata> hash_pairs = {
       // "Hello, world."
-      std::make_pair("+MO/YqmqPm/BYZwlDkir51GTc9Pt9BvmLrXcRRma8u8=",
-                     IntegrityAlgorithm::kSha256),
-      std::make_pair(
+      IntegrityMetadata("+MO/YqmqPm/BYZwlDkir51GTc9Pt9BvmLrXcRRma8u8=",
+                        IntegrityAlgorithm::kSha256),
+      IntegrityMetadata(
           "S7LmUoguRQsq3IHIZ0Xhm5jjCDqH6uUQbumuj5CnrIFDk+RyBW/dWuqzEiV4mPaB",
           IntegrityAlgorithm::kSha384),
-      std::make_pair("rQw3wx1psxXzqB8TyM3nAQlK2RcluhsNwxmcqXE2YbgoDW735o8TPmIR4"
-                     "uWpoxUERddvFwjgRSGw7gNPCwuvJg==",
-                     IntegrityAlgorithm::kSha512),
+      IntegrityMetadata(
+          "rQw3wx1psxXzqB8TyM3nAQlK2RcluhsNwxmcqXE2YbgoDW735o8TPmIR4"
+          "uWpoxUERddvFwjgRSGw7gNPCwuvJg==",
+          IntegrityAlgorithm::kSha512),
   };
-  Vector<IntegrityMetadataPair> signature_pairs = {
-      std::make_pair("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
-                     IntegrityAlgorithm::kEd25519),
-      std::make_pair("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=",
-                     IntegrityAlgorithm::kEd25519),
-      std::make_pair("CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC=",
-                     IntegrityAlgorithm::kEd25519),
+  Vector<IntegrityMetadata> signature_pairs = {
+      IntegrityMetadata("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
+                        IntegrityAlgorithm::kEd25519),
+      IntegrityMetadata("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=",
+                        IntegrityAlgorithm::kEd25519),
+      IntegrityMetadata("CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC=",
+                        IntegrityAlgorithm::kEd25519),
   };
 
   do {
     StringBuilder attribute;
     for (const auto& pair : signature_pairs) {
-      attribute.Append(AlgorithmToPrefix(pair.second));
-      attribute.Append(pair.first);
+      attribute.Append(AlgorithmToPrefix(pair.algorithm));
+      attribute.Append(pair.digest);
       attribute.Append(' ');
     }
     for (const auto& pair : hash_pairs) {
-      attribute.Append(AlgorithmToPrefix(pair.second));
-      attribute.Append(pair.first);
+      attribute.Append(AlgorithmToPrefix(pair.algorithm));
+      attribute.Append(pair.digest);
       attribute.Append(' ');
     }
     SCOPED_TRACE(attribute.ToString());
@@ -805,7 +806,7 @@
     ValidateMultipleItems(attribute.ToString() + " ed25519-???", hash_pairs,
                           signature_pairs);
   } while (std::next_permutation(signature_pairs.begin(), signature_pairs.end(),
-                                 CompareIntegrityMetadataPair));
+                                 CompareIntegrityMetadata));
 }
 
 TEST_P(SubresourceIntegritySignatureTest, CheckEmpty) {
@@ -830,7 +831,7 @@
 TEST_P(SubresourceIntegritySignatureTest, CheckNotSigned) {
   IntegrityReport integrity_report;
   IntegrityMetadataSet metadata_set;
-  metadata_set.Insert(std::make_pair("", IntegrityAlgorithm::kEd25519));
+  metadata_set.Insert(IntegrityMetadata("", IntegrityAlgorithm::kEd25519));
   String raw_headers = "";
 
   // If the flag is set, the lack of a signature will fail any signature
@@ -876,7 +877,7 @@
   IntegrityReport integrity_report;
   IntegrityMetadataSet metadata_set;
   metadata_set.public_keys = {
-      std::make_pair(kPublicKey, IntegrityAlgorithm::kEd25519)};
+      IntegrityMetadata(kPublicKey, IntegrityAlgorithm::kEd25519)};
 
   // Valid signature matching the integrity requirement should always pass.
   EXPECT_TRUE(SubresourceIntegrity::CheckSubresourceIntegrity(
diff --git a/third_party/blink/renderer/platform/loader/unencoded_digest.cc b/third_party/blink/renderer/platform/loader/unencoded_digest.cc
index 6c1e7bd..bab125bd 100644
--- a/third_party/blink/renderer/platform/loader/unencoded_digest.cc
+++ b/third_party/blink/renderer/platform/loader/unencoded_digest.cc
@@ -65,10 +65,10 @@
     IntegrityMetadata parsed_digest;
     size_t expected_digest_length = 0;
     if (entry.first == kSHA256Token) {
-      parsed_digest.SetAlgorithm(IntegrityAlgorithm::kSha256);
+      parsed_digest.algorithm = IntegrityAlgorithm::kSha256;
       expected_digest_length = 32;
     } else if (entry.first == kSHA512Token) {
-      parsed_digest.SetAlgorithm(IntegrityAlgorithm::kSha512);
+      parsed_digest.algorithm = IntegrityAlgorithm::kSha512;
       expected_digest_length = 64;
     } else {
       // Skip over entries with unknown algorithm tokens.
@@ -95,8 +95,8 @@
 
     // Store the byte sequence as a base64-encoded digest, matching CSP and
     // SRI's existing `IntegrityMetadata` implementation.
-    parsed_digest.SetDigest(Base64Encode(base::as_byte_span(digest)));
-    integrity_metadata.Insert(std::move(parsed_digest.ToPair()));
+    parsed_digest.digest = Base64Encode(base::as_byte_span(digest));
+    integrity_metadata.Insert(std::move(parsed_digest));
   }
 
   if (integrity_metadata.hashes.empty()) {
@@ -107,7 +107,7 @@
 
 bool UnencodedDigest::DoesMatch(WTF::SegmentedBuffer* data) {
   for (const IntegrityMetadata& digest : integrity_metadata_.hashes) {
-    HashAlgorithm algorithm = GetHashAlgorithm(digest.Algorithm());
+    HashAlgorithm algorithm = GetHashAlgorithm(digest.algorithm);
     DigestValue computed_digest;
     if (!ComputeDigest(algorithm, data, computed_digest)) {
       // TODO(https://crbug.com/381044049): Emit errors.
@@ -116,7 +116,7 @@
 
     // Convert the stored digest into a `DigestValue`
     Vector<char> digest_bytes;
-    Base64Decode(digest.Digest(), digest_bytes);
+    Base64Decode(digest.digest, digest_bytes);
     DigestValue expected_digest(base::as_byte_span(digest_bytes));
 
     // If any specified digest doesn't match the digest computed over |data|,
diff --git a/third_party/blink/renderer/platform/loader/unencoded_digest.h b/third_party/blink/renderer/platform/loader/unencoded_digest.h
index 37bda93..f76e00d 100644
--- a/third_party/blink/renderer/platform/loader/unencoded_digest.h
+++ b/third_party/blink/renderer/platform/loader/unencoded_digest.h
@@ -30,7 +30,7 @@
   // `Unencoded-Digest` header is present, and `std::nullopt` otherwise.
   static std::optional<UnencodedDigest> Create(const HTTPHeaderMap&);
 
-  const WTF::Vector<IntegrityMetadataPair>& digests() const {
+  const WTF::Vector<IntegrityMetadata>& digests() const {
     return integrity_metadata_.hashes;
   }
 
diff --git a/third_party/blink/renderer/platform/loader/unencoded_digest_unittest.cc b/third_party/blink/renderer/platform/loader/unencoded_digest_unittest.cc
index 8d7b1b24..edc376d3 100644
--- a/third_party/blink/renderer/platform/loader/unencoded_digest_unittest.cc
+++ b/third_party/blink/renderer/platform/loader/unencoded_digest_unittest.cc
@@ -173,13 +173,13 @@
     headers.Set(http_names::kUnencodedDigest, AtomicString(test.header));
 
     IntegrityMetadata expected;
-    expected.SetAlgorithm(test.alg);
-    expected.SetDigest(kHelloWorlds.at(test.alg));
+    expected.algorithm = test.alg;
+    expected.digest = kHelloWorlds.at(test.alg);
 
     auto result = UnencodedDigest::Create(headers);
     EXPECT_TRUE(result.has_value());
     EXPECT_EQ(1u, result->digests().size());
-    EXPECT_TRUE(result->digests().Contains(expected.ToPair()));
+    EXPECT_TRUE(result->digests().Contains(expected));
   }
 }
 
@@ -220,9 +220,9 @@
 
     for (const auto& algorithm : test.alg) {
       IntegrityMetadata expected;
-      expected.SetAlgorithm(algorithm);
-      expected.SetDigest(kHelloWorlds.at(algorithm));
-      EXPECT_TRUE(result->digests().Contains(expected.ToPair()));
+      expected.algorithm = algorithm;
+      expected.digest = kHelloWorlds.at(algorithm);
+      EXPECT_TRUE(result->digests().Contains(expected));
     }
   }
 }
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 5a8b551..31f2989 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -3809,6 +3809,11 @@
       status: "stable",
     },
     {
+      // crbug.com/402200344
+      name: "RubyFieldsetCrashFix",
+      status: "stable",
+    },
+    {
       // crbug.com/329776386
       name: "RubyOverhangOverlapFix",
       status: "stable",
@@ -4789,8 +4794,7 @@
       name: "WarnOnContentVisibilityRenderAccess",
     },
     {
-      name: "WebAnimationsSVG",
-      status: "experimental",
+      name: "WebAnimationsSVG"
     },
     {
       name: "WebAppInstallation",
diff --git a/third_party/blink/renderer/platform/testing/testing_platform_support.cc b/third_party/blink/renderer/platform/testing/testing_platform_support.cc
index f5189fd..afdd4c63 100644
--- a/third_party/blink/renderer/platform/testing/testing_platform_support.cc
+++ b/third_party/blink/renderer/platform/testing/testing_platform_support.cc
@@ -139,10 +139,56 @@
   void SetDateAllowed(bool val) override {}
   void SetRegExpAllowed(bool val) override {}
 
-  v8::Local<v8::Value> ToV8Value(base::ValueView,
+  v8::Local<v8::Value> ToV8Value(base::ValueView value,
                                  v8::Local<v8::Context> context) override {
-    NOTREACHED();
+    // The following logic is forked from V8ValueConverterImpl::ToV8Value() to
+    // support converting basic types.
+    struct Visitor {
+      raw_ptr<const V8ValueConverterForTest> converter;
+      raw_ptr<v8::Isolate> isolate;
+      v8::Local<v8::Object> creation_context;
+
+      v8::Local<v8::Value> operator()(std::monostate value) {
+        return v8::Null(isolate);
+      }
+
+      v8::Local<v8::Value> operator()(bool value) {
+        return v8::Boolean::New(isolate, value);
+      }
+
+      v8::Local<v8::Value> operator()(int value) {
+        return v8::Integer::New(isolate, value);
+      }
+
+      v8::Local<v8::Value> operator()(double value) {
+        return v8::Number::New(isolate, value);
+      }
+
+      v8::Local<v8::Value> operator()(std::string_view value) {
+        return v8::String::NewFromUtf8(isolate, value.data(),
+                                       v8::NewStringType::kNormal,
+                                       value.length())
+            .ToLocalChecked();
+      }
+
+      v8::Local<v8::Value> operator()(const base::Value::BlobStorage& value) {
+        NOTREACHED();
+      }
+
+      v8::Local<v8::Value> operator()(const base::Value::Dict& value) {
+        NOTREACHED();
+      }
+
+      v8::Local<v8::Value> operator()(const base::Value::List& value) {
+        NOTREACHED();
+      }
+    };
+
+    return value.Visit(Visitor{.converter = this,
+                               .isolate = context->GetIsolate(),
+                               .creation_context = context->Global()});
   }
+
   std::unique_ptr<base::Value> FromV8Value(
       v8::Local<v8::Value> val,
       v8::Local<v8::Context> context) override {
diff --git a/third_party/blink/web_tests/TestLists/Default.txt b/third_party/blink/web_tests/TestLists/Default.txt
index 831eb17..c2ee575 100644
--- a/third_party/blink/web_tests/TestLists/Default.txt
+++ b/third_party/blink/web_tests/TestLists/Default.txt
@@ -12,8 +12,6 @@
 animations/stability/empty-keyframes.html
 animations/interpolation/border-image-slice-interpolation-stability.html
 animations/responsive/interpolation/offset-rotate-responsive.html
-animations/svg-attribute-composition/svg-bias-composition.html
-animations/svg-attribute-interpolation/svg-numOctaves-interpolation.html
 compositing/animation/animated-composited-inside-hidden.html
 compositing/animation/animation-compositing.html
 compositing/animation/computed-style-during-delay.html
diff --git a/third_party/blink/web_tests/TestLists/highdpi b/third_party/blink/web_tests/TestLists/highdpi
index 8a52b61b..3212cb5 100644
--- a/third_party/blink/web_tests/TestLists/highdpi
+++ b/third_party/blink/web_tests/TestLists/highdpi
@@ -19,14 +19,6 @@
 animations/responsive/zoom-responsive-transform-animation-001.html
 animations/stability/font-builder-crash.html
 animations/state-at-end-event.html
-animations/svg-attribute-composition/svg-amplitude-composition.html
-animations/svg-attribute-composition/svg-azimuth-composition.html
-animations/svg-attribute-composition/svg-baseFrequency-composition.html
-animations/svg-attribute-composition/svg-bias-composition.html
-animations/svg-attribute-interpolation/svg-edgeMode-interpolation.html
-animations/svg-attribute-interpolation/svg-elevation-interpolation.html
-animations/svg-attribute-interpolation/svg-exponent-interpolation.html
-animations/svg-attribute-interpolation/svg-viewBox-interpolation.html
 animations/svg/animated-filter-svg-element.html
 animations/web-animations/KeyframeEffect-animation.html
 clipboard/copy-image-at.html
diff --git a/third_party/blink/web_tests/TestLists/skia-vulkan-swiftshader b/third_party/blink/web_tests/TestLists/skia-vulkan-swiftshader
index 494d606..30fab95 100644
--- a/third_party/blink/web_tests/TestLists/skia-vulkan-swiftshader
+++ b/third_party/blink/web_tests/TestLists/skia-vulkan-swiftshader
@@ -409,7 +409,6 @@
 animations/prefixed/keyframes-unprefixed-01.html
 animations/prefixed/string-keyframes-identifier-prefixed.html
 animations/responsive/responsive-neutral-keyframes.html
-animations/responsive/svg-responsive-to-timing-updates.html
 animations/retain-zero-percent.html
 animations/some-keyframes-empty.html
 animations/stability/animation-transition-collision-crash.html
@@ -418,21 +417,6 @@
 animations/stability/keyframeeffect-no-target-crash.html
 animations/stability/option-opacity-inherit-crash.html
 animations/stability/zero-duration-infinite-iterations.html
-animations/svg-attribute-composition/svg-intercept-composition.html
-animations/svg-attribute-composition/svg-rotate-composition.html
-animations/svg-attribute-composition/svg-seed-composition.html
-animations/svg-attribute-composition/svg-startOffset-composition-002.html
-animations/svg-attribute-composition/svg-transform-composition-list.html
-animations/svg-attribute-composition/svg-x-composition.html
-animations/svg-attribute-composition/svg-x-list-composition.html
-animations/svg-attribute-interpolation/svg-calc-interpolation.html
-animations/svg-attribute-interpolation/svg-in-interpolation.html
-animations/svg-attribute-interpolation/svg-lengthAdjust-interpolation.html
-animations/svg-attribute-interpolation/svg-method-interpolation.html
-animations/svg-attribute-interpolation/svg-numOctaves-interpolation.html
-animations/svg-attribute-interpolation/svg-r-interpolation.html
-animations/svg-attribute-interpolation/svg-stitchTiles-interpolation.html
-animations/svg/svg-animation-affects-use-elements.html
 animations/timing/keyframe-timing-functions3.html
 animations/timing/longhand-timing-function.html
 animations/timing/timing-model.html
diff --git a/third_party/blink/web_tests/animations/responsive/interpolation/resources/responsive-test.js b/third_party/blink/web_tests/animations/responsive/interpolation/resources/responsive-test.js
index 2d097b87..7b419c3 100644
--- a/third_party/blink/web_tests/animations/responsive/interpolation/resources/responsive-test.js
+++ b/third_party/blink/web_tests/animations/responsive/interpolation/resources/responsive-test.js
@@ -5,7 +5,6 @@
 /*
 Exported functions:
 assertCSSResponsive
-assertSVGResponsive
 
 Exported objects:
 neutralKeyframe
@@ -28,15 +27,14 @@
 }
 
 Description:
-assertCSSResponsive() and assertSVGResponsive() take a property
-specific interpolation and a list of style configurations with interpolation
-expectations that apply to each configuration.
-It starts the interpolation in every configuration, changes the
+assertCSSResponsive() takes a property specific interpolation and a list of
+style configurations with interpolation expectations that apply to each
+configuration. It starts the interpolation in every configuration, changes the
 state to every other configuration (n * (n - 1) complexity) and asserts that
-each destination configuration's expectations are met.
-Each animation target can be assigned custom styles via the ".target" selector.
-This test is designed to catch stale interpolation caches.
-Set from/to to the exported neutralKeyframe object to use neutral keyframes.
+each destination configuration's expectations are met. Each animation target can
+be assigned custom styles via the ".target" selector. This test is designed to
+catch stale interpolation caches. Set from/to to the exported neutralKeyframe
+object to use neutral keyframes.
 */
 
 (function() {
@@ -82,33 +80,6 @@
   });
 }
 
-function assertSVGResponsive(options) {
-  pendingResponsiveTests.push({
-    options,
-    bindings: {
-      prefixProperty(property) {
-        return 'svg-' + property;
-      },
-      createTargetContainer(container) {
-        var svgRoot = createElement('svg', container, 'svg-root', svgNamespace);
-        svgRoot.setAttribute('width', 0);
-        svgRoot.setAttribute('height', 0);
-        return svgRoot;
-      },
-      createTarget(targetContainer) {
-        console.assert(options.targetTag);
-        return createElement(options.targetTag, targetContainer, 'target', svgNamespace);
-      },
-      setValue(target, property, value) {
-        target.setAttribute(property, value);
-      },
-      getAnimatedValue(target, property) {
-        return options.getter ? options.getter(target) : target[property].animVal;
-      },
-    },
-  });
-}
-
 function createStateTransitions(configurations) {
   var stateTransitions = [];
   for (var i = 0; i < configurations.length; i++) {
@@ -292,7 +263,6 @@
 
 
 window.assertCSSResponsive = assertCSSResponsive;
-window.assertSVGResponsive = assertSVGResponsive;
 window.neutralKeyframe = neutralKeyframe;
 
 })();
diff --git a/third_party/blink/web_tests/animations/responsive/interpolation/svg-d-responsive.html b/third_party/blink/web_tests/animations/responsive/interpolation/svg-d-responsive.html
deleted file mode 100644
index 99c46c9..0000000
--- a/third_party/blink/web_tests/animations/responsive/interpolation/svg-d-responsive.html
+++ /dev/null
@@ -1,49 +0,0 @@
-<!DOCTYPE html>
-<script src="resources/responsive-test.js"></script>
-<script>
-assertSVGResponsive({
-  targetTag: 'path',
-  property: 'd',
-  getter(target) {
-    return getComputedStyle(target).getPropertyValue('d');
-  },
-  from: 'm 10 10 h 100',
-  to: neutralKeyframe,
-  configurations: [{
-    state: {underlying: 'M 30 30 H 250'},
-    expect: [
-      {at: 0.25, is: 'M 15 15 H 145'},
-      {at: 0.75, is: 'M 25 25 H 215'},
-    ],
-  }, {
-    state: {underlying: 'm 30 30 h 200'},
-    expect: [
-      {at: 0.25, is: 'm 15 15 h 125'},
-      {at: 0.75, is: 'm 25 25 h 175'},
-    ],
-  }, {
-    state: {underlying: 'M 30 30 L 100 100'},
-    expect: [
-      {at: 0.25, is: 'm 10 10 h 100'},
-      {at: 0.75, is: 'M 30 30 L 100 100'},
-    ],
-  }],
-});
-
-assertSVGResponsive({
-  targetTag: 'path',
-  property: 'd',
-  getter(target) {
-    return getComputedStyle(target).getPropertyValue('d');
-  },
-  from: '',
-  to: neutralKeyframe,
-  configurations: [{
-    state: {underlying: 'm 10 10 h 100'},
-    expect: [
-      {at: 0.25, is: ''},
-      {at: 0.75, is: 'm 10 10 h 100'},
-    ],
-  }],
-});
-</script>
diff --git a/third_party/blink/web_tests/animations/responsive/interpolation/svg-points-responsive.html b/third_party/blink/web_tests/animations/responsive/interpolation/svg-points-responsive.html
deleted file mode 100644
index 7ba3a7c..0000000
--- a/third_party/blink/web_tests/animations/responsive/interpolation/svg-points-responsive.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<script src="resources/responsive-test.js"></script>
-<script>
-assertSVGResponsive({
-  targetTag: 'polygon',
-  property: 'points',
-  getter(target) {
-    return Array.from(target.animatedPoints).map(p => `${p.x} ${p.y}`).join(', ');
-  },
-  from: neutralKeyframe,
-  to: '10 20, 30 40',
-  configurations: [{
-    state: {underlying: '10 10, 20 20'},
-    expect: [
-      {at: 0.25, is: '10 12.5, 22.5 25'},
-      {at: 0.75, is: '10 17.5, 27.5 35'},
-    ],
-  }, {
-    state: {underlying: '10 10'},
-    expect: [
-      {at: 0.25, is: '10 10'},
-      {at: 0.75, is: '10 20, 30 40'},
-    ],
-  }],
-});
-</script>
diff --git a/third_party/blink/web_tests/animations/responsive/interpolation/svg-tableValues-responsive.html b/third_party/blink/web_tests/animations/responsive/interpolation/svg-tableValues-responsive.html
deleted file mode 100644
index d7587ae..0000000
--- a/third_party/blink/web_tests/animations/responsive/interpolation/svg-tableValues-responsive.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<!DOCTYPE html>
-<script src="resources/responsive-test.js"></script>
-<script>
-assertSVGResponsive({
-  targetTag: 'feFuncG',
-  property: 'tableValues',
-  getter(target) {
-    return Array.from(target.tableValues.animVal).map(number => number.value).join(', ');
-  },
-  from: neutralKeyframe,
-  to: '10, 20',
-  configurations: [{
-    state: {underlying: '50, 60'},
-    expect: [
-      {at: 0.25, is: '40, 50'},
-      {at: 0.75, is: '20, 30'},
-    ],
-  }, {
-    state: {underlying: '50, 60, 80'},
-    expect: [
-      {at: 0.25, is: '50, 60, 80'},
-      // TODO(dbaron): This is suspicious!
-      {at: 0.75, is: '10, 20, 0'},
-    ],
-  }],
-});
-</script>
diff --git a/third_party/blink/web_tests/animations/responsive/interpolation/svg-transform-responsive.html b/third_party/blink/web_tests/animations/responsive/interpolation/svg-transform-responsive.html
deleted file mode 100644
index 39a7847..0000000
--- a/third_party/blink/web_tests/animations/responsive/interpolation/svg-transform-responsive.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<!DOCTYPE html>
-<script src="resources/responsive-test.js"></script>
-<script>
-function serializeSVGTransformList(transformList) {
-  var elements = [];
-  for (var index = 0; index < transformList.numberOfItems; ++index) {
-    var transform = transformList.getItem(index);
-    elements.push(transform.type);
-    elements.push(transform.angle);
-    elements.push(transform.matrix.a);
-    elements.push(transform.matrix.b);
-    elements.push(transform.matrix.c);
-    elements.push(transform.matrix.d);
-    elements.push(transform.matrix.e);
-    elements.push(transform.matrix.f);
-  }
-  return String(elements);
-}
-
-assertSVGResponsive({
-  targetTag: 'line',
-  property: 'transform',
-  getter(target) {
-    return serializeSVGTransformList(target.transform.animVal);
-  },
-  from: neutralKeyframe,
-  to: 'translate(30 70)',
-  configurations: [{
-    state: {underlying: 'translate(10 10)'},
-    expect: [
-      {at: 0.25, is: 'translate(15 25)'},
-      {at: 0.75, is: 'translate(25 55)'},
-    ],
-  }, {
-    state: {underlying: 'translate(20 30) skewX(10)'},
-    expect: [
-      {at: 0.25, is: 'translate(20 30) skewX(10)'},
-      {at: 0.75, is: 'translate(30 70)'},
-    ],
-  }],
-});
-</script>
diff --git a/third_party/blink/web_tests/animations/responsive/interpolation/svg-x-list-responsive.html b/third_party/blink/web_tests/animations/responsive/interpolation/svg-x-list-responsive.html
deleted file mode 100644
index a9b10be5..0000000
--- a/third_party/blink/web_tests/animations/responsive/interpolation/svg-x-list-responsive.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<script src="resources/responsive-test.js"></script>
-<script>
-assertSVGResponsive({
-  targetTag: 'text',
-  property: 'x',
-  from: neutralKeyframe,
-  to: '100 100',
-  getter(target) {
-    return Array.from(target.x.animVal).map(length => length.value).join(' ');
-  },
-  configurations: [{
-    state: {underlying: '0 0'},
-    expect: [
-      {at: 0.25, is: '25 25'},
-      {at: 0.75, is: '75 75'},
-    ],
-  }, {
-    state: {underlying: '50'},
-    expect: [
-      {at: 0.25, is: '50'},
-      {at: 0.75, is: '100 100'},
-    ],
-  }],
-});
-</script>
diff --git a/third_party/blink/web_tests/animations/responsive/svg-responsive-to-timing-updates.html b/third_party/blink/web_tests/animations/responsive/svg-responsive-to-timing-updates.html
deleted file mode 100644
index a649bce..0000000
--- a/third_party/blink/web_tests/animations/responsive/svg-responsive-to-timing-updates.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE html>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<svg>
-  <stop id="target" offset="0"/>
-</svg>
-<script>
-test(() => {
-  var animation = target.animate({'svg-offset': '1'}, 1);
-  assert_equals(target.offset.animVal, 0);
-  animation.currentTime = 0.5;
-  assert_equals(target.offset.animVal, 0.5);
-  animation.currentTime = 0.75;
-  assert_equals(target.offset.animVal, 0.75);
-  animation.cancel();
-  assert_equals(target.offset.animVal, 0);
-}, 'SVG Web Animations should be responsive to changes in animation timing');
-</script>
diff --git a/third_party/blink/web_tests/animations/responsive/svg-responsive-to-updated-baseval.html b/third_party/blink/web_tests/animations/responsive/svg-responsive-to-updated-baseval.html
deleted file mode 100644
index fd568ae..0000000
--- a/third_party/blink/web_tests/animations/responsive/svg-responsive-to-updated-baseval.html
+++ /dev/null
@@ -1,62 +0,0 @@
-<!DOCTYPE html>
-<title>SVG Web Animations should be responsive to changes in the underlying value</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script>
-// offset has a primitive animVal type.
-function createOffsetTestTarget() {
-  var target = document.createElementNS('http://www.w3.org/2000/svg', 'stop');
-  target.setAttribute('offset', '0');
-  var animation = target.animate({'svg-offset': '1'}, 1);
-  animation.pause();
-  animation.currentTime = 0.5;
-  assert_equals(target.offset.animVal, 0.5, 'Initial get animVal');
-  return target;
-}
-
-test(() => {
-  var target = createOffsetTestTarget();
-  target.setAttribute('offset', '0.5');
-  assert_equals(target.offset.animVal, 0.75);
-}, document.title + ': setAttribute() -> get primitive animVal');
-
-test(() => {
-  var target = createOffsetTestTarget();
-  target.offset.baseVal = '0.5';
-  assert_equals(target.offset.animVal, 0.75);
-}, document.title + ': set baseVal -> get primitive animVal');
-
-
-function serializeRect(rect) {
-  return [rect.x, rect.y, rect.width, rect.height].join(' ');
-}
-
-// viewBox has a tear-off animVal type.
-function createViewBoxTestTarget() {
-  var target = document.createElementNS('http://www.w3.org/2000/svg', 'marker');
-  target.setAttribute('viewBox', '0 0 0 0');
-  var animation = target.animate({'svg-viewBox': '1 1 1 1'}, 1);
-  animation.pause();
-  animation.currentTime = 0.5;
-  assert_equals(serializeRect(target.viewBox.animVal), '0.5 0.5 0.5 0.5', 'Initial get animVal');
-  return target;
-}
-
-test(() => {
-  var target = createViewBoxTestTarget();
-  var animVal = target.viewBox.animVal;
-  target.setAttribute('viewBox', '0.5 0.5 0.5 0.5');
-  assert_equals(serializeRect(animVal), '0.75 0.75 0.75 0.75');
-}, document.title + ': setAttribute() -> read tear-off animVal');
-
-test(() => {
-  var target = createViewBoxTestTarget();
-  var animVal = target.viewBox.animVal;
-  var baseVal = target.viewBox.baseVal;
-  baseVal.x = 0.5;
-  baseVal.y = 0.5;
-  baseVal.width = 0.5;
-  baseVal.height = 0.5;
-  assert_equals(serializeRect(animVal), '0.75 0.75 0.75 0.75');
-}, document.title + ': set baseVal -> read tear-off animVal');
-</script>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-amplitude-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-amplitude-composition.html
deleted file mode 100644
index f98726b..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-amplitude-composition.html
+++ /dev/null
@@ -1,62 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="0" height="0">
-<feComponentTransfer>
-<feFuncR type="gamma" class="target" />
-</feComponentTransfer>
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'amplitude',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 2},
-  {at: 0, is: 4},
-  {at: 0.2, is: 5},
-  {at: 0.6, is: 7},
-  {at: 1, is: 9},
-  {at: 1.4, is: 11},
-]);
-
-assertAttributeInterpolation({
-  property: 'amplitude',
-  underlying: '5',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: -3},
-  {at: 0, is: 1},
-  {at: 0.2, is: 3},
-  {at: 0.6, is: 7},
-  {at: 1, is: 11},
-  {at: 1.4, is: 15},
-]);
-
-assertAttributeInterpolation({
-  property: 'amplitude',
-  underlying: '5',
-  from: neutralKeyframe,
-  to: '10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 3},
-  {at: 0, is: 5},
-  {at: 0.2, is: 6},
-  {at: 0.6, is: 8},
-  {at: 1, is: 10},
-  {at: 1.4, is: 12},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-azimuth-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-azimuth-composition.html
deleted file mode 100644
index d2b7cf40..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-azimuth-composition.html
+++ /dev/null
@@ -1,60 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="0" height="0">
-<feDistantLight class="target" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'azimuth',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 2},
-  {at: 0, is: 4},
-  {at: 0.2, is: 5},
-  {at: 0.6, is: 7},
-  {at: 1, is: 9},
-  {at: 1.4, is: 11},
-]);
-
-assertAttributeInterpolation({
-  property: 'azimuth',
-  underlying: '5',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: -3},
-  {at: 0, is: 1},
-  {at: 0.2, is: 3},
-  {at: 0.6, is: 7},
-  {at: 1, is: 11},
-  {at: 1.4, is: 15},
-]);
-
-assertAttributeInterpolation({
-  property: 'azimuth',
-  underlying: '5',
-  from: neutralKeyframe,
-  to: '10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 3},
-  {at: 0, is: 5},
-  {at: 0.2, is: 6},
-  {at: 0.6, is: 8},
-  {at: 1, is: 10},
-  {at: 1.4, is: 12},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-baseFrequency-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-baseFrequency-composition.html
deleted file mode 100644
index fd00993..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-baseFrequency-composition.html
+++ /dev/null
@@ -1,139 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg xmlns="http://www.w3.org/2000/svg" width="90" height="90">
-<feTurbulence class="target" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'baseFrequency',
-  underlying: '0',
-  from: '1',
-  fromComposite: 'add',
-  to: '6 11',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-1, -3'},
-  {at: 0, is: '1, 1'},
-  {at: 0.2, is: '2, 3'},
-  {at: 0.6, is: '4, 7'},
-  {at: 1, is: '6, 11'},
-  {at: 1.4, is: '8, 15'},
-]);
-
-assertAttributeInterpolation({
-  property: 'baseFrequency',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6 11',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '2, 0'},
-  {at: 0, is: '4, 4'},
-  {at: 0.2, is: '5, 6'},
-  {at: 0.6, is: '7, 10'},
-  {at: 1, is: '9, 14'},
-  {at: 1.4, is: '11, 18'},
-]);
-
-assertAttributeInterpolation({
-  property: 'baseFrequency',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6 11',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-2.2, -4.2'},
-  {at: 0, is: '1, 1'},
-  {at: 0.2, is: '2.6, 3.6'},
-  {at: 0.6, is: '5.8, 8.8'},
-  {at: 1, is: '9, 14'},
-  {at: 1.4, is: '12.2, 19.2'},
-]);
-
-assertAttributeInterpolation({
-  property: 'baseFrequency',
-  underlying: '3',
-  from: neutralKeyframe,
-  to: '6 11',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: '1.8, -0.2'},
-  {at: 0, is: '3, 3'},
-  {at: 0.2, is: '3.6, 4.6'},
-  {at: 0.6, is: '4.8, 7.8'},
-  {at: 1, is: '6, 11'},
-  {at: 1.4, is: '7.2, 14.2'},
-]);
-
-assertAttributeInterpolation({
-  property: 'baseFrequency',
-  underlying: '0',
-  from: '-2 10',
-  fromComposite: 'add',
-  to: '3 10',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-4, 10'},
-  {at: 0, is: '-2, 10'},
-  {at: 0.2, is: '-1, 10'},
-  {at: 0.6, is: '1, 10'},
-  {at: 1, is: '3, 10'},
-  {at: 1.4, is: '5, 10'},
-]);
-
-assertAttributeInterpolation({
-  property: 'baseFrequency',
-  underlying: '3',
-  from: '-2 10',
-  fromComposite: 'add',
-  to: '3 10',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-1, 13'},
-  {at: 0, is: '1, 13'},
-  {at: 0.2, is: '2, 13'},
-  {at: 0.6, is: '4, 13'},
-  {at: 1, is: '6, 13'},
-  {at: 1.4, is: '8, 13'},
-]);
-
-assertAttributeInterpolation({
-  property: 'baseFrequency',
-  underlying: '3',
-  from: '-2 10',
-  fromComposite: 'replace',
-  to: '3 10',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-5.2, 8.8'},
-  {at: 0, is: '-2, 10'},
-  {at: 0.2, is: '-0.4, 10.6'},
-  {at: 0.6, is: '2.8, 11.8'},
-  {at: 1, is: '6, 13'},
-  {at: 1.4, is: '9.2, 14.2'},
-]);
-
-assertAttributeInterpolation({
-  property: 'baseFrequency',
-  underlying: '3',
-  from: neutralKeyframe,
-  to: '3 10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: '3, 0.2'},
-  {at: 0, is: '3, 3'},
-  {at: 0.2, is: '3, 4.4'},
-  {at: 0.6, is: '3, 7.2'},
-  {at: 1, is: '3, 10'},
-  {at: 1.4, is: '3, 12.8'},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-bias-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-bias-composition.html
deleted file mode 100644
index 9cebe9d..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-bias-composition.html
+++ /dev/null
@@ -1,60 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="0" height="0">
-<feConvolveMatrix class="target" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'bias',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 2},
-  {at: 0, is: 4},
-  {at: 0.2, is: 5},
-  {at: 0.6, is: 7},
-  {at: 1, is: 9},
-  {at: 1.4, is: 11},
-]);
-
-assertAttributeInterpolation({
-  property: 'bias',
-  underlying: '5',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: -3},
-  {at: 0, is: 1},
-  {at: 0.2, is: 3},
-  {at: 0.6, is: 7},
-  {at: 1, is: 11},
-  {at: 1.4, is: 15},
-]);
-
-assertAttributeInterpolation({
-  property: 'bias',
-  underlying: '5',
-  from: neutralKeyframe,
-  to: '10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 3},
-  {at: 0, is: 5},
-  {at: 0.2, is: 6},
-  {at: 0.6, is: 8},
-  {at: 1, is: 10},
-  {at: 1.4, is: 12},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-cx-cy-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-cx-cy-composition.html
deleted file mode 100644
index a296718..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-cx-cy-composition.html
+++ /dev/null
@@ -1,108 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<ellipse class="target" cx="40" cy="30" rx="20" ry="30" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-
-assertAttributeInterpolation({
-  property: 'cx',
-  underlying: '3',
-  from: '-2',
-  fromComposite: 'add',
-  to: '3',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-
-assertAttributeInterpolation({
-  property: 'cx',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'replace',
-  to: '3',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-
-assertAttributeInterpolation({
-  property: 'cx',
-  underlying: '1',
-  from: neutralKeyframe,
-  to: '6',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-
-assertAttributeInterpolation({
-  property: 'cy',
-  underlying: '3',
-  from: '-2',
-  fromComposite: 'add',
-  to: '3',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-
-assertAttributeInterpolation({
-  property: 'cy',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'replace',
-  to: '3',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-
-assertAttributeInterpolation({
-  property: 'cy',
-  underlying: '1',
-  from: neutralKeyframe,
-  to: '6',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-d-composition-expected.txt b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-d-composition-expected.txt
deleted file mode 100644
index 44aa0ffa..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-d-composition-expected.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-This is a testharness.js-based test.
-[FAIL] SMIL: Interpolate attribute <d> with underlying [M 10 10 H 20] from add [M 20 30 L 40 50] to add [M 30 40 L 50 60] at (0) is [M 20 30 L 40 50]
-  assert_equals: expected "path ( \\" M 20 30 L 40 50 \\" ) " but got "path ( \\" M 30 40 \\" ) "
-[FAIL] SMIL: Interpolate attribute <d> with underlying [M 10 10 H 20] from add [M 20 30 L 40 50] to add [M 30 40 L 50 60] at (0.2) is [M 22 32 L 42 52]
-  assert_equals: expected "path ( \\" M 22 32 L 42 52 \\" ) " but got "path ( \\" M 32 42 \\" ) "
-[FAIL] SMIL: Interpolate attribute <d> with underlying [M 10 10 H 20] from add [M 20 30 L 40 50] to add [M 30 40 L 50 60] at (0.6) is [M 26 36 L 46 56]
-  assert_equals: expected "path ( \\" M 26 36 L 46 56 \\" ) " but got "path ( \\" M 36 46 \\" ) "
-[FAIL] SMIL: Interpolate attribute <d> with underlying [M 10 10 H 20] from add [M 20 30 L 40 50] to add [M 30 40 L 50 60] at (1) is [M 30 40 L 50 60]
-  assert_equals: expected "path ( \\" M 30 40 L 50 60 \\" ) " but got "path ( \\" M 40 50 \\" ) "
-[FAIL] SMIL: Interpolate attribute <d> with underlying [M 10 10 L 20 20] from neutral to add [m 30 40 l 50 60] at (0) is [M 10 10 L 20 20]
-  assert_equals: expected "path ( \\" M 10 10 L 20 20 \\" ) " but got "none "
-[FAIL] SMIL: Interpolate attribute <d> with underlying [M 10 10 L 20 20] from neutral to add [m 30 40 l 50 60] at (0.2) is [m 14 16 l 18 20]
-  assert_equals: expected "path ( \\" M 14 16 L 32 36 \\" ) " but got "none "
-[FAIL] SMIL: Interpolate attribute <d> with underlying [M 10 10 L 20 20] from neutral to add [m 30 40 l 50 60] at (0.6) is [m 22 28 l 34 40]
-  assert_equals: expected "path ( \\" M 22 28 L 56 68 \\" ) " but got "none "
-[FAIL] SMIL: Interpolate attribute <d> with underlying [M 10 10 L 20 20] from neutral to add [m 30 40 l 50 60] at (1) is [m 30 40 l 50 60]
-  assert_equals: expected "path ( \\" M 30 40 L 80 100 \\" ) " but got "none "
-[FAIL] SMIL: Interpolate attribute <d> with underlying [m 30 40 l 50 60] from add [M 10 10 L 20 20] to neutral at (0) is [M 10 10 L 20 20]
-  assert_equals: expected "path ( \\" M 10 10 L 20 20 \\" ) " but got "path ( \\" M 30 40 L 80 100 \\" ) "
-[FAIL] SMIL: Interpolate attribute <d> with underlying [m 30 40 l 50 60] from add [M 10 10 L 20 20] to neutral at (0.2) is [m 14 16 l 18 20]
-  assert_equals: expected "path ( \\" M 14 16 L 32 36 \\" ) " but got "path ( \\" M 30 40 L 80 100 \\" ) "
-[FAIL] SMIL: Interpolate attribute <d> with underlying [m 30 40 l 50 60] from add [M 10 10 L 20 20] to neutral at (0.6) is [m 22 28 l 34 40]
-  assert_equals: expected "path ( \\" M 22 28 L 56 68 \\" ) " but got "path ( \\" M 30 40 L 80 100 \\" ) "
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-d-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-d-composition.html
deleted file mode 100644
index b06f1afde..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-d-composition.html
+++ /dev/null
@@ -1,108 +0,0 @@
-<!DOCTYPE html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<path class="target" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-
-// SVG Paths always replace.
-
-assertAttributeInterpolation({
-  property: 'd',
-  underlying: 'M 10 10 H 20',
-  from: 'M 20 30 L 40 50',
-  fromComposite: 'add',
-  to: 'M 30 40 L 50 60',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 'M 16 26 L 36 46'},
-  {at: 0, is: 'M 20 30 L 40 50'},
-  {at: 0.2, is: 'M 22 32 L 42 52'},
-  {at: 0.6, is: 'M 26 36 L 46 56'},
-  {at: 1, is: 'M 30 40 L 50 60'},
-  {at: 1.4, is: 'M 34 44 L 54 64'},
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  underlying: 'M 10 10 H 20',
-  from: 'M 20 30 L 40 50',
-  fromComposite: 'add',
-  to: 'M 30 40 H 50',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 'M 20 30 L 40 50'},
-  {at: 0, is: 'M 20 30 L 40 50'},
-  {at: 0.2, is: 'M 20 30 L 40 50'},
-  {at: 0.6, is: 'M 30 40 H 50'},
-  {at: 1, is: 'M 30 40 H 50'},
-  {at: 1.4, is: 'M 30 40 H 50'},
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  underlying: 'M 10 10 H 20',
-  from: 'm 20 30 L 40 50',
-  fromComposite: 'add',
-  to: 'm 30 40 L 50 60',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 'm 16 26 L 36 46'},
-  {at: 0, is: 'm 20 30 L 40 50'},
-  {at: 0.2, is: 'm 22 32 L 42 52'},
-  {at: 0.6, is: 'm 26 36 L 46 56'},
-  {at: 1, is: 'm 30 40 L 50 60'},
-  {at: 1.4, is: 'm 34 44 L 54 64'},
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  underlying: 'M 10 10 L 20 20',
-  from: neutralKeyframe,
-  to: 'm 30 40 l 50 60',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 'm 2 -2 l -6 -10'},
-  {at: 0, is: 'M 10 10 L 20 20'},
-  {at: 0.2, is: 'm 14 16 l 18 20'},
-  {at: 0.6, is: 'm 22 28 l 34 40'},
-  {at: 1, is: 'm 30 40 l 50 60'},
-  {at: 1.4, is: 'm 38 52 l 66 80'},
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  underlying: 'M 10 10 L 20 20',
-  from: neutralKeyframe,
-  to: 'm 30 40 l 50 60',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 'm 2 -2 l -6 -10'},
-  {at: 0, is: 'M 10 10 L 20 20'},
-  {at: 0.2, is: 'm 14 16 l 18 20'},
-  {at: 0.6, is: 'm 22 28 l 34 40'},
-  {at: 1, is: 'm 30 40 l 50 60'},
-  {at: 1.4, is: 'm 38 52 l 66 80'},
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  underlying: 'm 30 40 l 50 60',
-  from: 'M 10 10 L 20 20',
-  fromComposite: 'add',
-  to: neutralKeyframe,
-}, [
-  {at: -0.4, is: 'm 2 -2 l -6 -10'},
-  {at: 0, is: 'M 10 10 L 20 20'},
-  {at: 0.2, is: 'm 14 16 l 18 20'},
-  {at: 0.6, is: 'm 22 28 l 34 40'},
-  {at: 1, is: 'm 30 40 l 50 60'},
-  {at: 1.4, is: 'm 38 52 l 66 80'},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-diffuseConstant-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-diffuseConstant-composition.html
deleted file mode 100644
index 1ad0baf..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-diffuseConstant-composition.html
+++ /dev/null
@@ -1,60 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="0" height="0">
-<feDiffuseLighting class="target" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'diffuseConstant',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 2},
-  {at: 0, is: 4},
-  {at: 0.2, is: 5},
-  {at: 0.6, is: 7},
-  {at: 1, is: 9},
-  {at: 1.4, is: 11},
-]);
-
-assertAttributeInterpolation({
-  property: 'diffuseConstant',
-  underlying: '5',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: -3},
-  {at: 0, is: 1},
-  {at: 0.2, is: 3},
-  {at: 0.6, is: 7},
-  {at: 1, is: 11},
-  {at: 1.4, is: 15},
-]);
-
-assertAttributeInterpolation({
-  property: 'diffuseConstant',
-  underlying: '5',
-  from: neutralKeyframe,
-  to: '10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 3},
-  {at: 0, is: 5},
-  {at: 0.2, is: 6},
-  {at: 0.6, is: 8},
-  {at: 1, is: 10},
-  {at: 1.4, is: 12},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-divisor-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-divisor-composition.html
deleted file mode 100644
index b7ce542..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-divisor-composition.html
+++ /dev/null
@@ -1,60 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="0" height="0">
-<feConvolveMatrix class="target" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'divisor',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 2},
-  {at: 0, is: 4},
-  {at: 0.2, is: 5},
-  {at: 0.6, is: 7},
-  {at: 1, is: 9},
-  {at: 1.4, is: 11},
-]);
-
-assertAttributeInterpolation({
-  property: 'divisor',
-  underlying: '5',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: -3},
-  {at: 0, is: 1},
-  {at: 0.2, is: 3},
-  {at: 0.6, is: 7},
-  {at: 1, is: 11},
-  {at: 1.4, is: 15},
-]);
-
-assertAttributeInterpolation({
-  property: 'divisor',
-  underlying: '5',
-  from: neutralKeyframe,
-  to: '10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 3},
-  {at: 0, is: 5},
-  {at: 0.2, is: 6},
-  {at: 0.6, is: 8},
-  {at: 1, is: 10},
-  {at: 1.4, is: 12},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-dx-dy-length-list-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-dx-dy-length-list-composition.html
deleted file mode 100644
index f8550d1..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-dx-dy-length-list-composition.html
+++ /dev/null
@@ -1,135 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-  <svg width="0" height="0">
-    <text class="target">123</text>
-  </svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'dx',
-  underlying: '2',
-  from: '-1',
-  fromComposite: 'add',
-  to: '4',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '-1'},
-  {at: 0, is: '1'},
-  {at: 0.2, is: '2'},
-  {at: 0.6, is: '4'},
-  {at: 1, is: '6'},
-  {at: 1.4, is: '8'},
-]);
-assertAttributeInterpolation({
-  property: 'dy',
-  underlying: '2 2',
-  from: '-1 -4',
-  fromComposite: 'add',
-  to: '4 -14',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '-1 2'},
-  {at: 0, is: '1 -2'},
-  {at: 0.2, is: '2 -4'},
-  {at: 0.6, is: '4 -8'},
-  {at: 1, is: '6 -12'},
-  {at: 1.4, is: '8 -16'},
-]);
-
-assertAttributeInterpolation({
-  property: 'dx',
-  underlying: '2',
-  from: '1',
-  fromComposite: 'replace',
-  to: '4',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '-1'},
-  {at: 0, is: '1'},
-  {at: 0.2, is: '2'},
-  {at: 0.6, is: '4'},
-  {at: 1, is: '6'},
-  {at: 1.4, is: '8'},
-]);
-assertAttributeInterpolation({
-  property: 'dy',
-  underlying: '2 2',
-  from: '1 -2',
-  fromComposite: 'replace',
-  to: '4 -14',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '-1 2'},
-  {at: 0, is: '1 -2'},
-  {at: 0.2, is: '2 -4'},
-  {at: 0.6, is: '4 -8'},
-  {at: 1, is: '6 -12'},
-  {at: 1.4, is: '8 -16'},
-]);
-
-assertAttributeInterpolation({
-  property: 'dx',
-  underlying: '1',
-  from: neutralKeyframe,
-  to: '6',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: '-1'},
-  {at: 0, is: '1'},
-  {at: 0.2, is: '2'},
-  {at: 0.6, is: '4'},
-  {at: 1, is: '6'},
-  {at: 1.4, is: '8'},
-]);
-assertAttributeInterpolation({
-  property: 'dy',
-  underlying: '1 -2',
-  from: neutralKeyframe,
-  to: '6 -12',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: '-1 2'},
-  {at: 0, is: '1 -2'},
-  {at: 0.2, is: '2 -4'},
-  {at: 0.6, is: '4 -8'},
-  {at: 1, is: '6 -12'},
-  {at: 1.4, is: '8 -16'},
-]);
-
-assertAttributeInterpolation({
-  property: 'dx',
-  underlying: '1',
-  from: '2 3',
-  fromComposite: 'add',
-  to: '4 5 6',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '2 3'},
-  {at: 0, is: '2 3'},
-  {at: 0.2, is: '2 3'},
-  {at: 0.6, is: '4 5 6'},
-  {at: 1, is: '4 5 6'},
-  {at: 1.4, is: '4 5 6'},
-]);
-assertAttributeInterpolation({
-  property: 'dy',
-  underlying: '1 2',
-  from: '3',
-  fromComposite: 'add',
-  to: '4 5 6',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '3'},
-  {at: 0, is: '3'},
-  {at: 0.2, is: '3'},
-  {at: 0.6, is: '4 5 6'},
-  {at: 1, is: '4 5 6'},
-  {at: 1.4, is: '4 5 6'},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-dx-dy-number-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-dx-dy-number-composition.html
deleted file mode 100644
index 8be3dce..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-dx-dy-number-composition.html
+++ /dev/null
@@ -1,104 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-  <svg width="0" height="0">
-    <feOffset class="target"></feOffset>
-  </svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'dx',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 2},
-  {at: 0, is: 4},
-  {at: 0.2, is: 5},
-  {at: 0.6, is: 7},
-  {at: 1, is: 9},
-  {at: 1.4, is: 11},
-]);
-assertAttributeInterpolation({
-  property: 'dy',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 2},
-  {at: 0, is: 4},
-  {at: 0.2, is: 5},
-  {at: 0.6, is: 7},
-  {at: 1, is: 9},
-  {at: 1.4, is: 11},
-]);
-
-assertAttributeInterpolation({
-  property: 'dx',
-  underlying: '5',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: -3},
-  {at: 0, is: 1},
-  {at: 0.2, is: 3},
-  {at: 0.6, is: 7},
-  {at: 1, is: 11},
-  {at: 1.4, is: 15},
-]);
-assertAttributeInterpolation({
-  property: 'dy',
-  underlying: '5',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: -3},
-  {at: 0, is: 1},
-  {at: 0.2, is: 3},
-  {at: 0.6, is: 7},
-  {at: 1, is: 11},
-  {at: 1.4, is: 15},
-]);
-
-assertAttributeInterpolation({
-  property: 'dx',
-  underlying: '5',
-  from: neutralKeyframe,
-  to: '10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 3},
-  {at: 0, is: 5},
-  {at: 0.2, is: 6},
-  {at: 0.6, is: 8},
-  {at: 1, is: 10},
-  {at: 1.4, is: 12},
-]);
-assertAttributeInterpolation({
-  property: 'dy',
-  underlying: '5',
-  from: neutralKeyframe,
-  to: '10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 3},
-  {at: 0, is: 5},
-  {at: 0.2, is: 6},
-  {at: 0.6, is: 8},
-  {at: 1, is: 10},
-  {at: 1.4, is: 12},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-elevation-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-elevation-composition.html
deleted file mode 100644
index da9012bb..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-elevation-composition.html
+++ /dev/null
@@ -1,60 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="0" height="0">
-<feDistantLight class="target" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'elevation',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 2},
-  {at: 0, is: 4},
-  {at: 0.2, is: 5},
-  {at: 0.6, is: 7},
-  {at: 1, is: 9},
-  {at: 1.4, is: 11},
-]);
-
-assertAttributeInterpolation({
-  property: 'elevation',
-  underlying: '5',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: -3},
-  {at: 0, is: 1},
-  {at: 0.2, is: 3},
-  {at: 0.6, is: 7},
-  {at: 1, is: 11},
-  {at: 1.4, is: 15},
-]);
-
-assertAttributeInterpolation({
-  property: 'elevation',
-  underlying: '5',
-  from: neutralKeyframe,
-  to: '10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 3},
-  {at: 0, is: 5},
-  {at: 0.2, is: 6},
-  {at: 0.6, is: 8},
-  {at: 1, is: 10},
-  {at: 1.4, is: 12},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-exponent-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-exponent-composition.html
deleted file mode 100644
index bf5abae2..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-exponent-composition.html
+++ /dev/null
@@ -1,62 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="0" height="0">
-<feComponentTransfer>
-<feFuncR type="gamma" class="target" />
-</feComponentTransfer>
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'exponent',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 2},
-  {at: 0, is: 4},
-  {at: 0.2, is: 5},
-  {at: 0.6, is: 7},
-  {at: 1, is: 9},
-  {at: 1.4, is: 11},
-]);
-
-assertAttributeInterpolation({
-  property: 'exponent',
-  underlying: '5',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: -3},
-  {at: 0, is: 1},
-  {at: 0.2, is: 3},
-  {at: 0.6, is: 7},
-  {at: 1, is: 11},
-  {at: 1.4, is: 15},
-]);
-
-assertAttributeInterpolation({
-  property: 'exponent',
-  underlying: '5',
-  from: neutralKeyframe,
-  to: '10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 3},
-  {at: 0, is: 5},
-  {at: 0.2, is: 6},
-  {at: 0.6, is: 8},
-  {at: 1, is: 10},
-  {at: 1.4, is: 12},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-fx-fy-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-fx-fy-composition.html
deleted file mode 100644
index c5ab10e..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-fx-fy-composition.html
+++ /dev/null
@@ -1,108 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<radialGradient class="target" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-
-assertAttributeInterpolation({
-  property: 'fx',
-  underlying: '3',
-  from: '-2',
-  fromComposite: 'add',
-  to: '3',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-
-assertAttributeInterpolation({
-  property: 'fx',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'replace',
-  to: '3',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-
-assertAttributeInterpolation({
-  property: 'fx',
-  underlying: '1',
-  from: neutralKeyframe,
-  to: '6',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-
-assertAttributeInterpolation({
-  property: 'fy',
-  underlying: '3',
-  from: '-2',
-  fromComposite: 'add',
-  to: '3',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-
-assertAttributeInterpolation({
-  property: 'fy',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'replace',
-  to: '3',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-
-assertAttributeInterpolation({
-  property: 'fy',
-  underlying: '1',
-  from: neutralKeyframe,
-  to: '6',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-gradientTransform-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-gradientTransform-composition.html
deleted file mode 100644
index f851195..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-gradientTransform-composition.html
+++ /dev/null
@@ -1,250 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<linearGradient class="target" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-
-assertAttributeInterpolation({
-  property: 'gradientTransform',
-  underlying: 'translate(10 10)',
-  from: 'translate(0 10)',
-  fromComposite: 'add',
-  to: 'translate(20 50)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'translate(10,10) translate(-8,-6)'},
-  {at: 0, is: 'translate(10,10) translate(0,10)'},
-  {at: 0.2, is: 'translate(10,10) translate(4,18)'},
-  {at: 0.6, is: 'translate(10,10) translate(12,34)'},
-  {at: 1, is: 'translate(10,10) translate(20,50)'},
-  {at: 1.4, is: 'translate(10,10) translate(28,66)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'gradientTransform',
-  underlying: 'translate(10 10)',
-  from: 'translate(10 20)',
-  fromComposite: 'replace',
-  to: 'translate(20 50)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'translate(10 20)'},
-  {at: 0, is: 'translate(10 20)'},
-  {at: 0.2, is: 'translate(10 20)'},
-  {at: 0.6, is: 'translate(10 10) translate(20 50)'},
-  {at: 1, is: 'translate(10 10) translate(20 50)'},
-  {at: 1.4, is: 'translate(10 10) translate(20 50)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'gradientTransform',
-  underlying: 'translate(10 20)',
-  from: neutralKeyframe,
-  to: 'translate(30 60)',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: 'translate(2,4)'},
-  {at: 0, is: 'translate(10,20)'},
-  {at: 0.2, is: 'translate(14,28)'},
-  {at: 0.6, is: 'translate(22,44)'},
-  {at: 1, is: 'translate(30,60)'},
-  {at: 1.4, is: 'translate(38,76)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'gradientTransform',
-  underlying: 'scale(10 5)',
-  from: 'scale(10 10)',
-  fromComposite: 'add',
-  to: 'scale(20 50)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'scale(10 5) scale(6 -6)'},
-  {at: 0, is: 'scale(10 5) scale(10 10)'},
-  {at: 0.2, is: 'scale(10 5) scale(12 18)'},
-  {at: 0.6, is: 'scale(10 5) scale(16 34)'},
-  {at: 1, is: 'scale(10 5) scale(20 50)'},
-  {at: 1.4, is: 'scale(10 5) scale(24 66)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'gradientTransform',
-  underlying: 'scale(10 5)',
-  from: 'scale(10 10)',
-  fromComposite: 'replace',
-  to: 'scale(20 50)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'scale(10 10)'},
-  {at: 0, is: 'scale(10 10)'},
-  {at: 0.2, is: 'scale(10 10)'},
-  {at: 0.6, is: 'scale(10 5) scale(20 50)'},
-  {at: 1, is: 'scale(10 5) scale(20 50)'},
-  {at: 1.4, is: 'scale(10 5) scale(20 50)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'gradientTransform',
-  underlying: 'scale(10 10)',
-  from: neutralKeyframe,
-  to: 'scale(20 50)',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: 'scale(6 -6)'},
-  {at: 0, is: 'scale(10 10)'},
-  {at: 0.2, is: 'scale(12 18)'},
-  {at: 0.6, is: 'scale(16 34)'},
-  {at: 1, is: 'scale(20 50)'},
-  {at: 1.4, is: 'scale(24 66)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'gradientTransform',
-  underlying: 'rotate(10 10 10)',
-  from: 'rotate(10 20 30)',
-  fromComposite: 'add',
-  to: 'rotate(40 80 160)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'rotate(10 10 10) rotate(-2 -4 -22)'},
-  {at: 0, is: 'rotate(10 10 10) rotate(10 20 30)'},
-  {at: 0.2, is: 'rotate(10 10 10) rotate(16 32 56)'},
-  {at: 0.6, is: 'rotate(10 10 10) rotate(28 56 108)'},
-  {at: 1, is: 'rotate(10 10 10) rotate(40 80 160)'},
-  {at: 1.4, is: 'rotate(10 10 10) rotate(52 104 212)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'gradientTransform',
-  underlying: 'rotate(10 10 10)',
-  from: 'rotate(10 20 30)',
-  fromComposite: 'replace',
-  to: 'rotate(40 80 160)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'rotate(10 20 30)'},
-  {at: 0, is: 'rotate(10 20 30)'},
-  {at: 0.2, is: 'rotate(10 20 30)'},
-  {at: 0.6, is: 'rotate(10 10 10) rotate(40 80 160)'},
-  {at: 1, is: 'rotate(10 10 10) rotate(40 80 160)'},
-  {at: 1.4, is: 'rotate(10 10 10) rotate(40 80 160)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'gradientTransform',
-  underlying: 'rotate(10 20 30)',
-  from: neutralKeyframe,
-  to: 'rotate(40 80 160)',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: 'rotate(-2 -4 -22)'},
-  {at: 0, is: 'rotate(10 20 30)'},
-  {at: 0.2, is: 'rotate(16 32 56)'},
-  {at: 0.6, is: 'rotate(28 56 108)'},
-  {at: 1, is: 'rotate(40 80 160)'},
-  {at: 1.4, is: 'rotate(52 104 212)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'gradientTransform',
-  underlying: 'skewX(10)',
-  from: 'skewX(30)',
-  fromComposite: 'add',
-  to: 'skewX(50)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'skewX(10) skewX(22)'},
-  {at: 0, is: 'skewX(10) skewX(30)'},
-  {at: 0.2, is: 'skewX(10) skewX(34)'},
-  {at: 0.6, is: 'skewX(10) skewX(42)'},
-  {at: 1, is: 'skewX(10) skewX(50)'},
-  {at: 1.4, is: 'skewX(10) skewX(58)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'gradientTransform',
-  underlying: 'skewX(10)',
-  from: 'skewX(30)',
-  fromComposite: 'replace',
-  to: 'skewX(50)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'skewX(30)'},
-  {at: 0, is: 'skewX(30)'},
-  {at: 0.2, is: 'skewX(30)'},
-  {at: 0.6, is: 'skewX(10) skewX(50)'},
-  {at: 1, is: 'skewX(10) skewX(50)'},
-  {at: 1.4, is: 'skewX(10) skewX(50)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'gradientTransform',
-  underlying: 'skewX(30)',
-  from: neutralKeyframe,
-  to: 'skewX(50)',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: 'skewX(22)'},
-  {at: 0, is: 'skewX(30)'},
-  {at: 0.2, is: 'skewX(34)'},
-  {at: 0.6, is: 'skewX(42)'},
-  {at: 1, is: 'skewX(50)'},
-  {at: 1.4, is: 'skewX(58)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'gradientTransform',
-  underlying: 'skewY(10)',
-  from: 'skewY(30)',
-  fromComposite: 'add',
-  to: 'skewY(50)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'skewY(10) skewY(22)'},
-  {at: 0, is: 'skewY(10) skewY(30)'},
-  {at: 0.2, is: 'skewY(10) skewY(34)'},
-  {at: 0.6, is: 'skewY(10) skewY(42)'},
-  {at: 1, is: 'skewY(10) skewY(50)'},
-  {at: 1.4, is: 'skewY(10) skewY(58)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'gradientTransform',
-  underlying: 'skewY(10)',
-  from: 'skewY(30)',
-  fromComposite: 'replace',
-  to: 'skewY(50)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'skewY(30)'},
-  {at: 0, is: 'skewY(30)'},
-  {at: 0.2, is: 'skewY(30)'},
-  {at: 0.6, is: 'skewY(10) skewY(50)'},
-  {at: 1, is: 'skewY(10) skewY(50)'},
-  {at: 1.4, is: 'skewY(10) skewY(50)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'gradientTransform',
-  underlying: 'skewY(30)',
-  from: neutralKeyframe,
-  to: 'skewY(50)',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: 'skewY(22)'},
-  {at: 0, is: 'skewY(30)'},
-  {at: 0.2, is: 'skewY(34)'},
-  {at: 0.6, is: 'skewY(42)'},
-  {at: 1, is: 'skewY(50)'},
-  {at: 1.4, is: 'skewY(58)'}
-]);
-
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-height-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-height-composition.html
deleted file mode 100644
index 65180d4..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-height-composition.html
+++ /dev/null
@@ -1,341 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script src="../../resources/ahem.js"></script>
-<style>
-:root {
-  font: 10px Ahem;
-}
-</style>
-</head>
-<body>
-<template id="target-template">
-<svg width="200px" height="300px" viewBox="0 0 1500 1000">
-  <rect class="target" x="10" y="10" width="10" height="10" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-
-// Same unit
-
-assertAttributeInterpolation({
-  property: 'height',
-  underlying: '20',
-  from: '-10',
-  fromComposite: 'add',
-  to: '40',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 10},
-  {at: 0.2, is: 20},
-  {at: 0.6, is: 40},
-  {at: 1, is: 60},
-  {at: 1.4, is: 80}
-]);
-assertAttributeInterpolation({
-  property: 'height',
-  underlying: '20%',
-  from: '-10%',
-  fromComposite: 'add',
-  to: '40%',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '0%'},
-  {at: 0, is: '10%'},
-  {at: 0.2, is: '20%'},
-  {at: 0.6, is: '40%'},
-  {at: 1, is: '60%'},
-  {at: 1.4, is: '80%'}
-]);
-assertAttributeInterpolation({
-  property: 'height',
-  underlying: '20em',
-  from: '-10em',
-  fromComposite: 'add',
-  to: '40em',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '0em'},
-  {at: 0, is: '10em'},
-  {at: 0.2, is: '20em'},
-  {at: 0.6, is: '40em'},
-  {at: 1, is: '60em'},
-  {at: 1.4, is: '80em'}
-]);
-assertAttributeInterpolation({
-  property: 'height',
-  underlying: '20ex',
-  from: '-10ex',
-  fromComposite: 'add',
-  to: '40ex',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '0ex'},
-  {at: 0, is: '10ex'},
-  {at: 0.2, is: '20ex'},
-  {at: 0.6, is: '40ex'},
-  {at: 1, is: '60ex'},
-  {at: 1.4, is: '80ex'}
-]);
-assertAttributeInterpolation({
-  property: 'height',
-  underlying: '20rem',
-  from: '-10rem',
-  fromComposite: 'add',
-  to: '40rem',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '0rem'},
-  {at: 0, is: '10rem'},
-  {at: 0.2, is: '20rem'},
-  {at: 0.6, is: '40rem'},
-  {at: 1, is: '60rem'},
-  {at: 1.4, is: '80rem'}
-]);
-
-assertAttributeInterpolation({
-  property: 'height',
-  underlying: '20',
-  from: '10',
-  fromComposite: 'replace',
-  to: '40',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 10},
-  {at: 0.2, is: 20},
-  {at: 0.6, is: 40},
-  {at: 1, is: 60},
-  {at: 1.4, is: 80}
-]);
-assertAttributeInterpolation({
-  property: 'height',
-  underlying: '20%',
-  from: '10%',
-  fromComposite: 'replace',
-  to: '40%',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '0%'},
-  {at: 0, is: '10%'},
-  {at: 0.2, is: '20%'},
-  {at: 0.6, is: '40%'},
-  {at: 1, is: '60%'},
-  {at: 1.4, is: '80%'}
-]);
-assertAttributeInterpolation({
-  property: 'height',
-  underlying: '20em',
-  from: '10em',
-  fromComposite: 'replace',
-  to: '40em',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '0em'},
-  {at: 0, is: '10em'},
-  {at: 0.2, is: '20em'},
-  {at: 0.6, is: '40em'},
-  {at: 1, is: '60em'},
-  {at: 1.4, is: '80em'}
-]);
-assertAttributeInterpolation({
-  property: 'height',
-  underlying: '20ex',
-  from: '10ex',
-  fromComposite: 'replace',
-  to: '40ex',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '0ex'},
-  {at: 0, is: '10ex'},
-  {at: 0.2, is: '20ex'},
-  {at: 0.6, is: '40ex'},
-  {at: 1, is: '60ex'},
-  {at: 1.4, is: '80ex'}
-]);
-assertAttributeInterpolation({
-  property: 'height',
-  underlying: '20rem',
-  from: '10rem',
-  fromComposite: 'replace',
-  to: '40rem',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '0rem'},
-  {at: 0, is: '10rem'},
-  {at: 0.2, is: '20rem'},
-  {at: 0.6, is: '40rem'},
-  {at: 1, is: '60rem'},
-  {at: 1.4, is: '80rem'}
-]);
-
-assertAttributeInterpolation({
-  property: 'height',
-  underlying: '10',
-  from: neutralKeyframe,
-  to: '60',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 10},
-  {at: 0.2, is: 20},
-  {at: 0.6, is: 40},
-  {at: 1, is: 60},
-  {at: 1.4, is: 80}
-]);
-assertAttributeInterpolation({
-  property: 'height',
-  underlying: '10%',
-  from: neutralKeyframe,
-  to: '60%',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: '0%'},
-  {at: 0, is: '10%'},
-  {at: 0.2, is: '20%'},
-  {at: 0.6, is: '40%'},
-  {at: 1, is: '60%'},
-  {at: 1.4, is: '80%'}
-]);
-assertAttributeInterpolation({
-  property: 'height',
-  underlying: '10em',
-  from: neutralKeyframe,
-  to: '60em',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: '0em'},
-  {at: 0, is: '10em'},
-  {at: 0.2, is: '20em'},
-  {at: 0.6, is: '40em'},
-  {at: 1, is: '60em'},
-  {at: 1.4, is: '80em'}
-]);
-assertAttributeInterpolation({
-  property: 'height',
-  underlying: '10ex',
-  from: neutralKeyframe,
-  to: '60ex',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: '0ex'},
-  {at: 0, is: '10ex'},
-  {at: 0.2, is: '20ex'},
-  {at: 0.6, is: '40ex'},
-  {at: 1, is: '60ex'},
-  {at: 1.4, is: '80ex'}
-]);
-assertAttributeInterpolation({
-  property: 'height',
-  underlying: '10rem',
-  from: neutralKeyframe,
-  to: '60rem',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: '0rem'},
-  {at: 0, is: '10rem'},
-  {at: 0.2, is: '20rem'},
-  {at: 0.6, is: '40rem'},
-  {at: 1, is: '60rem'},
-  {at: 1.4, is: '80rem'}
-]);
-
-// Mixed units
-
-assertAttributeInterpolation({
-  property: 'height',
-  underlying: '10',
-  from: '10mm',
-  fromComposite: 'add',
-  to: '20px',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '54.913387298583984'},
-  {at: 0, is: '47.79527559055118'},
-  {at: 0.2, is: '44.23622131347656'},
-  {at: 0.6, is: '37.11811065673828'},
-  {at: 1, is: '30px'},
-  {at: 1.4, is: '22.881889343261719'}
-]);
-assertAttributeInterpolation({
-  property: 'height',
-  underlying: '10mm',
-  from: '10mm',
-  fromComposite: 'add',
-  to: '20px',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '82.70866141732283'},
-  {at: 0, is: '20mm'},
-  {at: 0.2, is: '72.03149606299212'},
-  {at: 0.6, is: '64.91338582677164'},
-  {at: 1, is: '57.79527559055118'},
-  {at: 1.4, is: '50.677165354330704'}
-]);
-
-assertAttributeInterpolation({
-  property: 'height',
-  underlying: '10',
-  from: '10mm',
-  fromComposite: 'replace',
-  to: '10px',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '44.913387298583984'},
-  {at: 0, is: '10mm'},
-  {at: 0.2, is: '34.23622131347656'},
-  {at: 0.6, is: '27.11811065673828'},
-  {at: 1, is: '20px'},
-  {at: 1.4, is: '12.881889343261719'}
-]);
-assertAttributeInterpolation({
-  property: 'height',
-  underlying: '10mm',
-  from: '20mm',
-  fromComposite: 'replace',
-  to: '20px',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '82.70866141732283'},
-  {at: 0, is: '20mm'},
-  {at: 0.2, is: '72.03149606299212'},
-  {at: 0.6, is: '64.91338582677164'},
-  {at: 1, is: '57.79527559055118'},
-  {at: 1.4, is: '50.677165354330704'}
-]);
-
-assertAttributeInterpolation({
-  property: 'height',
-  underlying: '10',
-  from: neutralKeyframe,
-  to: '60px',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 10},
-  {at: 0.2, is: 20},
-  {at: 0.6, is: 40},
-  {at: 1, is: 60},
-  {at: 1.4, is: 80}
-]);
-assertAttributeInterpolation({
-  property: 'height',
-  underlying: '10mm',
-  from: neutralKeyframe,
-  to: '20px',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: '44.913387298583984'},
-  {at: 0, is: '10mm'},
-  {at: 0.2, is: '34.23622131347656'},
-  {at: 0.6, is: '27.11811065673828'},
-  {at: 1, is: '20px'},
-  {at: 1.4, is: '12.881889343261719'}
-]);
-
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-intercept-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-intercept-composition.html
deleted file mode 100644
index 584cc812..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-intercept-composition.html
+++ /dev/null
@@ -1,62 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="0" height="0">
-<feComponentTransfer>
-<feFuncR type="linear" class="target" />
-</feComponentTransfer>
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'intercept',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 2},
-  {at: 0, is: 4},
-  {at: 0.2, is: 5},
-  {at: 0.6, is: 7},
-  {at: 1, is: 9},
-  {at: 1.4, is: 11},
-]);
-
-assertAttributeInterpolation({
-  property: 'intercept',
-  underlying: '5',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: -3},
-  {at: 0, is: 1},
-  {at: 0.2, is: 3},
-  {at: 0.6, is: 7},
-  {at: 1, is: 11},
-  {at: 1.4, is: 15},
-]);
-
-assertAttributeInterpolation({
-  property: 'intercept',
-  underlying: '5',
-  from: neutralKeyframe,
-  to: '10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 3},
-  {at: 0, is: 5},
-  {at: 0.2, is: 6},
-  {at: 0.6, is: 8},
-  {at: 1, is: 10},
-  {at: 1.4, is: 12},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-k1-k2-k3-k4-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-k1-k2-k3-k4-composition.html
deleted file mode 100644
index 9cf243d8..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-k1-k2-k3-k4-composition.html
+++ /dev/null
@@ -1,201 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="0" height="0">
-<feComposite class="target" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'k1',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 2},
-  {at: 0, is: 4},
-  {at: 0.2, is: 5},
-  {at: 0.6, is: 7},
-  {at: 1, is: 9},
-  {at: 1.4, is: 11},
-]);
-
-assertAttributeInterpolation({
-  property: 'k1',
-  underlying: '5',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: -3},
-  {at: 0, is: 1},
-  {at: 0.2, is: 3},
-  {at: 0.6, is: 7},
-  {at: 1, is: 11},
-  {at: 1.4, is: 15},
-]);
-
-assertAttributeInterpolation({
-  property: 'k1',
-  underlying: '5',
-  from: neutralKeyframe,
-  to: '10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 3},
-  {at: 0, is: 5},
-  {at: 0.2, is: 6},
-  {at: 0.6, is: 8},
-  {at: 1, is: 10},
-  {at: 1.4, is: 12},
-]);
-
-assertAttributeInterpolation({
-  property: 'k2',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 2},
-  {at: 0, is: 4},
-  {at: 0.2, is: 5},
-  {at: 0.6, is: 7},
-  {at: 1, is: 9},
-  {at: 1.4, is: 11},
-]);
-
-assertAttributeInterpolation({
-  property: 'k2',
-  underlying: '5',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: -3},
-  {at: 0, is: 1},
-  {at: 0.2, is: 3},
-  {at: 0.6, is: 7},
-  {at: 1, is: 11},
-  {at: 1.4, is: 15},
-]);
-
-assertAttributeInterpolation({
-  property: 'k2',
-  underlying: '5',
-  from: neutralKeyframe,
-  to: '10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 3},
-  {at: 0, is: 5},
-  {at: 0.2, is: 6},
-  {at: 0.6, is: 8},
-  {at: 1, is: 10},
-  {at: 1.4, is: 12},
-]);
-
-assertAttributeInterpolation({
-  property: 'k3',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 2},
-  {at: 0, is: 4},
-  {at: 0.2, is: 5},
-  {at: 0.6, is: 7},
-  {at: 1, is: 9},
-  {at: 1.4, is: 11},
-]);
-
-assertAttributeInterpolation({
-  property: 'k3',
-  underlying: '5',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: -3},
-  {at: 0, is: 1},
-  {at: 0.2, is: 3},
-  {at: 0.6, is: 7},
-  {at: 1, is: 11},
-  {at: 1.4, is: 15},
-]);
-
-assertAttributeInterpolation({
-  property: 'k3',
-  underlying: '5',
-  from: neutralKeyframe,
-  to: '10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 3},
-  {at: 0, is: 5},
-  {at: 0.2, is: 6},
-  {at: 0.6, is: 8},
-  {at: 1, is: 10},
-  {at: 1.4, is: 12},
-]);
-
-assertAttributeInterpolation({
-  property: 'k4',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 2},
-  {at: 0, is: 4},
-  {at: 0.2, is: 5},
-  {at: 0.6, is: 7},
-  {at: 1, is: 9},
-  {at: 1.4, is: 11},
-]);
-
-assertAttributeInterpolation({
-  property: 'k4',
-  underlying: '5',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: -3},
-  {at: 0, is: 1},
-  {at: 0.2, is: 3},
-  {at: 0.6, is: 7},
-  {at: 1, is: 11},
-  {at: 1.4, is: 15},
-]);
-
-assertAttributeInterpolation({
-  property: 'k4',
-  underlying: '5',
-  from: neutralKeyframe,
-  to: '10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 3},
-  {at: 0, is: 5},
-  {at: 0.2, is: 6},
-  {at: 0.6, is: 8},
-  {at: 1, is: 10},
-  {at: 1.4, is: 12},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-kernelMatrix-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-kernelMatrix-composition.html
deleted file mode 100644
index 3b56733..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-kernelMatrix-composition.html
+++ /dev/null
@@ -1,111 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-  <defs>
-    <filter>
-      <feConvolveMatrix order="1, 3" class="target" />
-    </filter>
-  </defs>
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'kernelMatrix',
-  underlying: '10, 20',
-  from: '30, 40',
-  fromComposite: 'add',
-  to: '50, -10',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '32, 80'},
-  {at: 0, is: '40, 60'},
-  {at: 0.2, is: '44, 50'},
-  {at: 0.6, is: '52, 30'},
-  {at: 1, is: '60, 10'},
-  {at: 1.4, is: '68, -10'},
-]);
-
-assertAttributeInterpolation({
-  property: 'kernelMatrix',
-  underlying: '10, 20',
-  from: '30',
-  fromComposite: 'add',
-  to: '50',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '32, 20'},
-  {at: 0, is: '40, 20'},
-  {at: 0.2, is: '44, 20'},
-  {at: 0.6, is: '52, 20'},
-  {at: 1, is: '60, 20'},
-  {at: 1.4, is: '68, 20'},
-]);
-
-assertAttributeInterpolation({
-  property: 'kernelMatrix',
-  underlying: '10',
-  from: '20, 30, 40',
-  fromComposite: 'add',
-  to: '50, 40, 30',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '18, 26, 44'},
-  {at: 0, is: '30, 30, 40'},
-  {at: 0.2, is: '36, 32, 38'},
-  {at: 0.6, is: '48, 36, 34'},
-  {at: 1, is: '60, 40, 30'},
-  {at: 1.4, is: '72, 44, 26'},
-]);
-
-assertAttributeInterpolation({
-  property: 'kernelMatrix',
-  underlying: '10',
-  from: '30, 40',
-  fromComposite: 'add',
-  to: '50, 60, 70',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: '40, 40'},
-  {at: 0, is: '40, 40'},
-  {at: 0.2, is: '40, 40'},
-  {at: 0.6, is: '50, 60, 70'},
-  {at: 1, is: '50, 60, 70'},
-  {at: 1.4, is: '50, 60, 70'},
-]);
-
-assertAttributeInterpolation({
-  property: 'kernelMatrix',
-  underlying: '10',
-  from: neutralKeyframe,
-  to: '50, -10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: '10'},
-  {at: 0, is: '10'},
-  {at: 0.2, is: '10'},
-  {at: 0.6, is: '50, -10'},
-  {at: 1, is: '50, -10'},
-  {at: 1.4, is: '50, -10'},
-]);
-
-assertAttributeInterpolation({
-  property: 'kernelMatrix',
-  underlying: '10, 20',
-  from: neutralKeyframe,
-  to: '50, -10',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-10, 24'},
-  {at: 0, is: '10, 20'},
-  {at: 0.2, is: '20, 18'},
-  {at: 0.6, is: '40, 14'},
-  {at: 1, is: '60, 10'},
-  {at: 1.4, is: '80, 6'},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-kernelUnitLength-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-kernelUnitLength-composition.html
deleted file mode 100644
index 3169dc2..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-kernelUnitLength-composition.html
+++ /dev/null
@@ -1,139 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<feDiffuseLighting class="target" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'kernelUnitLength',
-  underlying: '0',
-  from: '1',
-  fromComposite: 'add',
-  to: '6 11',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-1, -3'},
-  {at: 0, is: '1, 1'},
-  {at: 0.2, is: '2, 3'},
-  {at: 0.6, is: '4, 7'},
-  {at: 1, is: '6, 11'},
-  {at: 1.4, is: '8, 15'},
-]);
-
-assertAttributeInterpolation({
-  property: 'kernelUnitLength',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6 11',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '2, 0'},
-  {at: 0, is: '4, 4'},
-  {at: 0.2, is: '5, 6'},
-  {at: 0.6, is: '7, 10'},
-  {at: 1, is: '9, 14'},
-  {at: 1.4, is: '11, 18'},
-]);
-
-assertAttributeInterpolation({
-  property: 'kernelUnitLength',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6 11',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-2.2, -4.2'},
-  {at: 0, is: '1, 1'},
-  {at: 0.2, is: '2.6, 3.6'},
-  {at: 0.6, is: '5.8, 8.8'},
-  {at: 1, is: '9, 14'},
-  {at: 1.4, is: '12.2, 19.2'},
-]);
-
-assertAttributeInterpolation({
-  property: 'kernelUnitLength',
-  underlying: '3',
-  from: neutralKeyframe,
-  to: '6 11',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: '1.8, -0.2'},
-  {at: 0, is: '3, 3'},
-  {at: 0.2, is: '3.6, 4.6'},
-  {at: 0.6, is: '4.8, 7.8'},
-  {at: 1, is: '6, 11'},
-  {at: 1.4, is: '7.2, 14.2'},
-]);
-
-assertAttributeInterpolation({
-  property: 'kernelUnitLength',
-  underlying: '0',
-  from: '-2 10',
-  fromComposite: 'add',
-  to: '3 10',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-4, 10'},
-  {at: 0, is: '-2, 10'},
-  {at: 0.2, is: '-1, 10'},
-  {at: 0.6, is: '1, 10'},
-  {at: 1, is: '3, 10'},
-  {at: 1.4, is: '5, 10'},
-]);
-
-assertAttributeInterpolation({
-  property: 'kernelUnitLength',
-  underlying: '3',
-  from: '-2 10',
-  fromComposite: 'add',
-  to: '3 10',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-1, 13'},
-  {at: 0, is: '1, 13'},
-  {at: 0.2, is: '2, 13'},
-  {at: 0.6, is: '4, 13'},
-  {at: 1, is: '6, 13'},
-  {at: 1.4, is: '8, 13'},
-]);
-
-assertAttributeInterpolation({
-  property: 'kernelUnitLength',
-  underlying: '3',
-  from: '-2 10',
-  fromComposite: 'replace',
-  to: '3 10',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-5.2, 8.8'},
-  {at: 0, is: '-2, 10'},
-  {at: 0.2, is: '-0.4, 10.6'},
-  {at: 0.6, is: '2.8, 11.8'},
-  {at: 1, is: '6, 13'},
-  {at: 1.4, is: '9.2, 14.2'},
-]);
-
-assertAttributeInterpolation({
-  property: 'kernelUnitLength',
-  underlying: '3',
-  from: neutralKeyframe,
-  to: '3 10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: '3, 0.2'},
-  {at: 0, is: '3, 3'},
-  {at: 0.2, is: '3, 4.4'},
-  {at: 0.6, is: '3, 7.2'},
-  {at: 1, is: '3, 10'},
-  {at: 1.4, is: '3, 12.8'},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-limitingConeAngle-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-limitingConeAngle-composition.html
deleted file mode 100644
index 6489402..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-limitingConeAngle-composition.html
+++ /dev/null
@@ -1,64 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="0" height="0">
-<filter>
-<defs>
-<feSpotLight class="target" />
-</defs>
-</filter>
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'limitingConeAngle',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 2},
-  {at: 0, is: 4},
-  {at: 0.2, is: 5},
-  {at: 0.6, is: 7},
-  {at: 1, is: 9},
-  {at: 1.4, is: 11},
-]);
-
-assertAttributeInterpolation({
-  property: 'limitingConeAngle',
-  underlying: '5',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: -3},
-  {at: 0, is: 1},
-  {at: 0.2, is: 3},
-  {at: 0.6, is: 7},
-  {at: 1, is: 11},
-  {at: 1.4, is: 15},
-]);
-
-assertAttributeInterpolation({
-  property: 'limitingConeAngle',
-  underlying: '5',
-  from: neutralKeyframe,
-  to: '10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 3},
-  {at: 0, is: 5},
-  {at: 0.2, is: 6},
-  {at: 0.6, is: 8},
-  {at: 1, is: 10},
-  {at: 1.4, is: 12},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-markerHeight-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-markerHeight-composition.html
deleted file mode 100644
index 8dae1625..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-markerHeight-composition.html
+++ /dev/null
@@ -1,156 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script src="../../resources/ahem.js"></script>
-<style>
-:root {
-  font: 10px Ahem;
-}
-</style>
-</head>
-<body>
-<template id="target-template">
-<svg width="200px" height="300px" viewBox="0 0 1500 1000">
-  <marker class="target" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'markerHeight',
-  underlying: '2',
-  from: '-1',
-  fromComposite: 'add',
-  to: '4',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-assertAttributeInterpolation({
-  property: 'markerHeight',
-  underlying: '1in',
-  from: '9in',
-  fromComposite: 'add',
-  to: '698pt',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '700pt'},
-  {at: 0, is: '720pt'},
-  {at: 0.2, is: '730pt'},
-  {at: 0.6, is: '750pt'},
-  {at: 1, is: '770pt'},
-  {at: 1.4, is: '790pt'}
-]);
-assertAttributeInterpolation({
-  property: 'markerHeight',
-  underlying: '10',
-  from: '10',
-  fromComposite: 'add',
-  to: '19em',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '0'},
-  {at: 0, is: '20'},
-  {at: 0.2, is: '56'},
-  {at: 0.6, is: '128'},
-  {at: 1, is: '200'},
-  {at: 1.4, is: '272'}
-]);
-
-assertAttributeInterpolation({
-  property: 'markerHeight',
-  underlying: '2',
-  from: '1',
-  fromComposite: 'replace',
-  to: '4',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-assertAttributeInterpolation({
-  property: 'markerHeight',
-  underlying: '1in',
-  from: '10in',
-  fromComposite: 'replace',
-  to: '698pt',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '700pt'},
-  {at: 0, is: '720pt'},
-  {at: 0.2, is: '730pt'},
-  {at: 0.6, is: '750pt'},
-  {at: 1, is: '770pt'},
-  {at: 1.4, is: '790pt'}
-]);
-assertAttributeInterpolation({
-  property: 'markerHeight',
-  underlying: '5em',
-  from: '10',
-  fromComposite: 'replace',
-  to: '5em',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '0'},
-  {at: 0, is: '10'},
-  {at: 0.2, is: '28'},
-  {at: 0.6, is: '64'},
-  {at: 1, is: '100'},
-  {at: 1.4, is: '136'}
-]);
-
-assertAttributeInterpolation({
-  property: 'markerHeight',
-  underlying: '1',
-  from: neutralKeyframe,
-  to: '6',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-assertAttributeInterpolation({
-  property: 'markerHeight',
-  underlying: '10in',
-  from: neutralKeyframe,
-  to: '770pt',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: '700pt'},
-  {at: 0, is: '720pt'},
-  {at: 0.2, is: '730pt'},
-  {at: 0.6, is: '750pt'},
-  {at: 1, is: '770pt'},
-  {at: 1.4, is: '790pt'}
-]);
-assertAttributeInterpolation({
-  property: 'markerHeight',
-  underlying: '10',
-  from: neutralKeyframe,
-  to: '10em',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: '0'},
-  {at: 0, is: '10'},
-  {at: 0.2, is: '28'},
-  {at: 0.6, is: '64'},
-  {at: 1, is: '100'},
-  {at: 1.4, is: '136'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-markerWidth-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-markerWidth-composition.html
deleted file mode 100644
index e440370..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-markerWidth-composition.html
+++ /dev/null
@@ -1,156 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script src="../../resources/ahem.js"></script>
-<style>
-:root {
-  font: 10px Ahem;
-}
-</style>
-</head>
-<body>
-<template id="target-template">
-<svg width="200px" height="300px" viewBox="0 0 1500 1000">
-  <marker class="target" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'markerWidth',
-  underlying: '2',
-  from: '-1',
-  fromComposite: 'add',
-  to: '4',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-assertAttributeInterpolation({
-  property: 'markerWidth',
-  underlying: '1in',
-  from: '9in',
-  fromComposite: 'add',
-  to: '698pt',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '700pt'},
-  {at: 0, is: '720pt'},
-  {at: 0.2, is: '730pt'},
-  {at: 0.6, is: '750pt'},
-  {at: 1, is: '770pt'},
-  {at: 1.4, is: '790pt'}
-]);
-assertAttributeInterpolation({
-  property: 'markerWidth',
-  underlying: '10',
-  from: '10',
-  fromComposite: 'add',
-  to: '19em',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '0'},
-  {at: 0, is: '20'},
-  {at: 0.2, is: '56'},
-  {at: 0.6, is: '128'},
-  {at: 1, is: '200'},
-  {at: 1.4, is: '272'}
-]);
-
-assertAttributeInterpolation({
-  property: 'markerWidth',
-  underlying: '2',
-  from: '1',
-  fromComposite: 'replace',
-  to: '4',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-assertAttributeInterpolation({
-  property: 'markerWidth',
-  underlying: '1in',
-  from: '10in',
-  fromComposite: 'replace',
-  to: '698pt',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '700pt'},
-  {at: 0, is: '720pt'},
-  {at: 0.2, is: '730pt'},
-  {at: 0.6, is: '750pt'},
-  {at: 1, is: '770pt'},
-  {at: 1.4, is: '790pt'}
-]);
-assertAttributeInterpolation({
-  property: 'markerWidth',
-  underlying: '5em',
-  from: '10',
-  fromComposite: 'replace',
-  to: '5em',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '0'},
-  {at: 0, is: '10'},
-  {at: 0.2, is: '28'},
-  {at: 0.6, is: '64'},
-  {at: 1, is: '100'},
-  {at: 1.4, is: '136'}
-]);
-
-assertAttributeInterpolation({
-  property: 'markerWidth',
-  underlying: '1',
-  from: neutralKeyframe,
-  to: '6',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-assertAttributeInterpolation({
-  property: 'markerWidth',
-  underlying: '10in',
-  from: neutralKeyframe,
-  to: '770pt',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: '700pt'},
-  {at: 0, is: '720pt'},
-  {at: 0.2, is: '730pt'},
-  {at: 0.6, is: '750pt'},
-  {at: 1, is: '770pt'},
-  {at: 1.4, is: '790pt'}
-]);
-assertAttributeInterpolation({
-  property: 'markerWidth',
-  underlying: '10',
-  from: neutralKeyframe,
-  to: '10em',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: '0'},
-  {at: 0, is: '10'},
-  {at: 0.2, is: '28'},
-  {at: 0.6, is: '64'},
-  {at: 1, is: '100'},
-  {at: 1.4, is: '136'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-mode-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-mode-composition.html
deleted file mode 100644
index f4245407..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-mode-composition.html
+++ /dev/null
@@ -1,44 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="0" height="0">
-<feBlend class="target" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'mode',
-  underlying: 'multiply',
-  from: 'screen',
-  fromComposite: 'add',
-  to: 'lighten',
-  toComposite: 'add',
-}, [
-  {at: -2.4, is: 'screen'},
-  {at: 0, is: 'screen'},
-  {at: 0.2, is: 'screen'},
-  {at: 0.6, is: 'lighten'},
-  {at: 1, is: 'lighten'},
-  {at: 3.4, is: 'lighten'}
-]);
-
-assertAttributeInterpolation({
-  property: 'mode',
-  underlying: 'multiply',
-  from: neutralKeyframe,
-  to: 'lighten',
-  toComposite: 'replace',
-}, [
-  {at: -2.4, is: 'multiply'},
-  {at: 0, is: 'multiply'},
-  {at: 0.2, is: 'multiply'},
-  {at: 0.6, is: 'lighten'},
-  {at: 1, is: 'lighten'},
-  {at: 3.4, is: 'lighten'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-numOctaves-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-numOctaves-composition.html
deleted file mode 100644
index 043e8ad..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-numOctaves-composition.html
+++ /dev/null
@@ -1,76 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="0" height="0">
-<feTurbulence class="target" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'numOctaves',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '7',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 2},
-  {at: 0, is: 4},
-  {at: 0.2, is: 5},
-  {at: 0.6, is: 8},
-  {at: 1, is: 10},
-  {at: 1.4, is: 12}
-]);
-
-assertAttributeInterpolation({
-  property: 'numOctaves',
-  underlying: '5',
-  from: '1',
-  fromComposite: 'replace',
-  to: '7',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: -3},
-  {at: 0, is: 1},
-  {at: 0.2, is: 3},
-  {at: 0.6, is: 8},
-  {at: 1, is: 12},
-  {at: 1.4, is: 16}
-]);
-
-assertAttributeInterpolation({
-  property: 'numOctaves',
-  underlying: '2',
-  from: '1',
-  fromComposite: 'add',
-  to: '7',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 1},
-  {at: 0, is: 3},
-  {at: 0.2, is: 4},
-  {at: 0.6, is: 5},
-  {at: 1, is: 7},
-  {at: 1.4, is: 9}
-]);
-
-assertAttributeInterpolation({
-  property: 'numOctaves',
-  underlying: '2',
-  from: neutralKeyframe,
-  to: '7',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 2},
-  {at: 0.2, is: 3},
-  {at: 0.6, is: 5},
-  {at: 1, is: 7},
-  {at: 1.4, is: 9}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-offset-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-offset-composition.html
deleted file mode 100644
index 3349620..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-offset-composition.html
+++ /dev/null
@@ -1,60 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="0" height="0">
-<stop class="target" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'offset',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 2},
-  {at: 0, is: 4},
-  {at: 0.2, is: 5},
-  {at: 0.6, is: 7},
-  {at: 1, is: 9},
-  {at: 1.4, is: 11},
-]);
-
-assertAttributeInterpolation({
-  property: 'offset',
-  underlying: '5',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: -3},
-  {at: 0, is: 1},
-  {at: 0.2, is: 3},
-  {at: 0.6, is: 7},
-  {at: 1, is: 11},
-  {at: 1.4, is: 15},
-]);
-
-assertAttributeInterpolation({
-  property: 'offset',
-  underlying: '5',
-  from: neutralKeyframe,
-  to: '10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 3},
-  {at: 0, is: 5},
-  {at: 0.2, is: 6},
-  {at: 0.6, is: 8},
-  {at: 1, is: 10},
-  {at: 1.4, is: 12},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-order-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-order-composition.html
deleted file mode 100644
index ff5ecb8d..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-order-composition.html
+++ /dev/null
@@ -1,64 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="0" height="0">
-  <defs>
-    <filter>
-      <feConvolveMatrix kernelMatrix="100 200 300 400" class="target" />
-    </filter>
-  </defs>
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'order',
-  underlying: '1',
-  from: '1, 6',
-  fromComposite: 'add',
-  to: '3, 4',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '1, 8'},
-  {at: 0, is: '2, 7'},
-  {at: 0.2, is: '2, 7'},
-  {at: 0.6, is: '3, 6'},
-  {at: 1, is: '4, 5'},
-  {at: 1.4, is: '5, 4'},
-]);
-
-assertAttributeInterpolation({
-  property: 'order',
-  underlying: '3',
-  from: '1, 3',
-  fromComposite: 'replace',
-  to: '3',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '1, 2'},
-  {at: 0, is: '1, 3'},
-  {at: 0.2, is: '2, 4'},
-  {at: 0.6, is: '4, 5'},
-  {at: 1, is: '6, 6'},
-  {at: 1.4, is: '8, 7'},
-]);
-
-assertAttributeInterpolation({
-  property: 'order',
-  underlying: '3, 5',
-  from: neutralKeyframe,
-  to: '1',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: '4, 7'},
-  {at: 0, is: '3, 5'},
-  {at: 0.2, is: '3, 4'},
-  {at: 0.6, is: '2, 3'},
-  {at: 1, is: '1, 1'},
-  {at: 1.4, is: '1, 1'},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-orient-composition-expected.txt b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-orient-composition-expected.txt
deleted file mode 100644
index 4ea5b62..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-orient-composition-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-[FAIL] SMIL: Interpolate attribute <orient> with underlying [50] from add [90deg] to add [auto] at (0) is [140]
-  assert_equals: expected "140 " but got "90 "
-[FAIL] SMIL: Interpolate attribute <orient> with underlying [50] from add [90deg] to add [auto] at (0.2) is [140]
-  assert_equals: expected "140 " but got "90 "
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-orient-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-orient-composition.html
deleted file mode 100644
index 1a8d969..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-orient-composition.html
+++ /dev/null
@@ -1,75 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<defs>
-<marker class="target" />
-</defs>
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'orient',
-  underlying: '50',
-  from: '130',
-  fromComposite: 'add',
-  to: '200grad', // 180deg
-  toComposite: 'add'
-}, [
-  {at: -3, is: 30},
-  {at: 0, is: 180},
-  {at: 0.2, is: 190},
-  {at: 0.6, is: 210},
-  {at: 1, is: 230},
-  {at: 1.4, is: 250}
-]);
-assertAttributeInterpolation({
-  property: 'orient',
-  underlying: '50',
-  from: '90deg',
-  fromComposite: 'add',
-  to: 'auto',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 140},
-  {at: 0, is: 140},
-  {at: 0.2, is: 140},
-  {at: 0.6, is: 'auto'},
-  {at: 1, is: 'auto'},
-  {at: 1.4, is: 'auto'}
-]);
-assertAttributeInterpolation({
-  property: 'orient',
-  underlying: '20',
-  from: '120',
-  fromComposite: 'replace',
-  to: '180',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 88},
-  {at: 0, is: 120},
-  {at: 0.2, is: 136},
-  {at: 0.6, is: 168},
-  {at: 1, is: 200},
-  {at: 1.4, is: 232}
-]);
-assertAttributeInterpolation({
-  property: 'orient',
-  underlying: '20',
-  from: neutralKeyframe,
-  to: '180',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: -44},
-  {at: 0, is: 20},
-  {at: 0.2, is: 52},
-  {at: 0.6, is: 116},
-  {at: 1, is: 180},
-  {at: 1.4, is: 244}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-pathLength-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-pathLength-composition.html
deleted file mode 100644
index d8b095f..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-pathLength-composition.html
+++ /dev/null
@@ -1,60 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0">
-<path d="M 100 200 L 300 400" class="target" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'pathLength',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 2},
-  {at: 0, is: 4},
-  {at: 0.2, is: 5},
-  {at: 0.6, is: 7},
-  {at: 1, is: 9},
-  {at: 1.4, is: 11},
-]);
-
-assertAttributeInterpolation({
-  property: 'pathLength',
-  underlying: '5',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 1},
-  {at: 0.2, is: 3},
-  {at: 0.6, is: 7},
-  {at: 1, is: 11},
-  {at: 1.4, is: 15},
-]);
-
-assertAttributeInterpolation({
-  property: 'pathLength',
-  underlying: '5',
-  from: neutralKeyframe,
-  to: '10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 3},
-  {at: 0, is: 5},
-  {at: 0.2, is: 6},
-  {at: 0.6, is: 8},
-  {at: 1, is: 10},
-  {at: 1.4, is: 12},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-patternTransform-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-patternTransform-composition.html
deleted file mode 100644
index 92b554b..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-patternTransform-composition.html
+++ /dev/null
@@ -1,250 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<pattern class="target" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-
-assertAttributeInterpolation({
-  property: 'patternTransform',
-  underlying: 'translate(10 10)',
-  from: 'translate(0 10)',
-  fromComposite: 'add',
-  to: 'translate(20 50)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'translate(10,10) translate(-8,-6)'},
-  {at: 0, is: 'translate(10,10) translate(0,10)'},
-  {at: 0.2, is: 'translate(10,10) translate(4,18)'},
-  {at: 0.6, is: 'translate(10,10) translate(12,34)'},
-  {at: 1, is: 'translate(10,10) translate(20,50)'},
-  {at: 1.4, is: 'translate(10,10) translate(28,66)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'patternTransform',
-  underlying: 'translate(10 10)',
-  from: 'translate(10 20)',
-  fromComposite: 'replace',
-  to: 'translate(20 50)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'translate(10 20)'},
-  {at: 0, is: 'translate(10 20)'},
-  {at: 0.2, is: 'translate(10 20)'},
-  {at: 0.6, is: 'translate(10 10) translate(20 50)'},
-  {at: 1, is: 'translate(10 10) translate(20 50)'},
-  {at: 1.4, is: 'translate(10 10) translate(20 50)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'patternTransform',
-  underlying: 'translate(10 20)',
-  from: neutralKeyframe,
-  to: 'translate(30 60)',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: 'translate(2,4)'},
-  {at: 0, is: 'translate(10,20)'},
-  {at: 0.2, is: 'translate(14,28)'},
-  {at: 0.6, is: 'translate(22,44)'},
-  {at: 1, is: 'translate(30,60)'},
-  {at: 1.4, is: 'translate(38,76)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'patternTransform',
-  underlying: 'scale(10 5)',
-  from: 'scale(10 10)',
-  fromComposite: 'add',
-  to: 'scale(20 50)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'scale(10 5) scale(6 -6)'},
-  {at: 0, is: 'scale(10 5) scale(10 10)'},
-  {at: 0.2, is: 'scale(10 5) scale(12 18)'},
-  {at: 0.6, is: 'scale(10 5) scale(16 34)'},
-  {at: 1, is: 'scale(10 5) scale(20 50)'},
-  {at: 1.4, is: 'scale(10 5) scale(24 66)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'patternTransform',
-  underlying: 'scale(10 5)',
-  from: 'scale(10 10)',
-  fromComposite: 'replace',
-  to: 'scale(20 50)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'scale(10 10)'},
-  {at: 0, is: 'scale(10 10)'},
-  {at: 0.2, is: 'scale(10 10)'},
-  {at: 0.6, is: 'scale(10 5) scale(20 50)'},
-  {at: 1, is: 'scale(10 5) scale(20 50)'},
-  {at: 1.4, is: 'scale(10 5) scale(20 50)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'patternTransform',
-  underlying: 'scale(10 10)',
-  from: neutralKeyframe,
-  to: 'scale(20 50)',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: 'scale(6 -6)'},
-  {at: 0, is: 'scale(10 10)'},
-  {at: 0.2, is: 'scale(12 18)'},
-  {at: 0.6, is: 'scale(16 34)'},
-  {at: 1, is: 'scale(20 50)'},
-  {at: 1.4, is: 'scale(24 66)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'patternTransform',
-  underlying: 'rotate(10 10 10)',
-  from: 'rotate(10 20 30)',
-  fromComposite: 'add',
-  to: 'rotate(40 80 160)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'rotate(10 10 10) rotate(-2 -4 -22)'},
-  {at: 0, is: 'rotate(10 10 10) rotate(10 20 30)'},
-  {at: 0.2, is: 'rotate(10 10 10) rotate(16 32 56)'},
-  {at: 0.6, is: 'rotate(10 10 10) rotate(28 56 108)'},
-  {at: 1, is: 'rotate(10 10 10) rotate(40 80 160)'},
-  {at: 1.4, is: 'rotate(10 10 10) rotate(52 104 212)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'patternTransform',
-  underlying: 'rotate(10 10 10)',
-  from: 'rotate(10 20 30)',
-  fromComposite: 'replace',
-  to: 'rotate(40 80 160)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'rotate(10 20 30)'},
-  {at: 0, is: 'rotate(10 20 30)'},
-  {at: 0.2, is: 'rotate(10 20 30)'},
-  {at: 0.6, is: 'rotate(10 10 10) rotate(40 80 160)'},
-  {at: 1, is: 'rotate(10 10 10) rotate(40 80 160)'},
-  {at: 1.4, is: 'rotate(10 10 10) rotate(40 80 160)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'patternTransform',
-  underlying: 'rotate(10 20 30)',
-  from: neutralKeyframe,
-  to: 'rotate(40 80 160)',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: 'rotate(-2 -4 -22)'},
-  {at: 0, is: 'rotate(10 20 30)'},
-  {at: 0.2, is: 'rotate(16 32 56)'},
-  {at: 0.6, is: 'rotate(28 56 108)'},
-  {at: 1, is: 'rotate(40 80 160)'},
-  {at: 1.4, is: 'rotate(52 104 212)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'patternTransform',
-  underlying: 'skewX(10)',
-  from: 'skewX(30)',
-  fromComposite: 'add',
-  to: 'skewX(50)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'skewX(10) skewX(22)'},
-  {at: 0, is: 'skewX(10) skewX(30)'},
-  {at: 0.2, is: 'skewX(10) skewX(34)'},
-  {at: 0.6, is: 'skewX(10) skewX(42)'},
-  {at: 1, is: 'skewX(10) skewX(50)'},
-  {at: 1.4, is: 'skewX(10) skewX(58)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'patternTransform',
-  underlying: 'skewX(10)',
-  from: 'skewX(30)',
-  fromComposite: 'replace',
-  to: 'skewX(50)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'skewX(30)'},
-  {at: 0, is: 'skewX(30)'},
-  {at: 0.2, is: 'skewX(30)'},
-  {at: 0.6, is: 'skewX(10) skewX(50)'},
-  {at: 1, is: 'skewX(10) skewX(50)'},
-  {at: 1.4, is: 'skewX(10) skewX(50)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'patternTransform',
-  underlying: 'skewX(30)',
-  from: neutralKeyframe,
-  to: 'skewX(50)',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: 'skewX(22)'},
-  {at: 0, is: 'skewX(30)'},
-  {at: 0.2, is: 'skewX(34)'},
-  {at: 0.6, is: 'skewX(42)'},
-  {at: 1, is: 'skewX(50)'},
-  {at: 1.4, is: 'skewX(58)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'patternTransform',
-  underlying: 'skewY(10)',
-  from: 'skewY(30)',
-  fromComposite: 'add',
-  to: 'skewY(50)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'skewY(10) skewY(22)'},
-  {at: 0, is: 'skewY(10) skewY(30)'},
-  {at: 0.2, is: 'skewY(10) skewY(34)'},
-  {at: 0.6, is: 'skewY(10) skewY(42)'},
-  {at: 1, is: 'skewY(10) skewY(50)'},
-  {at: 1.4, is: 'skewY(10) skewY(58)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'patternTransform',
-  underlying: 'skewY(10)',
-  from: 'skewY(30)',
-  fromComposite: 'replace',
-  to: 'skewY(50)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'skewY(30)'},
-  {at: 0, is: 'skewY(30)'},
-  {at: 0.2, is: 'skewY(30)'},
-  {at: 0.6, is: 'skewY(10) skewY(50)'},
-  {at: 1, is: 'skewY(10) skewY(50)'},
-  {at: 1.4, is: 'skewY(10) skewY(50)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'patternTransform',
-  underlying: 'skewY(30)',
-  from: neutralKeyframe,
-  to: 'skewY(50)',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: 'skewY(22)'},
-  {at: 0, is: 'skewY(30)'},
-  {at: 0.2, is: 'skewY(34)'},
-  {at: 0.6, is: 'skewY(42)'},
-  {at: 1, is: 'skewY(50)'},
-  {at: 1.4, is: 'skewY(58)'}
-]);
-
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-points-composition-expected.txt b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-points-composition-expected.txt
deleted file mode 100644
index f5965e5..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-points-composition-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-[FAIL] SMIL: Interpolate attribute <points> with underlying [10 10, 20 20] from add [40 40, 30 30] to add [90 90, -10 -10, 50 50] at (0) is [50 50, 50 50]
-  assert_equals: expected "50 , 50 , 50 , 50 " but got "40 , 40 , 30 , 30 "
-[FAIL] SMIL: Interpolate attribute <points> with underlying [10 10, 20 20] from add [40 40, 30 30] to add [90 90, -10 -10, 50 50] at (0.2) is [50 50, 50 50]
-  assert_equals: expected "50 , 50 , 50 , 50 " but got "40 , 40 , 30 , 30 "
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-points-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-points-composition.html
deleted file mode 100644
index 43fcb6222..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-points-composition.html
+++ /dev/null
@@ -1,139 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="0" height="0">
-<polygon class="target" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'points',
-  underlying: '10 10, 20 20',
-  from: '40 40, 30 30',
-  fromComposite: 'add',
-  to: '90 90, -10 -10',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '30 30, 66 66'},
-  {at: 0, is: '50 50, 50 50'},
-  {at: 0.2, is: '60 60, 42 42'},
-  {at: 0.6, is: '80 80, 26 26'},
-  {at: 1, is: '100 100, 10 10'},
-  {at: 1.4, is: '120 120, -6 -6'},
-]);
-
-assertAttributeInterpolation({
-  property: 'points',
-  underlying: '10 10, 20 20',
-  from: '40 40, 30 30',
-  fromComposite: 'add',
-  to: '90 90, -10 -10, 50 50',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '50 50, 50 50'},
-  {at: 0, is: '50 50, 50 50'},
-  {at: 0.2, is: '50 50, 50 50'},
-  {at: 0.6, is: '90 90, -10 -10, 50 50'},
-  {at: 1, is: '90 90, -10 -10, 50 50'},
-  {at: 1.4, is: '90 90, -10 -10, 50 50'},
-]);
-
-assertAttributeInterpolation({
-  property: 'points',
-  underlying: '10 10, 20 20, 50 50',
-  from: '40 40',
-  fromComposite: 'add',
-  to: '90 90, -10 -10',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '40 40'},
-  {at: 0, is: '40 40'},
-  {at: 0.2, is: '40 40'},
-  {at: 0.6, is: '90 90, -10 -10'},
-  {at: 1, is: '90 90, -10 -10'},
-  {at: 1.4, is: '90 90, -10 -10'},
-]);
-
-assertAttributeInterpolation({
-  property: 'points',
-  underlying: '10 10, 20 20',
-  from: '40 40, 30 30',
-  fromComposite: 'add',
-  to: '90 90, -10 -10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: '34 34, 74 74'},
-  {at: 0, is: '50 50, 50 50'},
-  {at: 0.2, is: '58 58, 38 38'},
-  {at: 0.6, is: '74 74, 14 14'},
-  {at: 1, is: '90 90, -10 -10'},
-  {at: 1.4, is: '106 106, -34 -34'},
-]);
-
-assertAttributeInterpolation({
-  property: 'points',
-  underlying: '10 10, 20 20',
-  from: '40 40, 30 30',
-  fromComposite: 'add',
-  to: '90 90, -10 -10, 50 50',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: '50 50, 50 50'},
-  {at: 0, is: '50 50, 50 50'},
-  {at: 0.2, is: '50 50, 50 50'},
-  {at: 0.6, is: '90 90, -10 -10, 50 50'},
-  {at: 1, is: '90 90, -10 -10, 50 50'},
-  {at: 1.4, is: '90 90, -10 -10, 50 50'},
-]);
-
-assertAttributeInterpolation({
-  property: 'points',
-  underlying: '10 10, 20 20, 50 50',
-  from: '40 40',
-  fromComposite: 'add',
-  to: '90 90, -10 -10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: '40 40'},
-  {at: 0, is: '40 40'},
-  {at: 0.2, is: '40 40'},
-  {at: 0.6, is: '90 90, -10 -10'},
-  {at: 1, is: '90 90, -10 -10'},
-  {at: 1.4, is: '90 90, -10 -10'},
-]);
-
-assertAttributeInterpolation({
-  property: 'points',
-  underlying: '10 10, 20 20',
-  from: neutralKeyframe,
-  to: '90 90, -10 -10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: '-22 -22, 32 32'},
-  {at: 0, is: '10 10, 20 20'},
-  {at: 0.2, is: '26 26, 14 14'},
-  {at: 0.6, is: '58 58, 2 2'},
-  {at: 1, is: '90 90, -10 -10'},
-  {at: 1.4, is: '122 122, -22 -22'},
-]);
-
-assertAttributeInterpolation({
-  property: 'points',
-  underlying: '10 10, 20 20',
-  from: neutralKeyframe,
-  to: '90 90, -10 -10, 50 50',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: '10 10, 20 20'},
-  {at: 0, is: '10 10, 20 20'},
-  {at: 0.2, is: '10 10, 20 20'},
-  {at: 0.6, is: '90 90, -10 -10, 50 50'},
-  {at: 1, is: '90 90, -10 -10, 50 50'},
-  {at: 1.4, is: '90 90, -10 -10, 50 50'},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-pointsAtX-pointsAtY-pointsAtZ-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-pointsAtX-pointsAtY-pointsAtZ-composition.html
deleted file mode 100644
index cec17a59..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-pointsAtX-pointsAtY-pointsAtZ-composition.html
+++ /dev/null
@@ -1,154 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="0" height="0">
-<feSpotLight class="target" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'pointsAtX',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 2},
-  {at: 0, is: 4},
-  {at: 0.2, is: 5},
-  {at: 0.6, is: 7},
-  {at: 1, is: 9},
-  {at: 1.4, is: 11},
-]);
-
-assertAttributeInterpolation({
-  property: 'pointsAtX',
-  underlying: '5',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: -3},
-  {at: 0, is: 1},
-  {at: 0.2, is: 3},
-  {at: 0.6, is: 7},
-  {at: 1, is: 11},
-  {at: 1.4, is: 15},
-]);
-
-assertAttributeInterpolation({
-  property: 'pointsAtX',
-  underlying: '5',
-  from: neutralKeyframe,
-  to: '10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 3},
-  {at: 0, is: 5},
-  {at: 0.2, is: 6},
-  {at: 0.6, is: 8},
-  {at: 1, is: 10},
-  {at: 1.4, is: 12},
-]);
-
-assertAttributeInterpolation({
-  property: 'pointsAtY',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 2},
-  {at: 0, is: 4},
-  {at: 0.2, is: 5},
-  {at: 0.6, is: 7},
-  {at: 1, is: 9},
-  {at: 1.4, is: 11},
-]);
-
-assertAttributeInterpolation({
-  property: 'pointsAtY',
-  underlying: '5',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: -3},
-  {at: 0, is: 1},
-  {at: 0.2, is: 3},
-  {at: 0.6, is: 7},
-  {at: 1, is: 11},
-  {at: 1.4, is: 15},
-]);
-
-assertAttributeInterpolation({
-  property: 'pointsAtY',
-  underlying: '5',
-  from: neutralKeyframe,
-  to: '10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 3},
-  {at: 0, is: 5},
-  {at: 0.2, is: 6},
-  {at: 0.6, is: 8},
-  {at: 1, is: 10},
-  {at: 1.4, is: 12},
-]);
-
-assertAttributeInterpolation({
-  property: 'pointsAtZ',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 2},
-  {at: 0, is: 4},
-  {at: 0.2, is: 5},
-  {at: 0.6, is: 7},
-  {at: 1, is: 9},
-  {at: 1.4, is: 11},
-]);
-
-assertAttributeInterpolation({
-  property: 'pointsAtZ',
-  underlying: '5',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: -3},
-  {at: 0, is: 1},
-  {at: 0.2, is: 3},
-  {at: 0.6, is: 7},
-  {at: 1, is: 11},
-  {at: 1.4, is: 15},
-]);
-
-assertAttributeInterpolation({
-  property: 'pointsAtZ',
-  underlying: '5',
-  from: neutralKeyframe,
-  to: '10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 3},
-  {at: 0, is: 5},
-  {at: 0.2, is: 6},
-  {at: 0.6, is: 8},
-  {at: 1, is: 10},
-  {at: 1.4, is: 12},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-r-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-r-composition.html
deleted file mode 100644
index 20d1c4b..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-r-composition.html
+++ /dev/null
@@ -1,155 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<style>
-:root {
-  font: 10px Ahem;
-}
-</style>
-</head>
-<body>
-<template id="target-template">
-<svg width="7px" height="17px" viewBox="0 0 140 340">
-<circle class="target" cx="70" cy="70" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'r',
-  underlying: '5ch',
-  from: '5ch',
-  fromComposite: 'add',
-  to: '55ch',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '0ch'},
-  {at: 0, is: '10ch'},
-  {at: 0.2, is: '20ch'},
-  {at: 0.6, is: '40ch'},
-  {at: 1, is: '60ch'},
-  {at: 1.4, is: '80ch'}
-]);
-assertAttributeInterpolation({
-  property: 'r',
-  underlying: '5mm',
-  from: '5mm',
-  fromComposite: 'add',
-  to: '5.5cm',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '0mm'},
-  {at: 0, is: '10mm'},
-  {at: 0.2, is: '20mm'},
-  {at: 0.6, is: '40mm'},
-  {at: 1, is: '60mm'},
-  {at: 1.4, is: '80mm'}
-]);
-assertAttributeInterpolation({
-  property: 'r',
-  underlying: '20',
-  from: '10pc',
-  fromComposite: 'add',
-  to: '20ch',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '164'},
-  {at: 0, is: '180'},
-  {at: 0.2, is: '188'},
-  {at: 0.6, is: '204'},
-  {at: 1, is: '220'},
-  {at: 1.4, is: '236'}
-]);
-
-assertAttributeInterpolation({
-  property: 'r',
-  underlying: '20ch',
-  from: '10ch',
-  fromComposite: 'replace',
-  to: '40ch',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '0ch'},
-  {at: 0, is: '10ch'},
-  {at: 0.2, is: '20ch'},
-  {at: 0.6, is: '40ch'},
-  {at: 1, is: '60ch'},
-  {at: 1.4, is: '80ch'}
-]);
-assertAttributeInterpolation({
-  property: 'r',
-  underlying: '2cm',
-  from: '10mm',
-  fromComposite: 'replace',
-  to: '4cm',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '0mm'},
-  {at: 0, is: '10mm'},
-  {at: 0.2, is: '20mm'},
-  {at: 0.6, is: '40mm'},
-  {at: 1, is: '60mm'},
-  {at: 1.4, is: '80mm'}
-]);
-assertAttributeInterpolation({
-  property: 'r',
-  underlying: '10ch',
-  from: '10pc',
-  fromComposite: 'replace',
-  to: '10ch',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '144'},
-  {at: 0, is: '10pc'},
-  {at: 0.2, is: '168'},
-  {at: 0.6, is: '184'},
-  {at: 1, is: '20ch'},
-  {at: 1.4, is: '216'}
-]);
-
-assertAttributeInterpolation({
-  property: 'r',
-  underlying: '10ch',
-  from: neutralKeyframe,
-  to: '60ch',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: '0ch'},
-  {at: 0, is: '10ch'},
-  {at: 0.2, is: '20ch'},
-  {at: 0.6, is: '40ch'},
-  {at: 1, is: '60ch'},
-  {at: 1.4, is: '80ch'}
-]);
-assertAttributeInterpolation({
-  property: 'r',
-  underlying: '10mm',
-  from: neutralKeyframe,
-  to: '6cm',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: '0mm'},
-  {at: 0, is: '10mm'},
-  {at: 0.2, is: '20mm'},
-  {at: 0.6, is: '40mm'},
-  {at: 1, is: '60mm'},
-  {at: 1.4, is: '80mm'}
-]);
-assertAttributeInterpolation({
-  property: 'r',
-  underlying: '10pc',
-  from: neutralKeyframe,
-  to: '20ch',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: '144'},
-  {at: 0, is: '10pc'},
-  {at: 0.2, is: '168'},
-  {at: 0.6, is: '184'},
-  {at: 1, is: '20ch'},
-  {at: 1.4, is: '216'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-radius-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-radius-composition.html
deleted file mode 100644
index fdf86d9..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-radius-composition.html
+++ /dev/null
@@ -1,139 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<feMorphology class="target" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'radius',
-  underlying: '0',
-  from: '1',
-  fromComposite: 'add',
-  to: '6 11',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-1, -3'},
-  {at: 0, is: '1, 1'},
-  {at: 0.2, is: '2, 3'},
-  {at: 0.6, is: '4, 7'},
-  {at: 1, is: '6, 11'},
-  {at: 1.4, is: '8, 15'},
-]);
-
-assertAttributeInterpolation({
-  property: 'radius',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6 11',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '2, 0'},
-  {at: 0, is: '4, 4'},
-  {at: 0.2, is: '5, 6'},
-  {at: 0.6, is: '7, 10'},
-  {at: 1, is: '9, 14'},
-  {at: 1.4, is: '11, 18'},
-]);
-
-assertAttributeInterpolation({
-  property: 'radius',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6 11',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-2.2, -4.2'},
-  {at: 0, is: '1, 1'},
-  {at: 0.2, is: '2.6, 3.6'},
-  {at: 0.6, is: '5.8, 8.8'},
-  {at: 1, is: '9, 14'},
-  {at: 1.4, is: '12.2, 19.2'},
-]);
-
-assertAttributeInterpolation({
-  property: 'radius',
-  underlying: '3',
-  from: neutralKeyframe,
-  to: '6 11',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: '1.8, -0.2'},
-  {at: 0, is: '3, 3'},
-  {at: 0.2, is: '3.6, 4.6'},
-  {at: 0.6, is: '4.8, 7.8'},
-  {at: 1, is: '6, 11'},
-  {at: 1.4, is: '7.2, 14.2'},
-]);
-
-assertAttributeInterpolation({
-  property: 'radius',
-  underlying: '0',
-  from: '-2 10',
-  fromComposite: 'add',
-  to: '3 10',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-4, 10'},
-  {at: 0, is: '-2, 10'},
-  {at: 0.2, is: '-1, 10'},
-  {at: 0.6, is: '1, 10'},
-  {at: 1, is: '3, 10'},
-  {at: 1.4, is: '5, 10'},
-]);
-
-assertAttributeInterpolation({
-  property: 'radius',
-  underlying: '3',
-  from: '-2 10',
-  fromComposite: 'add',
-  to: '3 10',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-1, 13'},
-  {at: 0, is: '1, 13'},
-  {at: 0.2, is: '2, 13'},
-  {at: 0.6, is: '4, 13'},
-  {at: 1, is: '6, 13'},
-  {at: 1.4, is: '8, 13'},
-]);
-
-assertAttributeInterpolation({
-  property: 'radius',
-  underlying: '3',
-  from: '-2 10',
-  fromComposite: 'replace',
-  to: '3 10',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-5.2, 8.8'},
-  {at: 0, is: '-2, 10'},
-  {at: 0.2, is: '-0.4, 10.6'},
-  {at: 0.6, is: '2.8, 11.8'},
-  {at: 1, is: '6, 13'},
-  {at: 1.4, is: '9.2, 14.2'},
-]);
-
-assertAttributeInterpolation({
-  property: 'radius',
-  underlying: '3',
-  from: neutralKeyframe,
-  to: '3 10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: '3, 0.2'},
-  {at: 0, is: '3, 3'},
-  {at: 0.2, is: '3, 4.4'},
-  {at: 0.6, is: '3, 7.2'},
-  {at: 1, is: '3, 10'},
-  {at: 1.4, is: '3, 12.8'},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-refX-refY-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-refX-refY-composition.html
deleted file mode 100644
index 94029ca..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-refX-refY-composition.html
+++ /dev/null
@@ -1,108 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<marker class="target" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-
-assertAttributeInterpolation({
-  property: 'refX',
-  underlying: '3',
-  from: '-2',
-  fromComposite: 'add',
-  to: '3',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-
-assertAttributeInterpolation({
-  property: 'refX',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'replace',
-  to: '3',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-
-assertAttributeInterpolation({
-  property: 'refX',
-  underlying: '1',
-  from: neutralKeyframe,
-  to: '6',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-
-assertAttributeInterpolation({
-  property: 'refY',
-  underlying: '3',
-  from: '-2',
-  fromComposite: 'add',
-  to: '3',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-
-assertAttributeInterpolation({
-  property: 'refY',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'replace',
-  to: '3',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-
-assertAttributeInterpolation({
-  property: 'refY',
-  underlying: '1',
-  from: neutralKeyframe,
-  to: '6',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-rotate-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-rotate-composition.html
deleted file mode 100644
index efc6b93..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-rotate-composition.html
+++ /dev/null
@@ -1,109 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-  <text>
-    <tspan class="target">abcd</tspan>
-  </text>
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'rotate',
-  underlying: '10, 20',
-  from: '30, 40',
-  fromComposite: 'add',
-  to: '50, -10',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '32, 80'},
-  {at: 0, is: '40, 60'},
-  {at: 0.2, is: '44, 50'},
-  {at: 0.6, is: '52, 30'},
-  {at: 1, is: '60, 10'},
-  {at: 1.4, is: '68, -10'},
-]);
-
-assertAttributeInterpolation({
-  property: 'rotate',
-  underlying: '10, 20',
-  from: '30',
-  fromComposite: 'add',
-  to: '50',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '32, 20'},
-  {at: 0, is: '40, 20'},
-  {at: 0.2, is: '44, 20'},
-  {at: 0.6, is: '52, 20'},
-  {at: 1, is: '60, 20'},
-  {at: 1.4, is: '68, 20'},
-]);
-
-assertAttributeInterpolation({
-  property: 'rotate',
-  underlying: '10',
-  from: '20, 30, 40',
-  fromComposite: 'add',
-  to: '50, 40, 30',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '18, 26, 44'},
-  {at: 0, is: '30, 30, 40'},
-  {at: 0.2, is: '36, 32, 38'},
-  {at: 0.6, is: '48, 36, 34'},
-  {at: 1, is: '60, 40, 30'},
-  {at: 1.4, is: '72, 44, 26'},
-]);
-
-assertAttributeInterpolation({
-  property: 'rotate',
-  underlying: '10',
-  from: '30, 40',
-  fromComposite: 'add',
-  to: '50, 60, 70',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: '40, 40'},
-  {at: 0, is: '40, 40'},
-  {at: 0.2, is: '40, 40'},
-  {at: 0.6, is: '50, 60, 70'},
-  {at: 1, is: '50, 60, 70'},
-  {at: 1.4, is: '50, 60, 70'},
-]);
-
-assertAttributeInterpolation({
-  property: 'rotate',
-  underlying: '10',
-  from: neutralKeyframe,
-  to: '50, -10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: '10'},
-  {at: 0, is: '10'},
-  {at: 0.2, is: '10'},
-  {at: 0.6, is: '50, -10'},
-  {at: 1, is: '50, -10'},
-  {at: 1.4, is: '50, -10'},
-]);
-
-assertAttributeInterpolation({
-  property: 'rotate',
-  underlying: '10, 20',
-  from: neutralKeyframe,
-  to: '50, -10',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-10, 24'},
-  {at: 0, is: '10, 20'},
-  {at: 0.2, is: '20, 18'},
-  {at: 0.6, is: '40, 14'},
-  {at: 1, is: '60, 10'},
-  {at: 1.4, is: '80, 6'},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-rx-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-rx-composition.html
deleted file mode 100644
index 95e63f7..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-rx-composition.html
+++ /dev/null
@@ -1,108 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<ellipse class="target" cx="20" cy="20" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-
-assertAttributeInterpolation({
-  property: 'rx',
-  underlying: '3',
-  from: '-2',
-  fromComposite: 'add',
-  to: '3',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-
-assertAttributeInterpolation({
-  property: 'rx',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'replace',
-  to: '3',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-
-assertAttributeInterpolation({
-  property: 'rx',
-  underlying: '1',
-  from: neutralKeyframe,
-  to: '6',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-
-assertAttributeInterpolation({
-  property: 'ry',
-  underlying: '3',
-  from: '-2',
-  fromComposite: 'add',
-  to: '3',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-
-assertAttributeInterpolation({
-  property: 'ry',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'replace',
-  to: '3',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-
-assertAttributeInterpolation({
-  property: 'ry',
-  underlying: '1',
-  from: neutralKeyframe,
-  to: '6',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-scale-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-scale-composition.html
deleted file mode 100644
index d85756a..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-scale-composition.html
+++ /dev/null
@@ -1,64 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="0" height="0">
-<defs>
-<filter>
-<feDisplacementMap class="target" />
-</filter>
-</defs>
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'scale',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 2},
-  {at: 0, is: 4},
-  {at: 0.2, is: 5},
-  {at: 0.6, is: 7},
-  {at: 1, is: 9},
-  {at: 1.4, is: 11},
-]);
-
-assertAttributeInterpolation({
-  property: 'scale',
-  underlying: '5',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: -3},
-  {at: 0, is: 1},
-  {at: 0.2, is: 3},
-  {at: 0.6, is: 7},
-  {at: 1, is: 11},
-  {at: 1.4, is: 15},
-]);
-
-assertAttributeInterpolation({
-  property: 'scale',
-  underlying: '5',
-  from: neutralKeyframe,
-  to: '10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 3},
-  {at: 0, is: 5},
-  {at: 0.2, is: 6},
-  {at: 0.6, is: 8},
-  {at: 1, is: 10},
-  {at: 1.4, is: 12},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-seed-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-seed-composition.html
deleted file mode 100644
index 40c28d7..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-seed-composition.html
+++ /dev/null
@@ -1,64 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="0" height="0">
-<defs>
-<filter>
-<feTurbulence class="target" />
-</filter>
-</defs>
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'seed',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 2},
-  {at: 0, is: 4},
-  {at: 0.2, is: 5},
-  {at: 0.6, is: 7},
-  {at: 1, is: 9},
-  {at: 1.4, is: 11},
-]);
-
-assertAttributeInterpolation({
-  property: 'seed',
-  underlying: '5',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: -3},
-  {at: 0, is: 1},
-  {at: 0.2, is: 3},
-  {at: 0.6, is: 7},
-  {at: 1, is: 11},
-  {at: 1.4, is: 15},
-]);
-
-assertAttributeInterpolation({
-  property: 'seed',
-  underlying: '5',
-  from: neutralKeyframe,
-  to: '10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 3},
-  {at: 0, is: 5},
-  {at: 0.2, is: 6},
-  {at: 0.6, is: 8},
-  {at: 1, is: 10},
-  {at: 1.4, is: 12},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-slope-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-slope-composition.html
deleted file mode 100644
index f21c4fa..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-slope-composition.html
+++ /dev/null
@@ -1,62 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="0" height="0">
-<feComponentTransfer>
-<feFuncR type="linear" class="target" />
-</feComponentTransfer>
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'slope',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 2},
-  {at: 0, is: 4},
-  {at: 0.2, is: 5},
-  {at: 0.6, is: 7},
-  {at: 1, is: 9},
-  {at: 1.4, is: 11},
-]);
-
-assertAttributeInterpolation({
-  property: 'slope',
-  underlying: '5',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: -3},
-  {at: 0, is: 1},
-  {at: 0.2, is: 3},
-  {at: 0.6, is: 7},
-  {at: 1, is: 11},
-  {at: 1.4, is: 15},
-]);
-
-assertAttributeInterpolation({
-  property: 'slope',
-  underlying: '5',
-  from: neutralKeyframe,
-  to: '10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 3},
-  {at: 0, is: 5},
-  {at: 0.2, is: 6},
-  {at: 0.6, is: 8},
-  {at: 1, is: 10},
-  {at: 1.4, is: 12},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-specularConstant-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-specularConstant-composition.html
deleted file mode 100644
index f204f48..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-specularConstant-composition.html
+++ /dev/null
@@ -1,60 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="0" height="0">
-<fespecularlighting class="target" kernelUnitLength="1" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'specularConstant',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 2},
-  {at: 0, is: 4},
-  {at: 0.2, is: 5},
-  {at: 0.6, is: 7},
-  {at: 1, is: 9},
-  {at: 1.4, is: 11},
-]);
-
-assertAttributeInterpolation({
-  property: 'specularConstant',
-  underlying: '5',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: -3},
-  {at: 0, is: 1},
-  {at: 0.2, is: 3},
-  {at: 0.6, is: 7},
-  {at: 1, is: 11},
-  {at: 1.4, is: 15},
-]);
-
-assertAttributeInterpolation({
-  property: 'specularConstant',
-  underlying: '5',
-  from: neutralKeyframe,
-  to: '10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 3},
-  {at: 0, is: 5},
-  {at: 0.2, is: 6},
-  {at: 0.6, is: 8},
-  {at: 1, is: 10},
-  {at: 1.4, is: 12},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-specularExponent-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-specularExponent-composition.html
deleted file mode 100644
index 24ee1b8f..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-specularExponent-composition.html
+++ /dev/null
@@ -1,60 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="0" height="0">
-<feSpecularLighting class="target" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'specularExponent',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 2},
-  {at: 0, is: 4},
-  {at: 0.2, is: 5},
-  {at: 0.6, is: 7},
-  {at: 1, is: 9},
-  {at: 1.4, is: 11},
-]);
-
-assertAttributeInterpolation({
-  property: 'specularExponent',
-  underlying: '5',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: -3},
-  {at: 0, is: 1},
-  {at: 0.2, is: 3},
-  {at: 0.6, is: 7},
-  {at: 1, is: 11},
-  {at: 1.4, is: 15},
-]);
-
-assertAttributeInterpolation({
-  property: 'specularExponent',
-  underlying: '5',
-  from: neutralKeyframe,
-  to: '10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 3},
-  {at: 0, is: 5},
-  {at: 0.2, is: 6},
-  {at: 0.6, is: 8},
-  {at: 1, is: 10},
-  {at: 1.4, is: 12},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-startOffset-composition-001.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-startOffset-composition-001.html
deleted file mode 100644
index 05bdcbf..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-startOffset-composition-001.html
+++ /dev/null
@@ -1,76 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script src="../../resources/ahem.js"></script>
-<style>
-:root {
-  font: 50px Ahem;
-}
-</style>
-</head>
-<body>
-<svg>
-  <defs>
-    <path id="path1" d="m 0 0 h 250 v 250 h -250 z"/>
-  </defs>
-</svg>
-<template id="target-template">
-<svg width="7px" height="17px" viewBox="0 0 140 340">
-  <text text-anchor="middle">
-    <textPath xlink:href="#path1" startOffset="50%" class="target">
-      Text on a path
-    </textPath>
-  </text>
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'startOffset',
-  underlying: '2',
-  from: '-1',
-  fromComposite: 'add',
-  to: '4',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-assertAttributeInterpolation({
-  property: 'startOffset',
-  underlying: '1in',
-  from: '9in',
-  fromComposite: 'add',
-  to: '698pt',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '700pt'},
-  {at: 0, is: '720pt'},
-  {at: 0.2, is: '730pt'},
-  {at: 0.6, is: '750pt'},
-  {at: 1, is: '770pt'},
-  {at: 1.4, is: '790pt'}
-]);
-assertAttributeInterpolation({
-  property: 'startOffset',
-  underlying: '50',
-  from: '75',
-  fromComposite: 'add',
-  to: '19em',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '-225'},
-  {at: 0, is: '125'},
-  {at: 0.2, is: '300'},
-  {at: 0.6, is: '650'},
-  {at: 1, is: '1000'},
-  {at: 1.4, is: '1350'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-startOffset-composition-002.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-startOffset-composition-002.html
deleted file mode 100644
index 4bfc861..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-startOffset-composition-002.html
+++ /dev/null
@@ -1,76 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script src="../../resources/ahem.js"></script>
-<style>
-:root {
-  font: 50px Ahem;
-}
-</style>
-</head>
-<body>
-<svg>
-  <defs>
-    <path id="path1" d="m 0 0 h 250 v 250 h -250 z"/>
-  </defs>
-</svg>
-<template id="target-template">
-<svg width="7px" height="17px" viewBox="0 0 140 340">
-  <text text-anchor="middle">
-    <textPath xlink:href="#path1" startOffset="50%" class="target">
-      Text on a path
-    </textPath>
-  </text>
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'startOffset',
-  underlying: '2',
-  from: '1',
-  fromComposite: 'replace',
-  to: '4',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-assertAttributeInterpolation({
-  property: 'startOffset',
-  underlying: '50pt',
-  from: '10in',
-  fromComposite: 'replace',
-  to: '720pt',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '700pt'},
-  {at: 0, is: '720pt'},
-  {at: 0.2, is: '730pt'},
-  {at: 0.6, is: '750pt'},
-  {at: 1, is: '770pt'},
-  {at: 1.4, is: '790pt'}
-]);
-assertAttributeInterpolation({
-  property: 'startOffset',
-  underlying: '5em',
-  from: '125',
-  fromComposite: 'replace',
-  to: '15em',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '-225'},
-  {at: 0, is: '125'},
-  {at: 0.2, is: '300'},
-  {at: 0.6, is: '650'},
-  {at: 1, is: '1000'},
-  {at: 1.4, is: '1350'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-startOffset-composition-003.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-startOffset-composition-003.html
deleted file mode 100644
index 9a57862..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-startOffset-composition-003.html
+++ /dev/null
@@ -1,73 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script src="../../resources/ahem.js"></script>
-<style>
-:root {
-  font: 50px Ahem;
-}
-</style>
-</head>
-<body>
-<svg>
-  <defs>
-    <path id="path1" d="m 0 0 h 250 v 250 h -250 z"/>
-  </defs>
-</svg>
-<template id="target-template">
-<svg width="7px" height="17px" viewBox="0 0 140 340">
-  <text text-anchor="middle">
-    <textPath xlink:href="#path1" startOffset="50%" class="target">
-      Text on a path
-    </textPath>
-  </text>
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'startOffset',
-  underlying: '1',
-  from: neutralKeyframe,
-  to: '6',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-assertAttributeInterpolation({
-  property: 'startOffset',
-  underlying: '10in',
-  from: neutralKeyframe,
-  to: '770pt',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: '700pt'},
-  {at: 0, is: '720pt'},
-  {at: 0.2, is: '730pt'},
-  {at: 0.6, is: '750pt'},
-  {at: 1, is: '770pt'},
-  {at: 1.4, is: '790pt'}
-]);
-assertAttributeInterpolation({
-  property: 'startOffset',
-  underlying: '125',
-  from: neutralKeyframe,
-  to: '20em',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: '-225'},
-  {at: 0, is: '125'},
-  {at: 0.2, is: '300'},
-  {at: 0.6, is: '650'},
-  {at: 1, is: '1000'},
-  {at: 1.4, is: '1350'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-stdDeviation-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-stdDeviation-composition.html
deleted file mode 100644
index 7e79c50e..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-stdDeviation-composition.html
+++ /dev/null
@@ -1,145 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<defs>
-<filter>
-<feGaussianBlur class="target" />
-</filter>
-</defs>
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'stdDeviation',
-  underlying: '0',
-  from: '1',
-  fromComposite: 'add',
-  to: '6 11',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-1, -3'},
-  {at: 0, is: '1, 1'},
-  {at: 0.2, is: '2, 3'},
-  {at: 0.6, is: '4, 7'},
-  {at: 1, is: '6, 11'},
-  {at: 1.4, is: '8, 15'},
-]);
-
-assertAttributeInterpolation({
-  property: 'stdDeviation',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6 11',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '2, 0'},
-  {at: 0, is: '4, 4'},
-  {at: 0.2, is: '5, 6'},
-  {at: 0.6, is: '7, 10'},
-  {at: 1, is: '9, 14'},
-  {at: 1.4, is: '11, 18'},
-]);
-
-assertAttributeInterpolation({
-  property: 'stdDeviation',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6 11',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-2.2, -4.2'},
-  {at: 0, is: '1, 1'},
-  {at: 0.2, is: '2.6, 3.6'},
-  {at: 0.6, is: '5.8, 8.8'},
-  {at: 1, is: '9, 14'},
-  {at: 1.4, is: '12.2, 19.2'},
-]);
-
-assertAttributeInterpolation({
-  property: 'stdDeviation',
-  underlying: '3',
-  from: neutralKeyframe,
-  to: '6 11',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: '1.8, -0.2'},
-  {at: 0, is: '3, 3'},
-  {at: 0.2, is: '3.6, 4.6'},
-  {at: 0.6, is: '4.8, 7.8'},
-  {at: 1, is: '6, 11'},
-  {at: 1.4, is: '7.2, 14.2'},
-]);
-
-assertAttributeInterpolation({
-  property: 'stdDeviation',
-  underlying: '0',
-  from: '-2 10',
-  fromComposite: 'add',
-  to: '3 10',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-4, 10'},
-  {at: 0, is: '-2, 10'},
-  {at: 0.2, is: '-1, 10'},
-  {at: 0.6, is: '1, 10'},
-  {at: 1, is: '3, 10'},
-  {at: 1.4, is: '5, 10'},
-]);
-
-assertAttributeInterpolation({
-  property: 'stdDeviation',
-  underlying: '3',
-  from: '-2 10',
-  fromComposite: 'add',
-  to: '3 10',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-1, 13'},
-  {at: 0, is: '1, 13'},
-  {at: 0.2, is: '2, 13'},
-  {at: 0.6, is: '4, 13'},
-  {at: 1, is: '6, 13'},
-  {at: 1.4, is: '8, 13'},
-]);
-
-assertAttributeInterpolation({
-  property: 'stdDeviation',
-  underlying: '3',
-  from: '-2 10',
-  fromComposite: 'replace',
-  to: '3 10',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-5.2, 8.8'},
-  {at: 0, is: '-2, 10'},
-  {at: 0.2, is: '-0.4, 10.6'},
-  {at: 0.6, is: '2.8, 11.8'},
-  {at: 1, is: '6, 13'},
-  {at: 1.4, is: '9.2, 14.2'},
-]);
-
-assertAttributeInterpolation({
-  property: 'stdDeviation',
-  underlying: '3',
-  from: neutralKeyframe,
-  to: '3 10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: '3, 0.2'},
-  {at: 0, is: '3, 3'},
-  {at: 0.2, is: '3, 4.4'},
-  {at: 0.6, is: '3, 7.2'},
-  {at: 1, is: '3, 10'},
-  {at: 1.4, is: '3, 12.8'},
-]);
-
-
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-surfaceScale-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-surfaceScale-composition.html
deleted file mode 100644
index 35abf4d..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-surfaceScale-composition.html
+++ /dev/null
@@ -1,60 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="0" height="0">
-<feDiffuseLighting class="target" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'surfaceScale',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 2},
-  {at: 0, is: 4},
-  {at: 0.2, is: 5},
-  {at: 0.6, is: 7},
-  {at: 1, is: 9},
-  {at: 1.4, is: 11},
-]);
-
-assertAttributeInterpolation({
-  property: 'surfaceScale',
-  underlying: '5',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: -3},
-  {at: 0, is: 1},
-  {at: 0.2, is: 3},
-  {at: 0.6, is: 7},
-  {at: 1, is: 11},
-  {at: 1.4, is: 15},
-]);
-
-assertAttributeInterpolation({
-  property: 'surfaceScale',
-  underlying: '5',
-  from: neutralKeyframe,
-  to: '10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 3},
-  {at: 0, is: 5},
-  {at: 0.2, is: 6},
-  {at: 0.6, is: 8},
-  {at: 1, is: 10},
-  {at: 1.4, is: 12},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-tableValues-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-tableValues-composition.html
deleted file mode 100644
index 19d9dac2..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-tableValues-composition.html
+++ /dev/null
@@ -1,109 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-  <feComponentTransfer>
-    <feFuncG type="table" class="target" />
-  </feComponentTransfer>
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'tableValues',
-  underlying: '10, 20',
-  from: '30, 40',
-  fromComposite: 'add',
-  to: '50, -10',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '32, 80'},
-  {at: 0, is: '40, 60'},
-  {at: 0.2, is: '44, 50'},
-  {at: 0.6, is: '52, 30'},
-  {at: 1, is: '60, 10'},
-  {at: 1.4, is: '68, -10'},
-]);
-
-assertAttributeInterpolation({
-  property: 'tableValues',
-  underlying: '10, 20',
-  from: '30',
-  fromComposite: 'add',
-  to: '50',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '32, 20'},
-  {at: 0, is: '40, 20'},
-  {at: 0.2, is: '44, 20'},
-  {at: 0.6, is: '52, 20'},
-  {at: 1, is: '60, 20'},
-  {at: 1.4, is: '68, 20'},
-]);
-
-assertAttributeInterpolation({
-  property: 'tableValues',
-  underlying: '10',
-  from: '20, 30, 40',
-  fromComposite: 'add',
-  to: '50, 40, 30',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '18, 26, 44'},
-  {at: 0, is: '30, 30, 40'},
-  {at: 0.2, is: '36, 32, 38'},
-  {at: 0.6, is: '48, 36, 34'},
-  {at: 1, is: '60, 40, 30'},
-  {at: 1.4, is: '72, 44, 26'},
-]);
-
-assertAttributeInterpolation({
-  property: 'tableValues',
-  underlying: '10',
-  from: '30, 40',
-  fromComposite: 'add',
-  to: '50, 60, 70',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: '40, 40'},
-  {at: 0, is: '40, 40'},
-  {at: 0.2, is: '40, 40'},
-  {at: 0.6, is: '50, 60, 70'},
-  {at: 1, is: '50, 60, 70'},
-  {at: 1.4, is: '50, 60, 70'},
-]);
-
-assertAttributeInterpolation({
-  property: 'tableValues',
-  underlying: '10',
-  from: neutralKeyframe,
-  to: '50, -10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: '10'},
-  {at: 0, is: '10'},
-  {at: 0.2, is: '10'},
-  {at: 0.6, is: '50, -10'},
-  {at: 1, is: '50, -10'},
-  {at: 1.4, is: '50, -10'},
-]);
-
-assertAttributeInterpolation({
-  property: 'tableValues',
-  underlying: '10, 20',
-  from: neutralKeyframe,
-  to: '50, -10',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-10, 24'},
-  {at: 0, is: '10, 20'},
-  {at: 0.2, is: '20, 18'},
-  {at: 0.6, is: '40, 14'},
-  {at: 1, is: '60, 10'},
-  {at: 1.4, is: '80, 6'},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-targetX-targetY-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-targetX-targetY-composition.html
deleted file mode 100644
index 6a2b013c..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-targetX-targetY-composition.html
+++ /dev/null
@@ -1,108 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="0" height="0">
-<feConvolveMatrix class="target" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'targetX',
-  underlying: '128',
-  from: '-32',
-  fromComposite: 'add',
-  to: '1029',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: -328},
-  {at: 0, is: 96},
-  {at: 0.2, is: 308},
-  {at: 0.6, is: 733},
-  {at: 1, is: 1157},
-  {at: 1.4, is: 1581}
-]);
-
-assertAttributeInterpolation({
-  property: 'targetX',
-  underlying: '-37',
-  from: '18',
-  fromComposite: 'replace',
-  to: '1',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 40},
-  {at: 0, is: 18},
-
-  {at: 0.6, is: -14},
-  {at: 1, is: -36},
-  {at: 1.4, is: -58}
-]);
-
-assertAttributeInterpolation({
-  property: 'targetX',
-  underlying: '2',
-  from: neutralKeyframe,
-  to: '-99',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 42},
-  {at: 0, is: 2},
-  {at: 0.2, is: -18},
-  {at: 0.6, is: -59},
-  {at: 1, is: -99},
-  {at: 1.4, is: -139}
-]);
-
-
-assertAttributeInterpolation({
-  property: 'targetY',
-  underlying: '128',
-  from: '-32',
-  fromComposite: 'add',
-  to: '1029',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: -328},
-  {at: 0, is: 96},
-  {at: 0.2, is: 308},
-  {at: 0.6, is: 733},
-  {at: 1, is: 1157},
-  {at: 1.4, is: 1581}
-]);
-
-assertAttributeInterpolation({
-  property: 'targetY',
-  underlying: '-37',
-  from: '18',
-  fromComposite: 'replace',
-  to: '1',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 40},
-  {at: 0, is: 18},
-
-  {at: 0.6, is: -14},
-  {at: 1, is: -36},
-  {at: 1.4, is: -58}
-]);
-
-assertAttributeInterpolation({
-  property: 'targetY',
-  underlying: '2',
-  from: neutralKeyframe,
-  to: '-99',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 42},
-  {at: 0, is: 2},
-  {at: 0.2, is: -18},
-  {at: 0.6, is: -59},
-  {at: 1, is: -99},
-  {at: 1.4, is: -139}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-textLength-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-textLength-composition.html
deleted file mode 100644
index 456c546..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-textLength-composition.html
+++ /dev/null
@@ -1,58 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<text class="target" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'textLength',
-  underlying: '2',
-  from: '-1',
-  fromComposite: 'add',
-  to: '4',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-assertAttributeInterpolation({
-  property: 'textLength',
-  underlying: '2',
-  from: '1',
-  fromComposite: 'replace',
-  to: '4',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-assertAttributeInterpolation({
-  property: 'textLength',
-  underlying: '1',
-  from: neutralKeyframe,
-  to: '6',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-transform-composition-distinct.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-transform-composition-distinct.html
deleted file mode 100644
index 217f7ba..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-transform-composition-distinct.html
+++ /dev/null
@@ -1,78 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<line x1="1" y1="2" x2="3" y2="4" class="target" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'skewX(10)',
-  from: 'translate(10 20)',
-  fromComposite: 'add',
-  to: 'rotate(30 40 50)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'skewX(10) translate(10 20)'},
-  {at: 0, is: 'skewX(10) translate(10 20)'},
-  {at: 0.2, is: 'skewX(10) translate(10 20)'},
-  {at: 0.6, is: 'skewX(10) rotate(30 40 50)'},
-  {at: 1, is: 'skewX(10) rotate(30 40 50)'},
-  {at: 1.4, is: 'skewX(10) rotate(30 40 50)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'translate(5 5)',
-  from: 'translate(5 15)',
-  fromComposite: 'add',
-  to: 'rotate(30 40 50)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'translate(5 5) translate(5 15)'},
-  {at: 0, is: 'translate(5 5) translate(5 15)'},
-  {at: 0.2, is: 'translate(5 5) translate(5 15)'},
-  {at: 0.6, is: 'translate(5 5) rotate(30 40 50)'},
-  {at: 1, is: 'translate(5 5) rotate(30 40 50)'},
-  {at: 1.4, is: 'translate(5 5) rotate(30 40 50)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'skewY(5)',
-  from: 'skewX(10)',
-  fromComposite: 'add',
-  to: 'skewY(15)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'skewY(5) skewX(10)'},
-  {at: 0, is: 'skewY(5) skewX(10)'},
-  {at: 0.2, is: 'skewY(5) skewX(10)'},
-  {at: 0.6, is: 'skewY(5) skewY(15)'},
-  {at: 1, is: 'skewY(5) skewY(15)'},
-  {at: 1.4, is: 'skewY(5) skewY(15)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'translate(5 5)',
-  from: neutralKeyframe,
-  to: 'skewY(20)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'translate(5 5)'},
-  {at: 0, is: 'translate(5 5)'},
-  {at: 0.2, is: 'translate(5 5)'},
-  {at: 0.6, is: 'translate(5 5) skewY(20)'},
-  {at: 1, is: 'translate(5 5) skewY(20)'},
-  {at: 1.4, is: 'translate(5 5) skewY(20)'}
-]);
-
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-transform-composition-list.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-transform-composition-list.html
deleted file mode 100644
index a53f59b..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-transform-composition-list.html
+++ /dev/null
@@ -1,224 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<line x1="1" y1="2" x2="3" y2="4" class="target" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-
-// Common list of transforms
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'translate(10 10) scale(10 10) rotate(10 10 10)',
-  from: 'translate(100 10) scale(10 20) rotate(10 20 30)',
-  fromComposite: 'add',
-  to: 'translate(120 50) scale(20 50) rotate(30 70 150)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'translate(10 10) scale(10 10) rotate(10 10 10) translate(92 -6) scale(6 8) rotate(2 0 -18)'},
-  {at: 0, is: 'translate(10 10) scale(10 10) rotate(10 10 10) translate(100 10) scale(10 20) rotate(10 20 30)'},
-  {at: 0.2, is: 'translate(10 10) scale(10 10) rotate(10 10 10) translate(104 18) scale(12 26) rotate(14 30 54)'},
-  {at: 0.6, is: 'translate(10 10) scale(10 10) rotate(10 10 10) translate(112 34) scale(16 38) rotate(22 50 102)'},
-  {at: 1, is: 'translate(10 10) scale(10 10) rotate(10 10 10) translate(120 50) scale(20 50) rotate(30 70 150)'},
-  {at: 1.4, is: 'translate(10 10) scale(10 10) rotate(10 10 10) translate(128 66) scale(24 62) rotate(38 90 198)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'translate(10 10) scale(10 10) rotate(10 10 10)',
-  from: 'translate(110 20) scale(10 20) rotate(10 20 30)',
-  fromComposite: 'replace',
-  to: 'translate(120 50) scale(20 50) rotate(30 70 150)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'translate(110 20) scale(10 20) rotate(10 20 30)'},
-  {at: 0, is: 'translate(110 20) scale(10 20) rotate(10 20 30)'},
-  {at: 0.2, is: 'translate(110 20) scale(10 20) rotate(10 20 30)'},
-  {at: 0.6, is: 'translate(10 10) scale(10 10) rotate(10 10 10) translate(120 50) scale(20 50) rotate(30 70 150)'},
-  {at: 1, is: 'translate(10 10) scale(10 10) rotate(10 10 10) translate(120 50) scale(20 50) rotate(30 70 150)'},
-  {at: 1.4, is: 'translate(10 10) scale(10 10) rotate(10 10 10) translate(120 50) scale(20 50) rotate(30 70 150)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'translate(110 20) scale(10 20) rotate(10 20 30)',
-  from: neutralKeyframe,
-  to: 'translate(130 60) scale(30 60) rotate(40 80 160)',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: 'translate(102,4) scale(2 4) rotate(-2 -4 -22)'},
-  {at: 0, is: 'translate(110 20) scale(10 20) rotate(10 20 30)'},
-  {at: 0.2, is: 'translate(114,28) scale(14 28) rotate(16 32 56)'},
-  {at: 0.6, is: 'translate(122,44) scale(22 44) rotate(28 56 108)'},
-  {at: 1, is: 'translate(130 60) scale(30 60) rotate(40 80 160)'},
-  {at: 1.4, is: 'translate(138,76) scale(38 76) rotate(52 104 212)'}
-]);
-
-// Distinct list of transforms
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'translate(10 10) scale(10 10) skewX(10) skewY(10)',
-  from: 'translate(110 20) scale(10 20) skewX(10) rotate(10 20 30)',
-  fromComposite: 'add',
-  to: 'translate(130 60) scale(30 60) skewY(-30) rotate(40 80 160)',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 'translate(10 10) scale(10 10) skewX(10) skewY(10) translate(110 20) scale(10 20) skewX(10) rotate(10 20 30)'},
-  {at: 0, is: 'translate(10 10) scale(10 10) skewX(10) skewY(10) translate(110 20) scale(10 20) skewX(10) rotate(10 20 30)'},
-  {at: 0.2, is: 'translate(10 10) scale(10 10) skewX(10) skewY(10) translate(110 20) scale(10 20) skewX(10) rotate(10 20 30)'},
-  {at: 0.6, is: 'translate(10 10) scale(10 10) skewX(10) skewY(10) translate(130 60) scale(30 60) skewY(-30) rotate(40 80 160)'},
-  {at: 1, is: 'translate(10 10) scale(10 10) skewX(10) skewY(10) translate(130 60) scale(30 60) skewY(-30) rotate(40 80 160)'},
-  {at: 1.4, is: 'translate(10 10) scale(10 10) skewX(10) skewY(10) translate(130 60) scale(30 60) skewY(-30) rotate(40 80 160)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'translate(10 10) scale(10 10) skewX(10) rotate(10 10 10)',
-  from: 'translate(100 10) scale(0 10) skewX(0) rotate(0 10 20)',
-  fromComposite: 'add',
-  to: 'translate(130 60) scale(30 60) skewY(-30) rotate(40 80 160)',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 'translate(10 10) scale(10 10) skewX(10) rotate(10 10 10) translate(100 10) scale(0 10) skewX(0) rotate(0 10 20)'},
-  {at: 0, is: 'translate(10 10) scale(10 10) skewX(10) rotate(10 10 10) translate(100 10) scale(0 10) skewX(0) rotate(0 10 20)'},
-  {at: 0.2, is: 'translate(10 10) scale(10 10) skewX(10) rotate(10 10 10) translate(100 10) scale(0 10) skewX(0) rotate(0 10 20)'},
-  {at: 0.6, is: 'translate(10 10) scale(10 10) skewX(10) rotate(10 10 10) translate(130 60) scale(30 60) skewY(-30) rotate(40 80 160)'},
-  {at: 1, is: 'translate(10 10) scale(10 10) skewX(10) rotate(10 10 10) translate(130 60) scale(30 60) skewY(-30) rotate(40 80 160)'},
-  {at: 1.4, is: 'translate(10 10) scale(10 10) skewX(10) rotate(10 10 10) translate(130 60) scale(30 60) skewY(-30) rotate(40 80 160)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'translate(10 10) scale(10 10) skewY(10) rotate(10 10 10)',
-  from: 'translate(110 20) scale(10 20) skewX(10) rotate(10 20 30)',
-  fromComposite: 'add',
-  to: 'translate(120 50) scale(20 50) skewY(-40) rotate(30 70 150)',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 'translate(10 10) scale(10 10) skewY(10) rotate(10 10 10) translate(110 20) scale(10 20) skewX(10) rotate(10 20 30)'},
-  {at: 0, is: 'translate(10 10) scale(10 10) skewY(10) rotate(10 10 10) translate(110 20) scale(10 20) skewX(10) rotate(10 20 30)'},
-  {at: 0.2, is: 'translate(10 10) scale(10 10) skewY(10) rotate(10 10 10) translate(110 20) scale(10 20) skewX(10) rotate(10 20 30)'},
-  {at: 0.6, is: 'translate(10 10) scale(10 10) skewY(10) rotate(10 10 10) translate(120 50) scale(20 50) skewY(-40) rotate(30 70 150)'},
-  {at: 1, is: 'translate(10 10) scale(10 10) skewY(10) rotate(10 10 10) translate(120 50) scale(20 50) skewY(-40) rotate(30 70 150)'},
-  {at: 1.4, is: 'translate(10 10) scale(10 10) skewY(10) rotate(10 10 10) translate(120 50) scale(20 50) skewY(-40) rotate(30 70 150)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'translate(110 20) scale(10 20) skewX(10) rotate(10 20 30)',
-  from: neutralKeyframe,
-  to: 'translate(130 60) scale(30 60) skewY(-30) rotate(40 80 160)',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 'translate(110 20) scale(10 20) skewX(10) rotate(10 20 30)'},
-  {at: 0, is: 'translate(110 20) scale(10 20) skewX(10) rotate(10 20 30)'},
-  {at: 0.2, is: 'translate(110 20) scale(10 20) skewX(10) rotate(10 20 30)'},
-  {at: 0.6, is: 'translate(110 20) scale(10 20) skewX(10) rotate(10 20 30) translate(130 60) scale(30 60) skewY(-30) rotate(40 80 160)'},
-  {at: 1, is: 'translate(110 20) scale(10 20) skewX(10) rotate(10 20 30) translate(130 60) scale(30 60) skewY(-30) rotate(40 80 160)'},
-  {at: 1.4, is: 'translate(110 20) scale(10 20) skewX(10) rotate(10 20 30) translate(130 60) scale(30 60) skewY(-30) rotate(40 80 160)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'translate(10 10) scale(10 10)',
-  from: 'translate(110 20) scale(10 20) skewX(10)',
-  fromComposite: 'add',
-  to: 'translate(130 60) scale(30 60) skewX(-30) rotate(40 80 160)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'translate(10 10) scale(10 10) translate(110 20) scale(10 20) skewX(10)'},
-  {at: 0, is: 'translate(10 10) scale(10 10) translate(110 20) scale(10 20) skewX(10)'},
-  {at: 0.2, is: 'translate(10 10) scale(10 10) translate(110 20) scale(10 20) skewX(10)'},
-  {at: 0.6, is: 'translate(10 10) scale(10 10) translate(130 60) scale(30 60) skewX(-30) rotate(40 80 160)'},
-  {at: 1, is: 'translate(10 10) scale(10 10) translate(130 60) scale(30 60) skewX(-30) rotate(40 80 160)'},
-  {at: 1.4, is: 'translate(10 10) scale(10 10) translate(130 60) scale(30 60) skewX(-30) rotate(40 80 160)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'translate(10 10) scale(10 10) skewX(10)',
-  from: 'translate(100 10) scale(0 10) skewX(0)',
-  fromComposite: 'add',
-  to: 'translate(130 60) scale(30 60) skewX(-30) rotate(40 80 160)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'translate(10 10) scale(10 10) skewX(10) translate(100 10) scale(0 10) skewX(0)'},
-  {at: 0, is: 'translate(10 10) scale(10 10) skewX(10) translate(100 10) scale(0 10) skewX(0)'},
-  {at: 0.2, is: 'translate(10 10) scale(10 10) skewX(10) translate(100 10) scale(0 10) skewX(0)'},
-  {at: 0.6, is: 'translate(10 10) scale(10 10) skewX(10) translate(130 60) scale(30 60) skewX(-30) rotate(40 80 160)'},
-  {at: 1, is: 'translate(10 10) scale(10 10) skewX(10) translate(130 60) scale(30 60) skewX(-30) rotate(40 80 160)'},
-  {at: 1.4, is: 'translate(10 10) scale(10 10) skewX(10) translate(130 60) scale(30 60) skewX(-30) rotate(40 80 160)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'translate(10 10) scale(10 10) skewX(10) rotate(10 10 10)',
-  from: 'translate(110 20) scale(10 20) skewX(10)',
-  fromComposite: 'add',
-  to: 'translate(120 50) scale(20 50) skewX(-40) rotate(30 70 150)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'translate(10 10) scale(10 10) skewX(10) rotate(10 10 10) translate(110 20) scale(10 20) skewX(10)'},
-  {at: 0, is: 'translate(10 10) scale(10 10) skewX(10) rotate(10 10 10) translate(110 20) scale(10 20) skewX(10)'},
-  {at: 0.2, is: 'translate(10 10) scale(10 10) skewX(10) rotate(10 10 10) translate(110 20) scale(10 20) skewX(10)'},
-  {at: 0.6, is: 'translate(10 10) scale(10 10) skewX(10) rotate(10 10 10) translate(120 50) scale(20 50) skewX(-40) rotate(30 70 150)'},
-  {at: 1, is: 'translate(10 10) scale(10 10) skewX(10) rotate(10 10 10) translate(120 50) scale(20 50) skewX(-40) rotate(30 70 150)'},
-  {at: 1.4, is: 'translate(10 10) scale(10 10) skewX(10) rotate(10 10 10) translate(120 50) scale(20 50) skewX(-40) rotate(30 70 150)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'translate(110 20) scale(10 20) skewX(10)',
-  from: neutralKeyframe,
-  to: 'translate(130 60) scale(30 60) skewX(-30) rotate(40 80 160)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'translate(110 20) scale(10 20) skewX(10)'},
-  {at: 0, is: 'translate(110 20) scale(10 20) skewX(10)'},
-  {at: 0.2, is: 'translate(110 20) scale(10 20) skewX(10)'},
-  {at: 0.6, is: 'translate(110 20) scale(10 20) skewX(10) translate(130 60) scale(30 60) skewX(-30) rotate(40 80 160)'},
-  {at: 1, is: 'translate(110 20) scale(10 20) skewX(10) translate(130 60) scale(30 60) skewX(-30) rotate(40 80 160)'},
-  {at: 1.4, is: 'translate(110 20) scale(10 20) skewX(10) translate(130 60) scale(30 60) skewX(-30) rotate(40 80 160)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'translate(10 10)',
-  from: 'rotate(10 20 30)',
-  fromComposite: 'add',
-  to: 'translate(20 20) rotate(10 10 10)',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: 'translate(6 6) rotate(10 24 38)'},
-  {at: 0, is: 'translate(10 10) rotate(10 20 30)'},
-  {at: 0.2, is: 'translate(12 12) rotate(10 18 26)'},
-  {at: 0.6, is: 'translate(16 16) rotate(10 14 18)'},
-  {at: 1, is: 'translate(20 20) rotate(10 10 10)'},
-  {at: 1.4, is: 'translate(24 24) rotate(10 6 2)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'translate(10 10) scale(10 20)',
-  from: 'rotate(10 20 30) translate(5 15)',
-  fromComposite: 'add',
-  to: 'translate(20 20) scale(20 30) rotate(10 10 10) translate(5 5)',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: 'translate(6 6) scale(6 16) rotate(10 24 38) translate(5 19)'},
-  {at: 0, is: 'translate(10 10) scale(10 20) rotate(10 20 30) translate(5 15)'},
-  {at: 0.2, is: 'translate(12 12) scale(12 22) rotate(10 18 26) translate(5 13)'},
-  {at: 0.6, is: 'translate(16 16) scale(16 26) rotate(10 14 18) translate(5 9)'},
-  {at: 1, is: 'translate(20 20) scale(20 30) rotate(10 10 10) translate(5 5)'},
-  {at: 1.4, is: 'translate(24 24) scale(24 34) rotate(10 6 2) translate(5 1)'}
-]);
-
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-transform-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-transform-composition.html
deleted file mode 100644
index 1c01154..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-transform-composition.html
+++ /dev/null
@@ -1,250 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<line x1="1" y1="2" x2="3" y2="4" class="target" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'translate(10 10)',
-  from: 'translate(0 10)',
-  fromComposite: 'add',
-  to: 'translate(20 50)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'translate(10,10) translate(-8,-6)'},
-  {at: 0, is: 'translate(10,10) translate(0,10)'},
-  {at: 0.2, is: 'translate(10,10) translate(4,18)'},
-  {at: 0.6, is: 'translate(10,10) translate(12,34)'},
-  {at: 1, is: 'translate(10,10) translate(20,50)'},
-  {at: 1.4, is: 'translate(10,10) translate(28,66)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'translate(10 10)',
-  from: 'translate(10 20)',
-  fromComposite: 'replace',
-  to: 'translate(20 50)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'translate(10 20)'},
-  {at: 0, is: 'translate(10 20)'},
-  {at: 0.2, is: 'translate(10 20)'},
-  {at: 0.6, is: 'translate(10 10) translate(20 50)'},
-  {at: 1, is: 'translate(10 10) translate(20 50)'},
-  {at: 1.4, is: 'translate(10 10) translate(20 50)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'translate(10 20)',
-  from: neutralKeyframe,
-  to: 'translate(30 60)',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: 'translate(2,4)'},
-  {at: 0, is: 'translate(10,20)'},
-  {at: 0.2, is: 'translate(14,28)'},
-  {at: 0.6, is: 'translate(22,44)'},
-  {at: 1, is: 'translate(30,60)'},
-  {at: 1.4, is: 'translate(38,76)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'scale(10 5)',
-  from: 'scale(10 10)',
-  fromComposite: 'add',
-  to: 'scale(20 50)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'scale(10 5) scale(6 -6)'},
-  {at: 0, is: 'scale(10 5) scale(10 10)'},
-  {at: 0.2, is: 'scale(10 5) scale(12 18)'},
-  {at: 0.6, is: 'scale(10 5) scale(16 34)'},
-  {at: 1, is: 'scale(10 5) scale(20 50)'},
-  {at: 1.4, is: 'scale(10 5) scale(24 66)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'scale(10 5)',
-  from: 'scale(10 10)',
-  fromComposite: 'replace',
-  to: 'scale(20 50)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'scale(10 10)'},
-  {at: 0, is: 'scale(10 10)'},
-  {at: 0.2, is: 'scale(10 10)'},
-  {at: 0.6, is: 'scale(10 5) scale(20 50)'},
-  {at: 1, is: 'scale(10 5) scale(20 50)'},
-  {at: 1.4, is: 'scale(10 5) scale(20 50)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'scale(10 10)',
-  from: neutralKeyframe,
-  to: 'scale(20 50)',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: 'scale(6 -6)'},
-  {at: 0, is: 'scale(10 10)'},
-  {at: 0.2, is: 'scale(12 18)'},
-  {at: 0.6, is: 'scale(16 34)'},
-  {at: 1, is: 'scale(20 50)'},
-  {at: 1.4, is: 'scale(24 66)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'rotate(10 10 10)',
-  from: 'rotate(10 20 30)',
-  fromComposite: 'add',
-  to: 'rotate(40 80 160)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'rotate(10 10 10) rotate(-2 -4 -22)'},
-  {at: 0, is: 'rotate(10 10 10) rotate(10 20 30)'},
-  {at: 0.2, is: 'rotate(10 10 10) rotate(16 32 56)'},
-  {at: 0.6, is: 'rotate(10 10 10) rotate(28 56 108)'},
-  {at: 1, is: 'rotate(10 10 10) rotate(40 80 160)'},
-  {at: 1.4, is: 'rotate(10 10 10) rotate(52 104 212)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'rotate(10 10 10)',
-  from: 'rotate(10 20 30)',
-  fromComposite: 'replace',
-  to: 'rotate(40 80 160)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'rotate(10 20 30)'},
-  {at: 0, is: 'rotate(10 20 30)'},
-  {at: 0.2, is: 'rotate(10 20 30)'},
-  {at: 0.6, is: 'rotate(10 10 10) rotate(40 80 160)'},
-  {at: 1, is: 'rotate(10 10 10) rotate(40 80 160)'},
-  {at: 1.4, is: 'rotate(10 10 10) rotate(40 80 160)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'rotate(10 20 30)',
-  from: neutralKeyframe,
-  to: 'rotate(40 80 160)',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: 'rotate(-2 -4 -22)'},
-  {at: 0, is: 'rotate(10 20 30)'},
-  {at: 0.2, is: 'rotate(16 32 56)'},
-  {at: 0.6, is: 'rotate(28 56 108)'},
-  {at: 1, is: 'rotate(40 80 160)'},
-  {at: 1.4, is: 'rotate(52 104 212)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'skewX(10)',
-  from: 'skewX(30)',
-  fromComposite: 'add',
-  to: 'skewX(50)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'skewX(10) skewX(22)'},
-  {at: 0, is: 'skewX(10) skewX(30)'},
-  {at: 0.2, is: 'skewX(10) skewX(34)'},
-  {at: 0.6, is: 'skewX(10) skewX(42)'},
-  {at: 1, is: 'skewX(10) skewX(50)'},
-  {at: 1.4, is: 'skewX(10) skewX(58)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'skewX(10)',
-  from: 'skewX(30)',
-  fromComposite: 'replace',
-  to: 'skewX(50)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'skewX(30)'},
-  {at: 0, is: 'skewX(30)'},
-  {at: 0.2, is: 'skewX(30)'},
-  {at: 0.6, is: 'skewX(10) skewX(50)'},
-  {at: 1, is: 'skewX(10) skewX(50)'},
-  {at: 1.4, is: 'skewX(10) skewX(50)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'skewX(30)',
-  from: neutralKeyframe,
-  to: 'skewX(50)',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: 'skewX(22)'},
-  {at: 0, is: 'skewX(30)'},
-  {at: 0.2, is: 'skewX(34)'},
-  {at: 0.6, is: 'skewX(42)'},
-  {at: 1, is: 'skewX(50)'},
-  {at: 1.4, is: 'skewX(58)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'skewY(10)',
-  from: 'skewY(30)',
-  fromComposite: 'add',
-  to: 'skewY(50)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'skewY(10) skewY(22)'},
-  {at: 0, is: 'skewY(10) skewY(30)'},
-  {at: 0.2, is: 'skewY(10) skewY(34)'},
-  {at: 0.6, is: 'skewY(10) skewY(42)'},
-  {at: 1, is: 'skewY(10) skewY(50)'},
-  {at: 1.4, is: 'skewY(10) skewY(58)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'skewY(10)',
-  from: 'skewY(30)',
-  fromComposite: 'replace',
-  to: 'skewY(50)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'skewY(30)'},
-  {at: 0, is: 'skewY(30)'},
-  {at: 0.2, is: 'skewY(30)'},
-  {at: 0.6, is: 'skewY(10) skewY(50)'},
-  {at: 1, is: 'skewY(10) skewY(50)'},
-  {at: 1.4, is: 'skewY(10) skewY(50)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'skewY(30)',
-  from: neutralKeyframe,
-  to: 'skewY(50)',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: 'skewY(22)'},
-  {at: 0, is: 'skewY(30)'},
-  {at: 0.2, is: 'skewY(34)'},
-  {at: 0.6, is: 'skewY(42)'},
-  {at: 1, is: 'skewY(50)'},
-  {at: 1.4, is: 'skewY(58)'}
-]);
-
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-transform-matrix-expected.txt b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-transform-matrix-expected.txt
deleted file mode 100644
index 0aa5b41..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-transform-matrix-expected.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-This is a testharness.js-based test.
-[FAIL] Web Animations: Interpolate attribute <transform> with underlying [matrix(1 2 3 4 5 6)] from add [rotate(10 20 30)] to add [rotate(30 70 150)] at (-0.4) is [matrix(1 2 3 4 5 6) rotate(2 0 -18)]
-  assert_equals: expected "1 , 0 , 1 , 2 , 3 , 4 , 5 , 6 , 4 , 2 , 1 , 0.03 , - 0.03 , 1 , - 0.63 , - 0.01 " but got "4 , 2 , 1 , 0.03 , - 0.03 , 1 , - 0.63 , - 0.01 "
-[FAIL] Web Animations: Interpolate attribute <transform> with underlying [matrix(1 2 3 4 5 6)] from add [rotate(10 20 30)] to add [rotate(30 70 150)] at (0) is [matrix(1 2 3 4 5 6) rotate(10 20 30)]
-  assert_equals: expected "1 , 0 , 1 , 2 , 3 , 4 , 5 , 6 , 4 , 10 , 0.98 , 0.17 , - 0.17 , 0.98 , 5.51 , - 3.02 " but got "4 , 10 , 0.98 , 0.17 , - 0.17 , 0.98 , 5.51 , - 3.02 "
-[FAIL] Web Animations: Interpolate attribute <transform> with underlying [matrix(1 2 3 4 5 6)] from add [rotate(10 20 30)] to add [rotate(30 70 150)] at (0.2) is [matrix(1 2 3 4 5 6) rotate(14 30 54)]
-  assert_equals: expected "1 , 0 , 1 , 2 , 3 , 4 , 5 , 6 , 4 , 14 , 0.97 , 0.24 , - 0.24 , 0.97 , 13.95 , - 5.65 " but got "4 , 14 , 0.97 , 0.24 , - 0.24 , 0.97 , 13.95 , - 5.65 "
-[FAIL] Web Animations: Interpolate attribute <transform> with underlying [matrix(1 2 3 4 5 6)] from add [rotate(10 20 30)] to add [rotate(30 70 150)] at (0.6) is [matrix(1 2 3 4 5 6) rotate(22 50 102)]
-  assert_equals: expected "1 , 0 , 1 , 2 , 3 , 4 , 5 , 6 , 4 , 22 , 0.93 , 0.37 , - 0.37 , 0.93 , 41.85 , - 11.3 " but got "4 , 22 , 0.93 , 0.37 , - 0.37 , 0.93 , 41.85 , - 11.3 "
-[FAIL] Web Animations: Interpolate attribute <transform> with underlying [matrix(1 2 3 4 5 6)] from add [rotate(10 20 30)] to add [rotate(30 70 150)] at (1) is [matrix(1 2 3 4 5 6) rotate(30 70 150)]
-  assert_equals: expected "1 , 0 , 1 , 2 , 3 , 4 , 5 , 6 , 4 , 30 , 0.87 , 0.5 , - 0.5 , 0.87 , 84.38 , - 14.9 " but got "4 , 30 , 0.87 , 0.5 , - 0.5 , 0.87 , 84.38 , - 14.9 "
-[FAIL] Web Animations: Interpolate attribute <transform> with underlying [matrix(1 2 3 4 5 6)] from add [rotate(10 20 30)] to add [rotate(30 70 150)] at (1.4) is [matrix(1 2 3 4 5 6) rotate(38 90 198)]
-  assert_equals: expected "1 , 0 , 1 , 2 , 3 , 4 , 5 , 6 , 4 , 38 , 0.79 , 0.62 , - 0.62 , 0.79 , 140.98 , - 13.44 " but got "4 , 38 , 0.79 , 0.62 , - 0.62 , 0.79 , 140.98 , - 13.44 "
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-transform-matrix.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-transform-matrix.html
deleted file mode 100644
index 7207b27..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-transform-matrix.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<line x1="1" y1="2" x2="3" y2="4" class="target" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-
-assertAttributeInterpolation({
-  property: 'transform',
-  underlying: 'matrix(1 2 3 4 5 6)',
-  from: 'rotate(10 20 30)',
-  fromComposite: 'add',
-  to: 'rotate(30 70 150)',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 'matrix(1 2 3 4 5 6) rotate(2 0 -18)'},
-  {at: 0, is: 'matrix(1 2 3 4 5 6) rotate(10 20 30)'},
-  {at: 0.2, is: 'matrix(1 2 3 4 5 6) rotate(14 30 54)'},
-  {at: 0.6, is: 'matrix(1 2 3 4 5 6) rotate(22 50 102)'},
-  {at: 1, is: 'matrix(1 2 3 4 5 6) rotate(30 70 150)'},
-  {at: 1.4, is: 'matrix(1 2 3 4 5 6) rotate(38 90 198)'}
-]);
-
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-values-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-values-composition.html
deleted file mode 100644
index 2fa4709..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-values-composition.html
+++ /dev/null
@@ -1,111 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-  <defs>
-    <filter>
-      <feColorMatrix type="matrix" class="target" />
-    </filter>
-  </defs>
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'values',
-  underlying: '10, 20',
-  from: '30, 40',
-  fromComposite: 'add',
-  to: '50, -10',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '32, 80'},
-  {at: 0, is: '40, 60'},
-  {at: 0.2, is: '44, 50'},
-  {at: 0.6, is: '52, 30'},
-  {at: 1, is: '60, 10'},
-  {at: 1.4, is: '68, -10'},
-]);
-
-assertAttributeInterpolation({
-  property: 'values',
-  underlying: '10, 20',
-  from: '30',
-  fromComposite: 'add',
-  to: '50',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '32, 20'},
-  {at: 0, is: '40, 20'},
-  {at: 0.2, is: '44, 20'},
-  {at: 0.6, is: '52, 20'},
-  {at: 1, is: '60, 20'},
-  {at: 1.4, is: '68, 20'},
-]);
-
-assertAttributeInterpolation({
-  property: 'values',
-  underlying: '10',
-  from: '20, 30, 40',
-  fromComposite: 'add',
-  to: '50, 40, 30',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '18, 26, 44'},
-  {at: 0, is: '30, 30, 40'},
-  {at: 0.2, is: '36, 32, 38'},
-  {at: 0.6, is: '48, 36, 34'},
-  {at: 1, is: '60, 40, 30'},
-  {at: 1.4, is: '72, 44, 26'},
-]);
-
-assertAttributeInterpolation({
-  property: 'values',
-  underlying: '10',
-  from: '30, 40',
-  fromComposite: 'add',
-  to: '50, 60, 70',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: '40, 40'},
-  {at: 0, is: '40, 40'},
-  {at: 0.2, is: '40, 40'},
-  {at: 0.6, is: '50, 60, 70'},
-  {at: 1, is: '50, 60, 70'},
-  {at: 1.4, is: '50, 60, 70'},
-]);
-
-assertAttributeInterpolation({
-  property: 'values',
-  underlying: '10',
-  from: neutralKeyframe,
-  to: '50, -10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: '10'},
-  {at: 0, is: '10'},
-  {at: 0.2, is: '10'},
-  {at: 0.6, is: '50, -10'},
-  {at: 1, is: '50, -10'},
-  {at: 1.4, is: '50, -10'},
-]);
-
-assertAttributeInterpolation({
-  property: 'values',
-  underlying: '10, 20',
-  from: neutralKeyframe,
-  to: '50, -10',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-10, 24'},
-  {at: 0, is: '10, 20'},
-  {at: 0.2, is: '20, 18'},
-  {at: 0.6, is: '40, 14'},
-  {at: 1, is: '60, 10'},
-  {at: 1.4, is: '80, 6'},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-viewBox-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-viewBox-composition.html
deleted file mode 100644
index b8451dc..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-viewBox-composition.html
+++ /dev/null
@@ -1,78 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="0" height="0">
-  <defs>
-    <marker class="target" />
-  </defs>
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'viewBox',
-  underlying: '10, 10, 10, 10',
-  from: '10, 20, 80, 90',
-  fromComposite: 'add',
-  to: '20, 30, 70, 80',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '16, 26, 94, 104'},
-  {at: 0, is: '20, 30, 90, 100'},
-  {at: 0.2, is: '22, 32, 88, 98'},
-  {at: 0.6, is: '26, 36, 84, 94'},
-  {at: 1, is: '30, 40, 80, 90'},
-  {at: 1.4, is: '34, 44, 76, 86'},
-]);
-
-assertAttributeInterpolation({
-  property: 'viewBox',
-  underlying: '10, 10, 10, 10',
-  from: '10, 20, 80, 90',
-  fromComposite: 'add',
-  to: '20, 30, 70, 80',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: '20, 30, 98, 108'},
-  {at: 0, is: '20, 30, 90, 100'},
-  {at: 0.2, is: '20, 30, 86, 96'},
-  {at: 0.6, is: '20, 30, 78, 88'},
-  {at: 1, is: '20, 30, 70, 80'},
-  {at: 1.4, is: '20, 30, 62, 72'},
-]);
-
-assertAttributeInterpolation({
-  property: 'viewBox',
-  underlying: '10, 10, 10, 10',
-  from: '10, 20, 80, 90',
-  fromComposite: 'replace',
-  to: '20, 30, 70, 80',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '2, 12, 80, 90'},
-  {at: 0, is: '10, 20, 80, 90'},
-  {at: 0.2, is: '14, 24, 80, 90'},
-  {at: 0.6, is: '22, 32, 80, 90'},
-  {at: 1, is: '30, 40, 80, 90'},
-  {at: 1.4, is: '38, 48, 80, 90'},
-]);
-
-assertAttributeInterpolation({
-  property: 'viewBox',
-  underlying: '10, 20, 80, 90',
-  from: neutralKeyframe,
-  to: '20, 30, 70, 80',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: '6, 16, 84, 94'},
-  {at: 0, is: '10, 20, 80, 90'},
-  {at: 0.2, is: '12, 22, 78, 88'},
-  {at: 0.6, is: '16, 26, 74, 84'},
-  {at: 1, is: '20, 30, 70, 80'},
-  {at: 1.4, is: '24, 34, 66, 76'},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-width-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-width-composition.html
deleted file mode 100644
index 8d570eb..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-width-composition.html
+++ /dev/null
@@ -1,341 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script src="../../resources/ahem.js"></script>
-<style>
-:root {
-  font: 10px Ahem;
-}
-</style>
-</head>
-<body>
-<template id="target-template">
-<svg width="200px" height="300px" viewBox="0 0 1500 1000">
-  <rect class="target" x="10" y="10" width="10" height="10" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-
-// Same unit
-
-assertAttributeInterpolation({
-  property: 'width',
-  underlying: '20',
-  from: '-10',
-  fromComposite: 'add',
-  to: '40',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 10},
-  {at: 0.2, is: 20},
-  {at: 0.6, is: 40},
-  {at: 1, is: 60},
-  {at: 1.4, is: 80}
-]);
-assertAttributeInterpolation({
-  property: 'width',
-  underlying: '20%',
-  from: '-10%',
-  fromComposite: 'add',
-  to: '40%',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '0%'},
-  {at: 0, is: '10%'},
-  {at: 0.2, is: '20%'},
-  {at: 0.6, is: '40%'},
-  {at: 1, is: '60%'},
-  {at: 1.4, is: '80%'}
-]);
-assertAttributeInterpolation({
-  property: 'width',
-  underlying: '20em',
-  from: '-10em',
-  fromComposite: 'add',
-  to: '40em',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '0em'},
-  {at: 0, is: '10em'},
-  {at: 0.2, is: '20em'},
-  {at: 0.6, is: '40em'},
-  {at: 1, is: '60em'},
-  {at: 1.4, is: '80em'}
-]);
-assertAttributeInterpolation({
-  property: 'width',
-  underlying: '20ex',
-  from: '-10ex',
-  fromComposite: 'add',
-  to: '40ex',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '0ex'},
-  {at: 0, is: '10ex'},
-  {at: 0.2, is: '20ex'},
-  {at: 0.6, is: '40ex'},
-  {at: 1, is: '60ex'},
-  {at: 1.4, is: '80ex'}
-]);
-assertAttributeInterpolation({
-  property: 'width',
-  underlying: '20rem',
-  from: '-10rem',
-  fromComposite: 'add',
-  to: '40rem',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '0rem'},
-  {at: 0, is: '10rem'},
-  {at: 0.2, is: '20rem'},
-  {at: 0.6, is: '40rem'},
-  {at: 1, is: '60rem'},
-  {at: 1.4, is: '80rem'}
-]);
-
-assertAttributeInterpolation({
-  property: 'width',
-  underlying: '20',
-  from: '10',
-  fromComposite: 'replace',
-  to: '40',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 10},
-  {at: 0.2, is: 20},
-  {at: 0.6, is: 40},
-  {at: 1, is: 60},
-  {at: 1.4, is: 80}
-]);
-assertAttributeInterpolation({
-  property: 'width',
-  underlying: '20%',
-  from: '10%',
-  fromComposite: 'replace',
-  to: '40%',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '0%'},
-  {at: 0, is: '10%'},
-  {at: 0.2, is: '20%'},
-  {at: 0.6, is: '40%'},
-  {at: 1, is: '60%'},
-  {at: 1.4, is: '80%'}
-]);
-assertAttributeInterpolation({
-  property: 'width',
-  underlying: '20em',
-  from: '10em',
-  fromComposite: 'replace',
-  to: '40em',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '0em'},
-  {at: 0, is: '10em'},
-  {at: 0.2, is: '20em'},
-  {at: 0.6, is: '40em'},
-  {at: 1, is: '60em'},
-  {at: 1.4, is: '80em'}
-]);
-assertAttributeInterpolation({
-  property: 'width',
-  underlying: '20ex',
-  from: '10ex',
-  fromComposite: 'replace',
-  to: '40ex',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '0ex'},
-  {at: 0, is: '10ex'},
-  {at: 0.2, is: '20ex'},
-  {at: 0.6, is: '40ex'},
-  {at: 1, is: '60ex'},
-  {at: 1.4, is: '80ex'}
-]);
-assertAttributeInterpolation({
-  property: 'width',
-  underlying: '20rem',
-  from: '10rem',
-  fromComposite: 'replace',
-  to: '40rem',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '0rem'},
-  {at: 0, is: '10rem'},
-  {at: 0.2, is: '20rem'},
-  {at: 0.6, is: '40rem'},
-  {at: 1, is: '60rem'},
-  {at: 1.4, is: '80rem'}
-]);
-
-assertAttributeInterpolation({
-  property: 'width',
-  underlying: '10',
-  from: neutralKeyframe,
-  to: '60',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 10},
-  {at: 0.2, is: 20},
-  {at: 0.6, is: 40},
-  {at: 1, is: 60},
-  {at: 1.4, is: 80}
-]);
-assertAttributeInterpolation({
-  property: 'width',
-  underlying: '10%',
-  from: neutralKeyframe,
-  to: '60%',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: '0%'},
-  {at: 0, is: '10%'},
-  {at: 0.2, is: '20%'},
-  {at: 0.6, is: '40%'},
-  {at: 1, is: '60%'},
-  {at: 1.4, is: '80%'}
-]);
-assertAttributeInterpolation({
-  property: 'width',
-  underlying: '10em',
-  from: neutralKeyframe,
-  to: '60em',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: '0em'},
-  {at: 0, is: '10em'},
-  {at: 0.2, is: '20em'},
-  {at: 0.6, is: '40em'},
-  {at: 1, is: '60em'},
-  {at: 1.4, is: '80em'}
-]);
-assertAttributeInterpolation({
-  property: 'width',
-  underlying: '10ex',
-  from: neutralKeyframe,
-  to: '60ex',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: '0ex'},
-  {at: 0, is: '10ex'},
-  {at: 0.2, is: '20ex'},
-  {at: 0.6, is: '40ex'},
-  {at: 1, is: '60ex'},
-  {at: 1.4, is: '80ex'}
-]);
-assertAttributeInterpolation({
-  property: 'width',
-  underlying: '10rem',
-  from: neutralKeyframe,
-  to: '60rem',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: '0rem'},
-  {at: 0, is: '10rem'},
-  {at: 0.2, is: '20rem'},
-  {at: 0.6, is: '40rem'},
-  {at: 1, is: '60rem'},
-  {at: 1.4, is: '80rem'}
-]);
-
-// Mixed units
-
-assertAttributeInterpolation({
-  property: 'width',
-  underlying: '10',
-  from: '10mm',
-  fromComposite: 'add',
-  to: '20px',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '54.913387298583984'},
-  {at: 0, is: '47.79527559055118'},
-  {at: 0.2, is: '44.23622131347656'},
-  {at: 0.6, is: '37.11811065673828'},
-  {at: 1, is: '30px'},
-  {at: 1.4, is: '22.881889343261719'}
-]);
-assertAttributeInterpolation({
-  property: 'width',
-  underlying: '10mm',
-  from: '10mm',
-  fromComposite: 'add',
-  to: '20px',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '82.70866141732283'},
-  {at: 0, is: '20mm'},
-  {at: 0.2, is: '72.03149606299212'},
-  {at: 0.6, is: '64.91338582677164'},
-  {at: 1, is: '57.79527559055118'},
-  {at: 1.4, is: '50.677165354330704'}
-]);
-
-assertAttributeInterpolation({
-  property: 'width',
-  underlying: '10',
-  from: '10mm',
-  fromComposite: 'replace',
-  to: '10px',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '44.913387298583984'},
-  {at: 0, is: '10mm'},
-  {at: 0.2, is: '34.23622131347656'},
-  {at: 0.6, is: '27.11811065673828'},
-  {at: 1, is: '20px'},
-  {at: 1.4, is: '12.881889343261719'}
-]);
-assertAttributeInterpolation({
-  property: 'width',
-  underlying: '10mm',
-  from: '20mm',
-  fromComposite: 'replace',
-  to: '20px',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: '82.70866141732283'},
-  {at: 0, is: '20mm'},
-  {at: 0.2, is: '72.03149606299212'},
-  {at: 0.6, is: '64.91338582677164'},
-  {at: 1, is: '57.79527559055118'},
-  {at: 1.4, is: '50.677165354330704'}
-]);
-
-assertAttributeInterpolation({
-  property: 'width',
-  underlying: '10',
-  from: neutralKeyframe,
-  to: '60px',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 10},
-  {at: 0.2, is: 20},
-  {at: 0.6, is: 40},
-  {at: 1, is: 60},
-  {at: 1.4, is: 80}
-]);
-assertAttributeInterpolation({
-  property: 'width',
-  underlying: '10mm',
-  from: neutralKeyframe,
-  to: '20px',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: '44.913387298583984'},
-  {at: 0, is: '10mm'},
-  {at: 0.2, is: '34.23622131347656'},
-  {at: 0.6, is: '27.11811065673828'},
-  {at: 1, is: '20px'},
-  {at: 1.4, is: '12.881889343261719'}
-]);
-
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-x-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-x-composition.html
deleted file mode 100644
index 7630bc4..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-x-composition.html
+++ /dev/null
@@ -1,61 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-  <svg width="0" height="0">
-    <rect class="target"/>
-  </svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-
-assertAttributeInterpolation({
-  property: 'x',
-  underlying: '2',
-  from: '-1',
-  fromComposite: 'add',
-  to: '4',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-
-assertAttributeInterpolation({
-  property: 'x',
-  underlying: '2',
-  from: '1',
-  fromComposite: 'replace',
-  to: '4',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-
-assertAttributeInterpolation({
-  property: 'x',
-  underlying: '1',
-  from: neutralKeyframe,
-  to: '6',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-x-list-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-x-list-composition.html
deleted file mode 100644
index 6e675ed1..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-x-list-composition.html
+++ /dev/null
@@ -1,152 +0,0 @@
-<!DOCTYPE html>
-<style>
-body {
-  font-size: 10px;
-}
-</style>
-<body>
-<template id="target-template">
-  <svg width="0" height="0" viewBox="0 0 1000 1000">
-    <text class="target"/>
-  </svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-
-assertAttributeInterpolation({
-  property: 'x',
-  underlying: '1, 1, 1',
-  from: '-1, -2, 1',
-  fromComposite: 'add',
-  to: '4, -7, 6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-2, 1, 0'},
-  {at: 0, is: '0, -1, 2'},
-  {at: 0.2, is: '1, -2, 3'},
-  {at: 0.6, is: '3, -4, 5'},
-  {at: 1, is: '5, -6, 7'},
-  {at: 1.4, is: '7, -8, 9'},
-]);
-assertAttributeInterpolation({
-  property: 'x',
-  underlying: '1em, 1ex, 1rem',
-  from: '-1em, 0ex, 1rem',
-  fromComposite: 'add',
-  to: '4em, 5ex, 6rem',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-2em, -1ex, 0rem'},
-  {at: 0, is: '0em, 1ex, 2rem'},
-  {at: 0.2, is: '1em, 2ex, 3rem'},
-  {at: 0.6, is: '3em, 4ex, 5rem'},
-  {at: 1, is: '5em, 6ex, 7rem'},
-  {at: 1.4, is: '7em, 8ex, 9rem'},
-]);
-assertAttributeInterpolation({
-  property: 'x',
-  underlying: '50, 50, 0',
-  from: '50%, 0em, 0',
-  fromComposite: 'add',
-  to: '0em, 50%, 0',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '750, -150, 0'},
-  {at: 0, is: '550, 50, 0'},
-  {at: 0.2, is: '450, 150, 0'},
-  {at: 0.6, is: '250, 350, 0'},
-  {at: 1, is: '50, 550, 0'},
-  {at: 1.4, is: '-150, 750, 0'},
-]);
-
-assertAttributeInterpolation({
-  property: 'x',
-  underlying: '1, 1, 1',
-  from: '0, -1, 2',
-  fromComposite: 'replace',
-  to: '4, -7, 6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-2, 1, 0'},
-  {at: 0, is: '0, -1, 2'},
-  {at: 0.2, is: '1, -2, 3'},
-  {at: 0.6, is: '3, -4, 5'},
-  {at: 1, is: '5, -6, 7'},
-  {at: 1.4, is: '7, -8, 9'},
-]);
-assertAttributeInterpolation({
-  property: 'x',
-  underlying: '1em, 1ex, 1rem',
-  from: '0em, 1ex, 2rem',
-  fromComposite: 'replace',
-  to: '4em, 5ex, 6rem',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-2em, -1ex, 0rem'},
-  {at: 0, is: '0em, 1ex, 2rem'},
-  {at: 0.2, is: '1em, 2ex, 3rem'},
-  {at: 0.6, is: '3em, 4ex, 5rem'},
-  {at: 1, is: '5em, 6ex, 7rem'},
-  {at: 1.4, is: '7em, 8ex, 9rem'},
-]);
-assertAttributeInterpolation({
-  property: 'x',
-  underlying: '1em, 10%, 0',
-  from: '55%, 5em, 0',
-  fromComposite: 'replace',
-  to: '4em, 45%, 0',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '750, -150, 0'},
-  {at: 0, is: '550, 50, 0'},
-  {at: 0.2, is: '450, 150, 0'},
-  {at: 0.6, is: '250, 350, 0'},
-  {at: 1, is: '50, 550, 0'},
-  {at: 1.4, is: '-150, 750, 0'},
-]);
-
-assertAttributeInterpolation({
-  property: 'x',
-  underlying: '0, -1, 2',
-  from: neutralKeyframe,
-  to: '5, -6, 7',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: '-2, 1, 0'},
-  {at: 0, is: '0, -1, 2'},
-  {at: 0.2, is: '1, -2, 3'},
-  {at: 0.6, is: '3, -4, 5'},
-  {at: 1, is: '5, -6, 7'},
-  {at: 1.4, is: '7, -8, 9'},
-]);
-assertAttributeInterpolation({
-  property: 'x',
-  underlying: '0em, 1ex, 2rem',
-  from: neutralKeyframe,
-  to: '5em, 6ex, 7rem',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: '-2em, -1ex, 0rem'},
-  {at: 0, is: '0em, 1ex, 2rem'},
-  {at: 0.2, is: '1em, 2ex, 3rem'},
-  {at: 0.6, is: '3em, 4ex, 5rem'},
-  {at: 1, is: '5em, 6ex, 7rem'},
-  {at: 1.4, is: '7em, 8ex, 9rem'},
-]);
-assertAttributeInterpolation({
-  property: 'x',
-  underlying: '55%, 5em, 0',
-  from: neutralKeyframe,
-  to: '5em, 55%, 0',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: '750, -150, 0'},
-  {at: 0, is: '550, 50, 0'},
-  {at: 0.2, is: '450, 150, 0'},
-  {at: 0.6, is: '250, 350, 0'},
-  {at: 1, is: '50, 550, 0'},
-  {at: 1.4, is: '-150, 750, 0'},
-]);
-</script>
-</body>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-x1-x2-y1-y2-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-x1-x2-y1-y2-composition.html
deleted file mode 100644
index f8c82695..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-x1-x2-y1-y2-composition.html
+++ /dev/null
@@ -1,192 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<line class="target" x1="10" y1="10" x2="60" y2="60" />
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'x1',
-  underlying: 20,
-  from: -10,
-  fromComposite: 'add',
-  to: 40,
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: -10},
-  {at: 0, is: 10},
-  {at: 0.2, is: 20},
-  {at: 0.6, is: 40},
-  {at: 1, is: 60},
-  {at: 1.4, is: 80}
-]);
-assertAttributeInterpolation({
-  property: 'x2',
-  underlying: 20,
-  from: -10,
-  fromComposite: 'add',
-  to: 40,
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: -10},
-  {at: 0, is: 10},
-  {at: 0.2, is: 20},
-  {at: 0.6, is: 40},
-  {at: 1, is: 60},
-  {at: 1.4, is: 80}
-]);
-assertAttributeInterpolation({
-  property: 'y1',
-  underlying: 20,
-  from: -10,
-  fromComposite: 'add',
-  to: 40,
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: -10},
-  {at: 0, is: 10},
-  {at: 0.2, is: 20},
-  {at: 0.6, is: 40},
-  {at: 1, is: 60},
-  {at: 1.4, is: 80}
-]);
-assertAttributeInterpolation({
-  property: 'y2',
-  underlying: 20,
-  from: -10,
-  fromComposite: 'add',
-  to: 40,
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: -10},
-  {at: 0, is: 10},
-  {at: 0.2, is: 20},
-  {at: 0.6, is: 40},
-  {at: 1, is: 60},
-  {at: 1.4, is: 80}
-]);
-
-assertAttributeInterpolation({
-  property: 'x1',
-  underlying: 20,
-  from: 10,
-  fromComposite: 'replace',
-  to: 40,
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: -10},
-  {at: 0, is: 10},
-  {at: 0.2, is: 20},
-  {at: 0.6, is: 40},
-  {at: 1, is: 60},
-  {at: 1.4, is: 80}
-]);
-assertAttributeInterpolation({
-  property: 'x2',
-  underlying: 20,
-  from: 10,
-  fromComposite: 'replace',
-  to: 40,
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: -10},
-  {at: 0, is: 10},
-  {at: 0.2, is: 20},
-  {at: 0.6, is: 40},
-  {at: 1, is: 60},
-  {at: 1.4, is: 80}
-]);
-assertAttributeInterpolation({
-  property: 'y1',
-  underlying: 20,
-  from: 10,
-  fromComposite: 'replace',
-  to: 40,
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: -10},
-  {at: 0, is: 10},
-  {at: 0.2, is: 20},
-  {at: 0.6, is: 40},
-  {at: 1, is: 60},
-  {at: 1.4, is: 80}
-]);
-assertAttributeInterpolation({
-  property: 'y2',
-  underlying: 20,
-  from: 10,
-  fromComposite: 'replace',
-  to: 40,
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: -10},
-  {at: 0, is: 10},
-  {at: 0.2, is: 20},
-  {at: 0.6, is: 40},
-  {at: 1, is: 60},
-  {at: 1.4, is: 80}
-]);
-
-assertAttributeInterpolation({
-  property: 'x1',
-  underlying: 10,
-  from: neutralKeyframe,
-  to: 60,
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: -10},
-  {at: 0, is: 10},
-  {at: 0.2, is: 20},
-  {at: 0.6, is: 40},
-  {at: 1, is: 60},
-  {at: 1.4, is: 80}
-]);
-assertAttributeInterpolation({
-  property: 'x2',
-  underlying: 10,
-  from: neutralKeyframe,
-  to: 60,
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: -10},
-  {at: 0, is: 10},
-  {at: 0.2, is: 20},
-  {at: 0.6, is: 40},
-  {at: 1, is: 60},
-  {at: 1.4, is: 80}
-]);
-assertAttributeInterpolation({
-  property: 'y1',
-  underlying: 10,
-  from: neutralKeyframe,
-  to: 60,
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: -10},
-  {at: 0, is: 10},
-  {at: 0.2, is: 20},
-  {at: 0.6, is: 40},
-  {at: 1, is: 60},
-  {at: 1.4, is: 80}
-]);
-assertAttributeInterpolation({
-  property: 'y2',
-  underlying: 10,
-  from: neutralKeyframe,
-  to: 60,
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: -10},
-  {at: 0, is: 10},
-  {at: 0.2, is: 20},
-  {at: 0.6, is: 40},
-  {at: 1, is: 60},
-  {at: 1.4, is: 80}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-y-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-y-composition.html
deleted file mode 100644
index 557f68e..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-y-composition.html
+++ /dev/null
@@ -1,61 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-  <svg width="0" height="0">
-    <rect class="target"/>
-  </svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-
-assertAttributeInterpolation({
-  property: 'y',
-  underlying: '2',
-  from: '-1',
-  fromComposite: 'add',
-  to: '4',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-
-assertAttributeInterpolation({
-  property: 'y',
-  underlying: '2',
-  from: '1',
-  fromComposite: 'replace',
-  to: '4',
-  toComposite: 'add'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-
-assertAttributeInterpolation({
-  property: 'y',
-  underlying: '1',
-  from: neutralKeyframe,
-  to: '6',
-  toComposite: 'replace'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-y-list-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-y-list-composition.html
deleted file mode 100644
index efd2d56..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-y-list-composition.html
+++ /dev/null
@@ -1,152 +0,0 @@
-<!DOCTYPE html>
-<style>
-body {
-  font-size: 10px;
-}
-</style>
-<body>
-<template id="target-template">
-  <svg width="0" height="0" viewBox="0 0 1000 1000">
-    <text class="target"/>
-  </svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-
-assertAttributeInterpolation({
-  property: 'y',
-  underlying: '1, 1, 1',
-  from: '-1, -2, 1',
-  fromComposite: 'add',
-  to: '4, -7, 6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-2, 1, 0'},
-  {at: 0, is: '0, -1, 2'},
-  {at: 0.2, is: '1, -2, 3'},
-  {at: 0.6, is: '3, -4, 5'},
-  {at: 1, is: '5, -6, 7'},
-  {at: 1.4, is: '7, -8, 9'},
-]);
-assertAttributeInterpolation({
-  property: 'y',
-  underlying: '1em, 1ex, 1rem',
-  from: '-1em, 0ex, 1rem',
-  fromComposite: 'add',
-  to: '4em, 5ex, 6rem',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-2em, -1ex, 0rem'},
-  {at: 0, is: '0em, 1ex, 2rem'},
-  {at: 0.2, is: '1em, 2ex, 3rem'},
-  {at: 0.6, is: '3em, 4ex, 5rem'},
-  {at: 1, is: '5em, 6ex, 7rem'},
-  {at: 1.4, is: '7em, 8ex, 9rem'},
-]);
-assertAttributeInterpolation({
-  property: 'y',
-  underlying: '50, 50, 0',
-  from: '50%, 0em, 0',
-  fromComposite: 'add',
-  to: '0em, 50%, 0',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '750, -150, 0'},
-  {at: 0, is: '550, 50, 0'},
-  {at: 0.2, is: '450, 150, 0'},
-  {at: 0.6, is: '250, 350, 0'},
-  {at: 1, is: '50, 550, 0'},
-  {at: 1.4, is: '-150, 750, 0'},
-]);
-
-assertAttributeInterpolation({
-  property: 'y',
-  underlying: '1, 1, 1',
-  from: '0, -1, 2',
-  fromComposite: 'replace',
-  to: '4, -7, 6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-2, 1, 0'},
-  {at: 0, is: '0, -1, 2'},
-  {at: 0.2, is: '1, -2, 3'},
-  {at: 0.6, is: '3, -4, 5'},
-  {at: 1, is: '5, -6, 7'},
-  {at: 1.4, is: '7, -8, 9'},
-]);
-assertAttributeInterpolation({
-  property: 'y',
-  underlying: '1em, 1ex, 1rem',
-  from: '0em, 1ex, 2rem',
-  fromComposite: 'replace',
-  to: '4em, 5ex, 6rem',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '-2em, -1ex, 0rem'},
-  {at: 0, is: '0em, 1ex, 2rem'},
-  {at: 0.2, is: '1em, 2ex, 3rem'},
-  {at: 0.6, is: '3em, 4ex, 5rem'},
-  {at: 1, is: '5em, 6ex, 7rem'},
-  {at: 1.4, is: '7em, 8ex, 9rem'},
-]);
-assertAttributeInterpolation({
-  property: 'y',
-  underlying: '1em, 10%, 0',
-  from: '55%, 5em, 0',
-  fromComposite: 'replace',
-  to: '4em, 45%, 0',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: '750, -150, 0'},
-  {at: 0, is: '550, 50, 0'},
-  {at: 0.2, is: '450, 150, 0'},
-  {at: 0.6, is: '250, 350, 0'},
-  {at: 1, is: '50, 550, 0'},
-  {at: 1.4, is: '-150, 750, 0'},
-]);
-
-assertAttributeInterpolation({
-  property: 'y',
-  underlying: '0, -1, 2',
-  from: neutralKeyframe,
-  to: '5, -6, 7',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: '-2, 1, 0'},
-  {at: 0, is: '0, -1, 2'},
-  {at: 0.2, is: '1, -2, 3'},
-  {at: 0.6, is: '3, -4, 5'},
-  {at: 1, is: '5, -6, 7'},
-  {at: 1.4, is: '7, -8, 9'},
-]);
-assertAttributeInterpolation({
-  property: 'y',
-  underlying: '0em, 1ex, 2rem',
-  from: neutralKeyframe,
-  to: '5em, 6ex, 7rem',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: '-2em, -1ex, 0rem'},
-  {at: 0, is: '0em, 1ex, 2rem'},
-  {at: 0.2, is: '1em, 2ex, 3rem'},
-  {at: 0.6, is: '3em, 4ex, 5rem'},
-  {at: 1, is: '5em, 6ex, 7rem'},
-  {at: 1.4, is: '7em, 8ex, 9rem'},
-]);
-assertAttributeInterpolation({
-  property: 'y',
-  underlying: '55%, 5em, 0',
-  from: neutralKeyframe,
-  to: '5em, 55%, 0',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: '750, -150, 0'},
-  {at: 0, is: '550, 50, 0'},
-  {at: 0.2, is: '450, 150, 0'},
-  {at: 0.6, is: '250, 350, 0'},
-  {at: 1, is: '50, 550, 0'},
-  {at: 1.4, is: '-150, 750, 0'},
-]);
-</script>
-</body>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-z-composition.html b/third_party/blink/web_tests/animations/svg-attribute-composition/svg-z-composition.html
deleted file mode 100644
index f83dcaf..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-composition/svg-z-composition.html
+++ /dev/null
@@ -1,64 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="0" height="0">
-<defs>
-<filter>
-<fePointLight class="target" />
-</filter>
-</defs>
-</svg>
-</template>
-<script src="../svg-attribute-interpolation/resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'z',
-  underlying: '3',
-  from: '1',
-  fromComposite: 'add',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: 2},
-  {at: 0, is: 4},
-  {at: 0.2, is: 5},
-  {at: 0.6, is: 7},
-  {at: 1, is: 9},
-  {at: 1.4, is: 11},
-]);
-
-assertAttributeInterpolation({
-  property: 'z',
-  underlying: '5',
-  from: '1',
-  fromComposite: 'replace',
-  to: '6',
-  toComposite: 'add',
-}, [
-  {at: -0.4, is: -3},
-  {at: 0, is: 1},
-  {at: 0.2, is: 3},
-  {at: 0.6, is: 7},
-  {at: 1, is: 11},
-  {at: 1.4, is: 15},
-]);
-
-assertAttributeInterpolation({
-  property: 'z',
-  underlying: '5',
-  from: neutralKeyframe,
-  to: '10',
-  toComposite: 'replace',
-}, [
-  {at: -0.4, is: 3},
-  {at: 0, is: 5},
-  {at: 0.2, is: 6},
-  {at: 0.6, is: 8},
-  {at: 1, is: 10},
-  {at: 1.4, is: 12},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/resources/interpolation-test.js b/third_party/blink/web_tests/animations/svg-attribute-interpolation/resources/interpolation-test.js
deleted file mode 100644
index dcb27c7b..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/resources/interpolation-test.js
+++ /dev/null
@@ -1,479 +0,0 @@
-/* Copyright 2015 The Chromium Authors
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- *
- * Exported function:
- *  - assertAttributeInterpolation({property, from, to, [fromComposite], [toComposite], [underlying]}, [{at: fraction, is: value}])
- *        Constructs a test case for each fraction that asserts the expected value
- *        equals the value produced by interpolation between from and to composited
- *        onto underlying by fromComposite and toComposite respectively using
- *        SMIL and Web Animations.
- *        Set from/to to the exported neutralKeyframe object to specify neutral keyframes.
- *        SMIL will only be tested with equal fromComposite and toComposite values.
-*/
-'use strict';
-(() => {
-  var interpolationTests = [];
-  var neutralKeyframe = {};
-
-  // Set to true to output rebaselined test expectations.
-  var rebaselineTests = false;
-
-  function isNeutralKeyframe(keyframe) {
-    return keyframe === neutralKeyframe;
-  }
-
-  function createElement(tagName, container) {
-    var element = document.createElement(tagName);
-    if (container) {
-      container.appendChild(element);
-    }
-    return element;
-  }
-
-  // Constructs a timing function which produces 'y' at x = 0.5
-  function createEasing(y) {
-    // FIXME: if 'y' is > 0 and < 1 use a linear timing function and allow
-    // 'x' to vary. Use a bezier only for values < 0 or > 1.
-    if (y == 0) {
-      return 'steps(1, end)';
-    }
-    if (y == 1) {
-      return 'steps(1, start)';
-    }
-    if (y == 0.5) {
-      return 'steps(2, end)';
-    }
-    // Approximate using a bezier.
-    var b = (8 * y - 1) / 6;
-    return 'cubic-bezier(0, ' + b + ', 1, ' + b + ')';
-  }
-
-  function assertAttributeInterpolation(params, expectations) {
-    interpolationTests.push({params, expectations});
-  }
-
-  function roundNumbers(value) {
-    return value.
-        // Round numbers to two decimal places.
-        replace(/-?\d*\.\d+(e-?\d+)?/g, function(n) {
-          return (parseFloat(n).toFixed(2)).
-              replace(/\.\d+/, function(m) {
-                return m.replace(/0+$/, '');
-              }).
-              replace(/\.$/, '').
-              replace(/^-0$/, '0');
-        });
-  }
-
-  function normalizeValue(value) {
-    return roundNumbers(value).
-        // Place whitespace between tokens.
-        replace(/([\w\d.]+|[^\s])/g, '$1 ').
-        replace(/\s+/g, ' ');
-  }
-
-  function createTarget(container) {
-    var targetContainer = createElement('div');
-    var template = document.querySelector('#target-template');
-    if (template) {
-      targetContainer.appendChild(template.content.cloneNode(true));
-      // Remove whitespace text nodes at start / end.
-      while (targetContainer.firstChild.nodeType != Node.ELEMENT_NODE && !/\S/.test(targetContainer.firstChild.nodeValue)) {
-        targetContainer.removeChild(targetContainer.firstChild);
-      }
-      while (targetContainer.lastChild.nodeType != Node.ELEMENT_NODE && !/\S/.test(targetContainer.lastChild.nodeValue)) {
-        targetContainer.removeChild(targetContainer.lastChild);
-      }
-      // If the template contains just one element, use that rather than a wrapper div.
-      if (targetContainer.children.length == 1 && targetContainer.childNodes.length == 1) {
-        targetContainer = targetContainer.firstChild;
-      }
-      container.appendChild(targetContainer);
-    }
-    var target = targetContainer.querySelector('.target') || targetContainer;
-    target.container = targetContainer;
-    return target;
-  }
-
-  var anchor = createElement('a');
-  function sanitizeUrls(value) {
-    var matches = value.match(/url\([^\)]*\)/g);
-    if (matches !== null) {
-      for (var i = 0; i < matches.length; ++i) {
-        var url = /url\(([^\)]*)\)/g.exec(matches[i])[1];
-        anchor.href = url;
-        anchor.pathname = '...' + anchor.pathname.substring(anchor.pathname.lastIndexOf('/'));
-        value = value.replace(matches[i], 'url(' + anchor.href + ')');
-      }
-    }
-    return value;
-  }
-
-  function serializeSVGLengthList(numberList) {
-    var elements = [];
-    for (var index = 0; index < numberList.numberOfItems; ++index)
-      elements.push(numberList.getItem(index).value);
-    return String(elements);
-  }
-
-  function serializeSVGNumberList(numberList) {
-    return Array.from(numberList).map(number => number.value).join(', ');
-  }
-
-  function serializeSVGPointList(pointList) {
-    var elements = [];
-    for (var index = 0; index < pointList.numberOfItems; ++index) {
-      var point = pointList.getItem(index);
-      elements.push(point.x);
-      elements.push(point.y);
-    }
-    return String(elements);
-  }
-
-  function serializeSVGPreserveAspectRatio(preserveAspectRatio) {
-    return String([preserveAspectRatio.align, preserveAspectRatio.meetOrSlice]);
-  }
-
-  function serializeSVGRect(rect) {
-    return [rect.x, rect.y, rect.width, rect.height].join(', ');
-  }
-
-  function serializeSVGTransformList(transformList) {
-    var elements = [];
-    for (var index = 0; index < transformList.numberOfItems; ++index) {
-      var transform = transformList.getItem(index);
-      elements.push(transform.type);
-      elements.push(transform.angle);
-      elements.push(transform.matrix.a);
-      elements.push(transform.matrix.b);
-      elements.push(transform.matrix.c);
-      elements.push(transform.matrix.d);
-      elements.push(transform.matrix.e);
-      elements.push(transform.matrix.f);
-    }
-    return String(elements);
-  }
-
-  var svgNamespace = 'http://www.w3.org/2000/svg';
-  var xlinkNamespace = 'http://www.w3.org/1999/xlink';
-
-  var animatedNumberOptionalNumberAttributes = [
-    'baseFrequency',
-    'kernelUnitLength',
-    'order',
-    'radius',
-    'stdDeviation',
-  ];
-
-  function namespacedAttributeName(attributeName) {
-    if (attributeName === 'href')
-      return 'xlink:href';
-    return attributeName;
-  }
-
-  function getAttributeValue(element, attributeName) {
-    if (animatedNumberOptionalNumberAttributes.includes(attributeName))
-      return getAttributeValue(element, attributeName + 'X') + ', ' + getAttributeValue(element, attributeName + 'Y');
-
-    // The attribute 'class' is exposed in IDL as 'className'
-    if (attributeName === 'class')
-      attributeName = 'className';
-
-    // The attribute 'in' is exposed in IDL as 'in1'
-    if (attributeName === 'in')
-      attributeName = 'in1';
-
-    // The attribute 'orient' is exposed in IDL as 'orientType' and 'orientAngle'
-    if (attributeName === 'orient') {
-      if (element['orientType'] && element['orientType'].animVal === SVGMarkerElement.SVG_MARKER_ORIENT_AUTO)
-        return 'auto';
-      attributeName = 'orientAngle';
-    }
-
-    var result = null;
-    if (attributeName === 'd')
-      result = getComputedStyle(element).getPropertyValue('d');
-    else if (attributeName === 'points')
-      result = element['animatedPoints'];
-    else
-      result = element[attributeName].animVal;
-
-    if (result === null) {
-      if (attributeName === 'pathLength')
-        return '0';
-      if (attributeName === 'preserveAlpha')
-        return 'false';
-
-      console.error('Unknown attribute, cannot get ' + attributeName);
-      return null;
-    }
-
-    if (result instanceof SVGAngle || result instanceof SVGLength)
-      result = result.value;
-    else if (result instanceof SVGLengthList)
-      result = serializeSVGLengthList(result);
-    else if (result instanceof SVGNumberList)
-      result = serializeSVGNumberList(result);
-    else if (result instanceof SVGPointList)
-      result = serializeSVGPointList(result);
-    else if (result instanceof SVGPreserveAspectRatio)
-      result = serializeSVGPreserveAspectRatio(result);
-    else if (result instanceof SVGRect)
-      result = serializeSVGRect(result);
-    else if (result instanceof SVGTransformList)
-      result = serializeSVGTransformList(result);
-
-    if (typeof result !== 'string' && typeof result !== 'number' && typeof result !== 'boolean') {
-      console.error('Attribute value has unexpected type: ' + result);
-    }
-
-    return String(result);
-  }
-
-  function setAttributeValue(element, attributeName, expectation) {
-    if (!element[attributeName]
-        && attributeName !== 'class'
-        && attributeName !== 'd'
-        && (attributeName !== 'in' || !element['in1'])
-        && (attributeName !== 'orient' || !element['orientType'])
-        && (animatedNumberOptionalNumberAttributes.indexOf(attributeName) === -1 || !element[attributeName + 'X'])) {
-      console.error('Unknown attribute, cannot set ' + attributeName);
-      return;
-    }
-
-    if (attributeName.toLowerCase().indexOf('transform') === -1) {
-      var setElement = document.createElementNS(svgNamespace, 'set');
-      setElement.setAttribute('attributeName', namespacedAttributeName(attributeName));
-      setElement.setAttribute('attributeType', 'XML');
-      setElement.setAttribute('to', expectation);
-      element.appendChild(setElement);
-    } else {
-      element.setAttribute(attributeName, expectation);
-    }
-  }
-
-  function createAnimateElement(attributeName, from, to, composite)
-  {
-    var animateElement;
-    if (attributeName.toLowerCase().includes('transform')) {
-      if (isNeutralKeyframe(from) || isNeutralKeyframe(to)) {
-        return null;
-      }
-      from = from.split(')');
-      to = to.split(')');
-      // Discard empty string at end.
-      from.pop();
-      to.pop();
-
-      // SMIL requires separate animateTransform elements for each transform in the list.
-      if (from.length !== 1 || to.length !== 1) {
-        return null;
-      }
-
-      from = from[0].split('(');
-      to = to[0].split('(');
-      if (from[0].trim() !== to[0].trim()) {
-        return null;
-      }
-
-      animateElement = document.createElementNS(svgNamespace, 'animateTransform');
-      animateElement.setAttribute('type', from[0].trim());
-      animateElement.setAttribute('from', from[1]);
-      animateElement.setAttribute('to', to[1]);
-    } else {
-      animateElement = document.createElementNS(svgNamespace, 'animate');
-      animateElement.setAttribute('from', from);
-      animateElement.setAttribute('to', to);
-    }
-
-    animateElement.setAttribute('attributeName', namespacedAttributeName(attributeName));
-    animateElement.setAttribute('attributeType', 'XML');
-    animateElement.setAttribute('begin', '0');
-    animateElement.setAttribute('dur', '1');
-    animateElement.setAttribute('fill', 'freeze');
-    animateElement.setAttribute('additive', composite === 'add' ? 'sum' : composite);
-    return animateElement;
-  }
-
-  function createTestTarget(method, description, container, params, expectation, rebaselineExpectation) {
-    var target = createTarget(container);
-    if (params.underlying) {
-      target.setAttribute(params.property, params.underlying);
-    }
-
-    var expected = createTarget(container);
-    setAttributeValue(expected, params.property, expectation.is);
-
-    target.interpolate = function() {
-      switch (method) {
-      case 'SMIL':
-        console.assert(params.fromComposite === params.toComposite);
-        var animateElement = createAnimateElement(params.property, params.from, params.to, params.fromComposite);
-        if (animateElement) {
-          target.appendChild(animateElement);
-          target.container.pauseAnimations();
-          target.container.setCurrentTime(expectation.at);
-        } else {
-          target.container.remove();
-          target.measure = function() {};
-        }
-        break;
-      case 'Web Animations':
-        // Replace 'transform' with 'svg-transform', etc. This avoids collisions with CSS properties or the Web Animations API (offset).
-        var prefixedProperty = 'svg-' + params.property;
-        var keyframes = [];
-        if (!isNeutralKeyframe(params.from)) {
-          keyframes.push({
-            offset: 0,
-            [prefixedProperty]: params.from,
-            composite: params.fromComposite,
-          });
-        }
-        if (!isNeutralKeyframe(params.to)) {
-          keyframes.push({
-            offset: 1,
-            [prefixedProperty]: params.to,
-            composite: params.toComposite,
-          });
-        }
-        target.animate(keyframes, {
-          fill: 'forwards',
-          duration: 1,
-          easing: createEasing(expectation.at),
-          delay: -0.5,
-          iterations: 0.5,
-        });
-        break;
-      default:
-        console.error('Unknown test method: ' + method);
-      }
-    };
-
-    target.measure = function() {
-      test(function() {
-        var actualResult = getAttributeValue(target, params.property);
-        if (rebaselineExpectation) {
-          var roundResult = roundNumbers(actualResult);
-          rebaselineExpectation.textContent += `  {at: ${expectation.at}, is: '${roundResult}'},\n`;
-        }
-
-        assert_equals(
-          normalizeValue(actualResult),
-          normalizeValue(getAttributeValue(expected, params.property)));
-      }, `${method}: ${description} at (${expectation.at}) is [${expectation.is}]`);
-    };
-
-    return target;
-  }
-
-  function createTestTargets(interpolationTests, container, rebaselineContainer) {
-    var targets = [];
-    for (var interpolationTest of interpolationTests) {
-      var params = interpolationTest.params;
-      assert_true('property' in params);
-      assert_true('from' in params);
-      assert_true('to' in params);
-      params.fromComposite = isNeutralKeyframe(params.from) ? 'add' : (params.fromComposite || 'replace');
-      params.toComposite = isNeutralKeyframe(params.to) ? 'add' : (params.toComposite || 'replace');
-      var underlyingText = params.underlying ? `with underlying [${params.underlying}] ` : '';
-      var fromText = isNeutralKeyframe(params.from) ? 'neutral' : `${params.fromComposite} [${params.from}]`;
-      var toText = isNeutralKeyframe(params.to) ? 'neutral' : `${params.toComposite} [${params.to}]`;
-      var description = `Interpolate attribute <${params.property}> ${underlyingText}from ${fromText} to ${toText}`;
-
-      if (rebaselineTests) {
-        var rebaseline = createElement('pre', rebaselineContainer);
-
-        var assertionCode =
-          `assertAttributeInterpolation({\n` +
-          `  property: '${params.property}',\n` +
-          `  underlying: '${params.underlying}',\n`;
-
-
-        if (isNeutralKeyframe(params.from)) {
-          assertionCode += `  from: neutralKeyframe,\n`;
-        } else {
-          assertionCode +=
-            `  from: '${params.from}',\n` +
-            `  fromComposite: '${params.fromComposite}',\n`;
-        }
-
-        if (isNeutralKeyframe(params.to)) {
-          assertionCode += `  to: neutralKeyframe,\n`;
-        } else {
-          assertionCode +=
-            `  to: '${params.to}',\n` +
-            `  toComposite: '${params.toComposite}',\n`;
-        }
-
-        assertionCode += `}, [\n`;
-
-        rebaseline.appendChild(document.createTextNode(assertionCode));
-        var rebaselineExpectation = document.createTextNode('');
-        rebaseline.appendChild(rebaselineExpectation);
-        rebaseline.appendChild(document.createTextNode(']);\n\n'));
-      }
-
-      for (var method of ['SMIL', 'Web Animations']) {
-        if (method === 'SMIL' && params.fromComposite !== params.toComposite) {
-          continue;
-        }
-        createElement('pre', container).textContent = `${method}: ${description}`;
-        var smilContainer = createElement('div', container);
-        for (var expectation of interpolationTest.expectations) {
-          if (method === 'SMIL' && (expectation.at < 0 || expectation.at > 1)) {
-            continue;
-          }
-          targets.push(createTestTarget(method, description, smilContainer, params, expectation, method === 'SMIL' ? null : rebaselineExpectation));
-        }
-      }
-    }
-    return targets;
-  }
-
-  function runTests() {
-    return new Promise((resolve) => {
-      var container = createElement('div', document.body);
-      var rebaselineContainer = createElement('pre', document.body);
-      var targets = createTestTargets(interpolationTests, container, rebaselineContainer);
-
-      requestAnimationFrame(() => {
-        for (var target of targets) {
-          target.interpolate();
-        }
-
-        requestAnimationFrame(() => {
-          for (var target of targets) {
-            target.measure();
-          }
-
-          if (window.testRunner) {
-            container.style.display = 'none';
-          }
-
-          resolve();
-        });
-      });
-    });
-  }
-
-  function loadScript(url) {
-    return new Promise(function(resolve) {
-      var script = createElement('script', document.head);
-      script.src = url;
-      script.onload = resolve;
-    });
-  }
-
-  loadScript('../../resources/testharness.js').then(() => {
-    return loadScript('../../resources/testharnessreport.js');
-  }).then(() => {
-    var asyncHandle = async_test('This test uses interpolation-test.js.')
-    requestAnimationFrame(() => {
-      runTests().then(() => asyncHandle.done());
-    });
-  });
-
-  window.assertAttributeInterpolation = assertAttributeInterpolation;
-  window.neutralKeyframe = neutralKeyframe;
-})();
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-amplitude-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-amplitude-interpolation.html
deleted file mode 100644
index e54d591..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-amplitude-interpolation.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<feComponentTransfer>
-<feFuncR type="gamma" class="target" />
-</feComponentTransfer>
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'amplitude',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-azimuth-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-azimuth-interpolation.html
deleted file mode 100644
index 2818c152..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-azimuth-interpolation.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<feDistantLight class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'azimuth',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-baseFrequency-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-baseFrequency-interpolation.html
deleted file mode 100644
index b9e44e47..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-baseFrequency-interpolation.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg xmlns="http://www.w3.org/2000/svg" width="90" height="90">
-<feTurbulence class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'baseFrequency',
-  from: '1',
-  to: '6 11'
-}, [
-  {at: -0.4, is: '-1, -3'},
-  {at: 0, is: '1, 1'},
-  {at: 0.2, is: '2, 3'},
-  {at: 0.6, is: '4, 7'},
-  {at: 1, is: '6, 11'},
-  {at: 1.4, is: '8, 15'}
-]);
-assertAttributeInterpolation({
-  property: 'baseFrequency',
-  from: '-2 10',
-  to: '3 10'
-}, [
-  {at: -0.4, is: '-4, 10'},
-  {at: 0, is: '-2 10'},
-  {at: 0.2, is: '-1, 10'},
-  {at: 0.6, is: '1, 10'},
-  {at: 1, is: '3, 10'},
-  {at: 1.4, is: '5, 10'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-bias-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-bias-interpolation.html
deleted file mode 100644
index cb353873..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-bias-interpolation.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<feConvolveMatrix class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'bias',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-calc-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-calc-interpolation.html
deleted file mode 100644
index 448aa01..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-calc-interpolation.html
+++ /dev/null
@@ -1,91 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="50" height="50">
-<ellipse class="target" cx="40" cy="30" rx="20" ry="30" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'cx',
-  from: 'calc(50% - 25px)',
-  to: 'calc(100% - 10px)'
-}, [
-  {at: -0.25, is: '-10px'},
-  {at: 0, is: '0px'},
-  {at: 0.25, is: '10px'},
-  {at: 0.5, is: '20px'},
-  {at: 0.75, is: '30px'},
-  {at: 1, is: '40px'},
-  {at: 1.25, is: '50px'}
-]);
-assertAttributeInterpolation({
-  property: 'cy',
-  from: '0%',
-  to: '100px'
-}, [
-  {at: -0.25, is: 'calc(0% + -25px)'},
-  {at: 0, is: '0%'},
-  {at: 0.25, is: 'calc(0% + 25px)'},
-  {at: 0.5, is: 'calc(0% + 50px)'},
-  {at: 0.75, is: 'calc(0% + 75px)'},
-  {at: 1, is: '100px'},
-  {at: 1.25, is: 'calc(0% + 125px)'}
-]);
-assertAttributeInterpolation({
-  property: 'cy',
-  from: '0%',
-  to: '100'
-}, [
-  {at: -0.25, is: 'calc(0% + -25px)'},
-  {at: 0, is: '0%'},
-  {at: 0.25, is: 'calc(0% + 25px)'},
-  {at: 0.5, is: 'calc(0% + 50px)'},
-  {at: 0.75, is: 'calc(0% + 75px)'},
-  {at: 1, is: '100px'},
-  {at: 1.25, is: 'calc(0% + 125px)'}
-]);
-assertAttributeInterpolation({
-  property: 'cy',
-  from: '10%',
-  to: 'calc(10% + 100px)'
-}, [
-  {at: -0.25, is: 'calc(10% + -25px)'},
-  {at: 0, is: '10%'},
-  {at: 0.25, is: 'calc(10% + 25px)'},
-  {at: 0.5, is: 'calc(10% + 50px)'},
-  {at: 0.75, is: 'calc(10% + 75px)'},
-  {at: 1, is: 'calc(10% + 100px)'},
-  {at: 1.25, is: 'calc(10% + 125px)'}
-]);
-assertAttributeInterpolation({
-  property: 'cy',
-  from: 'calc(50% - 25px)',
-  to: 'calc(100% - 10px)'
-}, [
-  {at: -0.25, is: 'calc(((50% - 25px) * 1.25) + ((100% - 10px) * -0.25))'},
-  {at: 0, is: 'calc(50% - 25px)'},
-  {at: 0.25, is: 'calc(((50% - 25px) * 0.75) + ((100% - 10px) * 0.25))'},
-  {at: 0.5, is: 'calc(((50% - 25px) * 0.5) + ((100% - 10px) * 0.5))'},
-  {at: 0.75, is: 'calc(((50% - 25px) * 0.25) + ((100% - 10px) * 0.75))'},
-  {at: 1, is: 'calc(100% - 10px)'},
-  {at: 1.25, is: 'calc(((50% - 25px) * -0.25) + ((100% - 10px) * 1.25))'}
-]);
-assertAttributeInterpolation({
-  property: 'cy',
-  from: 'calc(10mm + 0in)',
-  to: 'calc(10mm + 100in)'
-}, [
-  {at: -0.25, is: 'calc(10mm + -25in)'},
-  {at: 0, is: '10mm'},
-  {at: 0.25, is: 'calc(10mm + 25in)'},
-  {at: 0.5, is: 'calc(10mm + 50in)'},
-  {at: 0.75, is: 'calc(10mm + 75in)'},
-  {at: 1, is: 'calc(10mm + 100in)'},
-  {at: 1.25, is: 'calc(10mm + 125in)'}
-]);
-</script>
-</body>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-class-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-class-interpolation.html
deleted file mode 100644
index 4a6e555..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-class-interpolation.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<rect class="target" left="10" right="20" width="40" height="30" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'class',
-  from: 'old',
-  to: 'new'
-}, [
-  {at: -0.4, is: 'old'},
-  {at: 0, is: 'old'},
-  {at: 0.2, is: 'old'},
-  {at: 0.6, is: 'new'},
-  {at: 1, is: 'new'},
-  {at: 1.4, is: 'new'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-clipPathUnits-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-clipPathUnits-interpolation.html
deleted file mode 100644
index ff73a35..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-clipPathUnits-interpolation.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<clipPath class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'clipPathUnits',
-  from: 'userSpaceOnUse',
-  to: 'objectBoundingBox',
-}, [
-  {at: -2.4, is: 'userSpaceOnUse'},
-  {at: 0, is: 'userSpaceOnUse'},
-  {at: 0.2, is: 'userSpaceOnUse'},
-  {at: 0.6, is: 'objectBoundingBox'},
-  {at: 1, is: 'objectBoundingBox'},
-  {at: 3.4, is: 'objectBoundingBox'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-cx-cy-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-cx-cy-interpolation.html
deleted file mode 100644
index c03a84a7..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-cx-cy-interpolation.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<ellipse class="target" cx="40" cy="30" rx="20" ry="30" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'cx',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-assertAttributeInterpolation({
-  property: 'cy',
-  from: '-1',
-  to: '-6'
-}, [
-  {at: -0.4, is: 1},
-  {at: 0, is: -1},
-  {at: 0.2, is: -2},
-  {at: 0.6, is: -4},
-  {at: 1, is: -6},
-  {at: 1.4, is: -8}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-d-interpolation-expected.txt b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-d-interpolation-expected.txt
deleted file mode 100644
index 375c23b..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-d-interpolation-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-This is a testharness.js-based test.
-[FAIL] SMIL: Interpolate attribute <d> from replace [m 10 0 h 1] to replace [m 20 0 v 2] at (0) is [m 10 0 h 1]
-  assert_equals: expected "path ( \\" M 10 0 H 11 \\" ) " but got "path ( \\" M 10 0 \\" ) "
-[FAIL] SMIL: Interpolate attribute <d> from replace [m 10 0 h 1] to replace [m 20 0 v 2] at (0.2) is [m 10 0 h 1]
-  assert_equals: expected "path ( \\" M 10 0 H 11 \\" ) " but got "path ( \\" M 12 0 \\" ) "
-[FAIL] SMIL: Interpolate attribute <d> from replace [m 10 0 h 1] to replace [m 20 0 v 2] at (0.6) is [m 20 0 v 2]
-  assert_equals: expected "path ( \\" M 20 0 V 2 \\" ) " but got "path ( \\" M 16 0 \\" ) "
-[FAIL] SMIL: Interpolate attribute <d> from replace [m 10 0 h 1] to replace [m 20 0 v 2] at (1) is [m 20 0 v 2]
-  assert_equals: expected "path ( \\" M 20 0 V 2 \\" ) " but got "path ( \\" M 20 0 \\" ) "
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-d-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-d-interpolation.html
deleted file mode 100644
index d0c024e..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-d-interpolation.html
+++ /dev/null
@@ -1,412 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta http-equiv="content-type" content="text/html; charset=utf-8" />
-</head>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<path class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-
-// Distinct number of path segments
-assertAttributeInterpolation({
-  property: 'd',
-  from: 'm 0 0 h 1 h 2',
-  to: 'm 0 0 h 3'
-}, [
-  {at: -0.4, is: 'm 0 0 h 1 h 2'},
-  {at: 0, is: 'm 0 0 h 1 h 2'},
-  {at: 0.2, is: 'm 0 0 h 1 h 2'},
-  {at: 0.6, is: 'm 0 0 h 3'},
-  {at: 1, is: 'm 0 0 h 3'},
-  {at: 1.4, is: 'm 0 0 h 3'}
-]);
-
-// Distinct segment types
-assertAttributeInterpolation({
-  property: 'd',
-  from: 'm 10 0 h 1',
-  to: 'm 20 0 v 2'
-}, [
-  {at: -0.4, is: 'm 10 0 h 1'},
-  {at: 0, is: 'm 10 0 h 1'},
-  {at: 0.2, is: 'm 10 0 h 1'},
-  {at: 0.6, is: 'm 20 0 v 2'},
-  {at: 1, is: 'm 20 0 v 2'},
-  {at: 1.4, is: 'm 20 0 v 2'}
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  from: 'm 1 2 l 3 4 z',
-  to: 'm 1 2 l 3 4'
-}, [
-  {at: -0.4, is: 'm 1 2 l 3 4 z'},
-  {at: 0, is: 'm 1 2 l 3 4 z'},
-  {at: 0.2, is: 'm 1 2 l 3 4 z'},
-  {at: 0.6, is: 'm 1 2 l 3 4'},
-  {at: 1, is: 'm 1 2 l 3 4'},
-  {at: 1.4, is: 'm 1 2 l 3 4'}
-]);
-
-// Exercise each segment type
-assertAttributeInterpolation({
-  property: 'd',
-  from: 'm 0 0 z',
-  to: 'm 0 0 z'
-}, [
-  {at: -0.4, is: 'm 0 0 z'},
-  {at: 0, is: 'm 0 0 z'},
-  {at: 0.2, is: 'm 0 0 z'},
-  {at: 0.6, is: 'm 0 0 z'},
-  {at: 1, is: 'm 0 0 z'},
-  {at: 1.4, is: 'm 0 0 z'}
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  from: 'M 20 50',
-  to: 'M 30 70'
-}, [
-  {at: -0.4, is: 'M 16 42'},
-  {at: 0, is: 'M 20 50'},
-  {at: 0.2, is: 'M 22 54'},
-  {at: 0.6, is: 'M 26 62'},
-  {at: 1, is: 'M 30 70'},
-  {at: 1.4, is: 'M 34 78'}
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  from: 'm 20 50',
-  to: 'm 30 70'
-}, [
-  {at: -0.4, is: 'm 16 42'},
-  {at: 0, is: 'm 20 50'},
-  {at: 0.2, is: 'm 22 54'},
-  {at: 0.6, is: 'm 26 62'},
-  {at: 1, is: 'm 30 70'},
-  {at: 1.4, is: 'm 34 78'}
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  from: 'm 0 0 L 20 50',
-  to: 'm 0 0 L 30 70'
-}, [
-  {at: -0.4, is: 'm 0 0 L 16 42'},
-  {at: 0, is: 'm 0 0 L 20 50'},
-  {at: 0.2, is: 'm 0 0 L 22 54'},
-  {at: 0.6, is: 'm 0 0 L 26 62'},
-  {at: 1, is: 'm 0 0 L 30 70'},
-  {at: 1.4, is: 'm 0 0 L 34 78'}
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  from: 'm 0 0 l 20 50',
-  to: 'm 0 0 l 30 70'
-}, [
-  {at: -0.4, is: 'm 0 0 l 16 42'},
-  {at: 0, is: 'm 0 0 l 20 50'},
-  {at: 0.2, is: 'm 0 0 l 22 54'},
-  {at: 0.6, is: 'm 0 0 l 26 62'},
-  {at: 1, is: 'm 0 0 l 30 70'},
-  {at: 1.4, is: 'm 0 0 l 34 78'}
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  from: 'm 0 0 C 32 42 52 62 12 22',
-  to: 'm 0 0 C 37 47 57 67 17 27'
-}, [
-  {at: -0.4, is: 'm 0 0 C 30 40 50 60 10 20'},
-  {at: 0, is: 'm 0 0 C 32 42 52 62 12 22'},
-  {at: 0.2, is: 'm 0 0 C 33 43 53 63 13 23'},
-  {at: 0.6, is: 'm 0 0 C 35 45 55 65 15 25'},
-  {at: 1, is: 'm 0 0 C 37 47 57 67 17 27'},
-  {at: 1.4, is: 'm 0 0 C 39 49 59 69 19 29'}
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  from: 'm 0 0 c 32 42 52 62 12 22',
-  to: 'm 0 0 c 37 47 57 67 17 27'
-}, [
-  {at: -0.4, is: 'm 0 0 c 30 40 50 60 10 20'},
-  {at: 0, is: 'm 0 0 c 32 42 52 62 12 22'},
-  {at: 0.2, is: 'm 0 0 c 33 43 53 63 13 23'},
-  {at: 0.6, is: 'm 0 0 c 35 45 55 65 15 25'},
-  {at: 1, is: 'm 0 0 c 37 47 57 67 17 27'},
-  {at: 1.4, is: 'm 0 0 c 39 49 59 69 19 29'}
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  from: 'm 0 0 Q 32 42 52 62',
-  to: 'm 0 0 Q 37 47 57 67'
-}, [
-  {at: -0.4, is: 'm 0 0 Q 30 40 50 60'},
-  {at: 0, is: 'm 0 0 Q 32 42 52 62'},
-  {at: 0.2, is: 'm 0 0 Q 33 43 53 63'},
-  {at: 0.6, is: 'm 0 0 Q 35 45 55 65'},
-  {at: 1, is: 'm 0 0 Q 37 47 57 67'},
-  {at: 1.4, is: 'm 0 0 Q 39 49 59 69'}
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  from: 'm 0 0 q 32 42 52 62',
-  to: 'm 0 0 q 37 47 57 67'
-}, [
-  {at: -0.4, is: 'm 0 0 q 30 40 50 60'},
-  {at: 0, is: 'm 0 0 q 32 42 52 62'},
-  {at: 0.2, is: 'm 0 0 q 33 43 53 63'},
-  {at: 0.6, is: 'm 0 0 q 35 45 55 65'},
-  {at: 1, is: 'm 0 0 q 37 47 57 67'},
-  {at: 1.4, is: 'm 0 0 q 39 49 59 69'}
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  from: 'm 0 0 A 10 20 30 1 0 40 50',
-  to: 'm 0 0 A 60 70 80 0 1 90 100'
-}, [
-  {at: -0.4, is: 'm 0 0 A -10 0 10 1 0 20 30'},
-  {at: 0, is: 'm 0 0 A 10 20 30 1 0 40 50'},
-  {at: 0.2, is: 'm 0 0 A 20 30 40 1 0 50 60'},
-  {at: 0.6, is: 'm 0 0 A 40 50 60 0 1 70 80'},
-  {at: 1, is: 'm 0 0 A 60 70 80 0 1 90 100'},
-  {at: 1.4, is: 'm 0 0 A 80 90 100 0 1 110 120'},
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  from: 'm 0 0 a 10 20 30 1 0 40 50',
-  to: 'm 0 0 a 60 70 80 0 1 90 100'
-}, [
-  {at: -0.4, is: 'm 0 0 a -10 0 10 1 0 20 30'},
-  {at: 0, is: 'm 0 0 a 10 20 30 1 0 40 50'},
-  {at: 0.2, is: 'm 0 0 a 20 30 40 1 0 50 60'},
-  {at: 0.6, is: 'm 0 0 a 40 50 60 0 1 70 80'},
-  {at: 1, is: 'm 0 0 a 60 70 80 0 1 90 100'},
-  {at: 1.4, is: 'm 0 0 a 80 90 100 0 1 110 120'}
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  from: 'm 0 0 H 10',
-  to: 'm 0 0 H 60'
-}, [
-  {at: -0.4, is: 'm 0 0 H -10'},
-  {at: 0, is: 'm 0 0 H 10'},
-  {at: 0.2, is: 'm 0 0 H 20'},
-  {at: 0.6, is: 'm 0 0 H 40'},
-  {at: 1, is: 'm 0 0 H 60'},
-  {at: 1.4, is: 'm 0 0 H 80'}
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  from: 'm 0 0 h 10',
-  to: 'm 0 0 h 60'
-}, [
-  {at: -0.4, is: 'm 0 0 h -10'},
-  {at: 0, is: 'm 0 0 h 10'},
-  {at: 0.2, is: 'm 0 0 h 20'},
-  {at: 0.6, is: 'm 0 0 h 40'},
-  {at: 1, is: 'm 0 0 h 60'},
-  {at: 1.4, is: 'm 0 0 h 80'}
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  from: 'm 0 0 V 10',
-  to: 'm 0 0 V 60'
-}, [
-  {at: -0.4, is: 'm 0 0 V -10'},
-  {at: 0, is: 'm 0 0 V 10'},
-  {at: 0.2, is: 'm 0 0 V 20'},
-  {at: 0.6, is: 'm 0 0 V 40'},
-  {at: 1, is: 'm 0 0 V 60'},
-  {at: 1.4, is: 'm 0 0 V 80'}
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  from: 'm 0 0 v 10',
-  to: 'm 0 0 v 60'
-}, [
-  {at: -0.4, is: 'm 0 0 v -10'},
-  {at: 0, is: 'm 0 0 v 10'},
-  {at: 0.2, is: 'm 0 0 v 20'},
-  {at: 0.6, is: 'm 0 0 v 40'},
-  {at: 1, is: 'm 0 0 v 60'},
-  {at: 1.4, is: 'm 0 0 v 80'}
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  from: 'm 0 0 S 32 42 52 62',
-  to: 'm 0 0 S 37 47 57 67'
-}, [
-  {at: -0.4, is: 'm 0 0 S 30 40 50 60'},
-  {at: 0, is: 'm 0 0 S 32 42 52 62'},
-  {at: 0.2, is: 'm 0 0 S 33 43 53 63'},
-  {at: 0.6, is: 'm 0 0 S 35 45 55 65'},
-  {at: 1, is: 'm 0 0 S 37 47 57 67'},
-  {at: 1.4, is: 'm 0 0 S 39 49 59 69'},
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  from: 'm 0 0 s 32 42 52 62',
-  to: 'm 0 0 s 37 47 57 67'
-}, [
-  {at: -0.4, is: 'm 0 0 s 30 40 50 60'},
-  {at: 0, is: 'm 0 0 s 32 42 52 62'},
-  {at: 0.2, is: 'm 0 0 s 33 43 53 63'},
-  {at: 0.6, is: 'm 0 0 s 35 45 55 65'},
-  {at: 1, is: 'm 0 0 s 37 47 57 67'},
-  {at: 1.4, is: 'm 0 0 s 39 49 59 69'},
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  from: 'm 0 0 T 20 50',
-  to: 'm 0 0 T 30 70'
-}, [
-  {at: -0.4, is: 'm 0 0 T 16 42'},
-  {at: 0, is: 'm 0 0 T 20 50'},
-  {at: 0.2, is: 'm 0 0 T 22 54'},
-  {at: 0.6, is: 'm 0 0 T 26 62'},
-  {at: 1, is: 'm 0 0 T 30 70'},
-  {at: 1.4, is: 'm 0 0 T 34 78'},
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  from: 'm 0 0 t 20 50',
-  to: 'm 0 0 t 30 70'
-}, [
-  {at: -0.4, is: 'm 0 0 t 16 42'},
-  {at: 0, is: 'm 0 0 t 20 50'},
-  {at: 0.2, is: 'm 0 0 t 22 54'},
-  {at: 0.6, is: 'm 0 0 t 26 62'},
-  {at: 1, is: 'm 0 0 t 30 70'},
-  {at: 1.4, is: 'm 0 0 t 34 78'},
-]);
-
-// Mix relative and non-relative
-assertAttributeInterpolation({
-  property: 'd',
-  from: 'M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z',
-  to: 'M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z'
-}, [
-  {at: -0.4, is: 'M 0 0 L 100 100 m 0 100 l 100 0 Z l 60 -180 Z'},
-  {at: 0, is: 'M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z'},
-  {at: 0.2, is: 'M 0 0 L 100 100 m 0 100 l 100 0 Z l 120 -60 Z'},
-  {at: 0.6, is: 'M 0 0 L 100 100 m 0 100 l 100 0 Z l 160 20 Z'},
-  {at: 1, is: 'M 0 0 L 100 100 m 0 100 l 100 0 Z l 200 100 Z'},
-  {at: 1.4, is: 'M 0 0 L 100 100 m 0 100 l 100 0 Z l 240 180 Z'},
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  from: 'M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z',
-  to: 'M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z'
-}, [
-  {at: -0.4, is: 'M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z'},
-  {at: 0, is: 'M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z'},
-  {at: 0.2, is: 'M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z'},
-  {at: 0.6, is: 'M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z'},
-  {at: 1, is: 'M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z'},
-  {at: 1.4, is: 'M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z'},
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  from: 'm 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120',
-  to: 'M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220'
-}, [
-  {at: -0.4, is: 'M -30 -20 L -10 10 Z L 52 68 Z M 72 84 L 162 144 Z T 126 220'},
-  {at: 0, is: 'm 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120'},
-  {at: 0.2, is: 'M 30 40 L 50 70 Z L 64 86 Z M 84 108 L 174 168 Z T 162 220'},
-  {at: 0.6, is: 'M 70 80 L 90 110 Z L 72 98 Z M 92 124 L 182 184 Z T 186 220'},
-  {at: 1, is: 'M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220'},
-  {at: 1.4, is: 'M 150 160 L 170 190 Z L 88 122 Z M 108 156 L 198 216 Z T 234 220'}
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  from: 'm 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130',
-  to: 'M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330'
-}, [
-  {at: -0.4, is: 'M -30 -20 C 14 38 4 48 54 58 C 136 146 186 156 166 176'},
-  {at: 0, is: 'm 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130'},
-  {at: 0.2, is: 'M 30 40 C 68 86 58 96 108 106 C 202 212 252 222 232 242'},
-  {at: 0.6, is: 'M 70 80 C 104 118 94 128 144 138 C 246 256 296 266 276 286'},
-  {at: 1, is: 'M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330'},
-  {at: 1.4, is: 'M 150 160 C 176 182 166 192 216 202 C 334 344 384 354 364 374'}
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  from: 'm 10 20 q 30 60 40 50 q 100 70 90 80',
-  to: 'M 110 120 Q 130 160 140 150 Q 200 170 190 180'
-}, [
-  {at: -0.4, is: 'M -30 -20 Q 4 48 14 38 Q 130 128 120 138'},
-  {at: 0, is: 'm 10 20 q 30 60 40 50 q 100 70 90 80'},
-  {at: 0.2, is: 'M 30 40 Q 58 96 68 86 Q 160 146 150 156'},
-  {at: 0.6, is: 'M 70 80 Q 94 128 104 118 Q 180 158 170 168'},
-  {at: 1, is: 'M 110 120 Q 130 160 140 150 Q 200 170 190 180'},
-  {at: 1.4, is: 'M 150 160 Q 166 192 176 182 Q 220 182 210 192'}
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  from: 'm 10 20 s 30 60 40 50 s 100 70 90 80',
-  to: 'M 110 120 S 130 160 140 150 S 200 170 190 180'
-}, [
-  {at: -0.4, is: 'M -30 -20 S 4 48 14 38 S 130 128 120 138'},
-  {at: 0, is: 'm 10 20 s 30 60 40 50 s 100 70 90 80'},
-  {at: 0.2, is: 'M 30 40 S 58 96 68 86 S 160 146 150 156'},
-  {at: 0.6, is: 'M 70 80 S 94 128 104 118 S 180 158 170 168'},
-  {at: 1, is: 'M 110 120 S 130 160 140 150 S 200 170 190 180'},
-  {at: 1.4, is: 'M 150 160 S 166 192 176 182 S 220 182 210 192'}
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  from: 'm 10 20 h 30 v 40 h 50 v 60 l 70 80',
-  to: 'M 110 120 H 130 V 140 H 250 V 260 L 270 280'
-}, [
-  {at: -0.4, is: 'M -30 -20 H 4 V 28 H 26 V 64 L 116 168'},
-  {at: 0, is: 'm 10 20 h 30 v 40 h 50 v 60 l 70 80'},
-  {at: 0.2, is: 'M 30 40 H 58 V 76 H 122 V 148 L 182 216'},
-  {at: 0.6, is: 'M 70 80 H 94 V 108 H 186 V 204 L 226 248'},
-  {at: 1, is: 'M 110 120 H 130 V 140 H 250 V 260 L 270 280'},
-  {at: 1.4, is: 'M 150 160 H 166 V 172 H 314 V 316 L 314 312'}
-]);
-
-assertAttributeInterpolation({
-  property: 'd',
-  from: 'm 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50',
-  to: 'M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100'
-}, [
-  {at: -0.4, is: 'M 6 16 A -10 0 10 1 0 34 58 A 90 100 10 1 1 230 128'},
-  {at: 0, is: 'm 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50'},
-  {at: 0.2, is: 'M 12 22 A 20 30 40 1 0 58 76 A 120 130 40 1 1 170 116'},
-  {at: 0.6, is: 'M 16 26 A 40 50 60 0 1 74 88 A 140 150 60 0 1 130 108'},
-  {at: 1, is: 'M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100'},
-  {at: 1.4, is: 'M 24 34 A 80 90 100 0 1 106 112 A 180 190 100 0 1 50 92'}
-]);
-
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-diffuseConstant-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-diffuseConstant-interpolation.html
deleted file mode 100644
index f2a46b78..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-diffuseConstant-interpolation.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<feDiffuseLighting class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'diffuseConstant',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-divisor-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-divisor-interpolation.html
deleted file mode 100644
index 05c1cca..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-divisor-interpolation.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<feConvolveMatrix class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'divisor',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-dx-dy-length-list-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-dx-dy-length-list-interpolation.html
deleted file mode 100644
index e4bb6eb..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-dx-dy-length-list-interpolation.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="0" height="0">
-<text class="target">123</text>
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'dx',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: '-1'},
-  {at: 0, is: '1'},
-  {at: 0.2, is: '2'},
-  {at: 0.6, is: '4'},
-  {at: 1, is: '6'},
-  {at: 1.4, is: '8'}
-]);
-assertAttributeInterpolation({
-  property: 'dy',
-  from: '1 -2',
-  to: '6 -12'
-}, [
-  {at: -0.4, is: '-1 2'},
-  {at: 0, is: '1 -2'},
-  {at: 0.2, is: '2 -4'},
-  {at: 0.6, is: '4 -8'},
-  {at: 1, is: '6 -12'},
-  {at: 1.4, is: '8 -16'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-dx-dy-number-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-dx-dy-number-interpolation.html
deleted file mode 100644
index 924d6d4..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-dx-dy-number-interpolation.html
+++ /dev/null
@@ -1,39 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-  <svg width="0" height="0">
-    <feOffset class="target"></feOffset>
-  </svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'dx',
-  from: '1',
-  to: '6',
-}, [
-  {at: -0.4, is: '-1'},
-  {at: 0, is: '1'},
-  {at: 0.2, is: '2'},
-  {at: 0.6, is: '4'},
-  {at: 1, is: '6'},
-  {at: 1.4, is: '8'},
-]);
-
-assertAttributeInterpolation({
-  property: 'dy',
-  from: '1',
-  to: '6',
-}, [
-  {at: -0.4, is: '-1'},
-  {at: 0, is: '1'},
-  {at: 0.2, is: '2'},
-  {at: 0.6, is: '4'},
-  {at: 1, is: '6'},
-  {at: 1.4, is: '8'},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-edgeMode-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-edgeMode-interpolation.html
deleted file mode 100644
index 66d931f..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-edgeMode-interpolation.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<defs>
-<filter>
-<feConvolveMatrix class="target" />
-</filter>
-</defs>
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'edgeMode',
-  from: 'duplicate',
-  to: 'wrap'
-}, [
-  {at: -0.4, is: 'duplicate'},
-  {at: 0, is: 'duplicate'},
-  {at: 0.2, is: 'duplicate'},
-  {at: 0.6, is: 'wrap'},
-  {at: 1, is: 'wrap'},
-  {at: 1.4, is: 'wrap'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-elevation-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-elevation-interpolation.html
deleted file mode 100644
index b99f820f..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-elevation-interpolation.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<feDistantLight class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'elevation',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-exponent-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-exponent-interpolation.html
deleted file mode 100644
index 0c0b907..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-exponent-interpolation.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<feComponentTransfer>
-<feFuncR type="gamma" class="target" />
-</feComponentTransfer>
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'exponent',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-filterUnits-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-filterUnits-interpolation.html
deleted file mode 100644
index 78a94ae8..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-filterUnits-interpolation.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<defs>
-<filter class="target" />
-</defs>
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'filterUnits',
-  from: 'userSpaceOnUse',
-  to: 'objectBoundingBox'
-}, [
-  {at: -2.4, is: 'userSpaceOnUse'},
-  {at: 0, is: 'userSpaceOnUse'},
-  {at: 0.2, is: 'userSpaceOnUse'},
-  {at: 0.6, is: 'objectBoundingBox'},
-  {at: 1, is: 'objectBoundingBox'},
-  {at: 3.4, is: 'objectBoundingBox'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-fx-fy-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-fx-fy-interpolation.html
deleted file mode 100644
index 60eb398..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-fx-fy-interpolation.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<radialGradient class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'fx',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-assertAttributeInterpolation({
-  property: 'fy',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-gradientTransform-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-gradientTransform-interpolation.html
deleted file mode 100644
index bb67f76..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-gradientTransform-interpolation.html
+++ /dev/null
@@ -1,79 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<linearGradient class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-
-assertAttributeInterpolation({
-  property: 'gradientTransform',
-  from: 'translate(10 20)',
-  to: 'translate(30 60)'
-}, [
-  {at: -0.4, is: 'translate(2,4)'},
-  {at: 0, is: 'translate(10 20)'},
-  {at: 0.2, is: 'translate(14,28)'},
-  {at: 0.6, is: 'translate(22,44)'},
-  {at: 1, is: 'translate(30 60)'},
-  {at: 1.4, is: 'translate(38,76)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'gradientTransform',
-  from: 'scale(10 20)',
-  to: 'scale(30 60)'
-}, [
-  {at: -0.4, is: 'scale(2 4)'},
-  {at: 0, is: 'scale(10 20)'},
-  {at: 0.2, is: 'scale(14 28)'},
-  {at: 0.6, is: 'scale(22 44)'},
-  {at: 1, is: 'scale(30 60)'},
-  {at: 1.4, is: 'scale(38 76)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'gradientTransform',
-  from: 'rotate(10 20 30)',
-  to: 'rotate(40 80 160)'
-}, [
-  {at: -0.4, is: 'rotate(-2 -4 -22)'},
-  {at: 0, is: 'rotate(10 20 30)'},
-  {at: 0.2, is: 'rotate(16 32 56)'},
-  {at: 0.6, is: 'rotate(28 56 108)'},
-  {at: 1, is: 'rotate(40 80 160)'},
-  {at: 1.4, is: 'rotate(52 104 212)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'gradientTransform',
-  from: 'skewX(10)',
-  to: 'skewX(20)'
-}, [
-  {at: -0.4, is: 'skewX(6)'},
-  {at: 0, is: 'skewX(10)'},
-  {at: 0.2, is: 'skewX(12)'},
-  {at: 0.6, is: 'skewX(16)'},
-  {at: 1, is: 'skewX(20)'},
-  {at: 1.4, is: 'skewX(24)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'gradientTransform',
-  from: 'skewY(10)',
-  to: 'skewY(20)'
-}, [
-  {at: -0.4, is: 'skewY(6)'},
-  {at: 0, is: 'skewY(10)'},
-  {at: 0.2, is: 'skewY(12)'},
-  {at: 0.6, is: 'skewY(16)'},
-  {at: 1, is: 'skewY(20)'},
-  {at: 1.4, is: 'skewY(24)'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-gradientUnits-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-gradientUnits-interpolation.html
deleted file mode 100644
index cac4ba2..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-gradientUnits-interpolation.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<linearGradient class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'gradientUnits',
-  from: 'userSpaceOnUse',
-  to: 'objectBoundingBox'
-}, [
-  {at: -2.4, is: 'userSpaceOnUse'},
-  {at: 0, is: 'userSpaceOnUse'},
-  {at: 0.2, is: 'userSpaceOnUse'},
-  {at: 0.6, is: 'objectBoundingBox'},
-  {at: 1, is: 'objectBoundingBox'},
-  {at: 3.4, is: 'objectBoundingBox'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-height-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-height-interpolation.html
deleted file mode 100644
index ddad650..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-height-interpolation.html
+++ /dev/null
@@ -1,94 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script src="../../resources/ahem.js"></script>
-<style>
-:root {
-  font: 10px Ahem;
-}
-</style>
-</head>
-<body>
-<template id="target-template">
-<svg width="200px" height="300px" viewBox="0 0 1500 1000">
-  <rect class="target" x="10" y="10" width="10" height="10" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'height',
-  from: '10',
-  to: '60'
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 10},
-  {at: 0.2, is: 20},
-  {at: 0.6, is: 40},
-  {at: 1, is: 60},
-  {at: 1.4, is: 80}
-]);
-assertAttributeInterpolation({
-  property: 'height',
-  from: '10%',
-  to: '60%'
-}, [
-  {at: -0.4, is: '0%'},
-  {at: 0, is: '10%'},
-  {at: 0.2, is: '20%'},
-  {at: 0.6, is: '40%'},
-  {at: 1, is: '60%'},
-  {at: 1.4, is: '80%'}
-]);
-assertAttributeInterpolation({
-  property: 'height',
-  from: '10em',
-  to: '60em'
-}, [
-  {at: -0.4, is: '0em'},
-  {at: 0, is: '10em'},
-  {at: 0.2, is: '20em'},
-  {at: 0.6, is: '40em'},
-  {at: 1, is: '60em'},
-  {at: 1.4, is: '80em'}
-]);
-assertAttributeInterpolation({
-  property: 'height',
-  from: '10ex',
-  to: '60ex'
-}, [
-  {at: -0.4, is: '0ex'},
-  {at: 0, is: '10ex'},
-  {at: 0.2, is: '20ex'},
-  {at: 0.6, is: '40ex'},
-  {at: 1, is: '60ex'},
-  {at: 1.4, is: '80ex'}
-]);
-assertAttributeInterpolation({
-  property: 'height',
-  from: '10rem',
-  to: '60rem'
-}, [
-  {at: -0.4, is: '0rem'},
-  {at: 0, is: '10rem'},
-  {at: 0.2, is: '20rem'},
-  {at: 0.6, is: '40rem'},
-  {at: 1, is: '60rem'},
-  {at: 1.4, is: '80rem'}
-]);
-assertAttributeInterpolation({
-  property: 'height',
-  from: '10mm',
-  to: '20px'
-}, [
-  {at: -0.4, is: '44.913387298583984'},
-  {at: 0, is: '10mm'},
-  {at: 0.2, is: '34.23622131347656'},
-  {at: 0.6, is: '27.11811065673828'},
-  {at: 1, is: '20px'},
-  {at: 1.4, is: '12.881889343261719'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-href-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-href-interpolation.html
deleted file mode 100644
index 9866f14..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-href-interpolation.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-<linearGradient class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'href',
-  from: '#A',
-  to: '#B'
-}, [
-  {at: -0.4, is: '#A'},
-  {at: 0, is: '#A'},
-  {at: 0.2, is: '#A'},
-  {at: 0.6, is: '#B'},
-  {at: 1, is: '#B'},
-  {at: 1.4, is: '#B'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-in-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-in-interpolation.html
deleted file mode 100644
index faa1a25..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-in-interpolation.html
+++ /dev/null
@@ -1,45 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<defs>
-<filter>
-<feBlend mode="normal" class="target" />
-</filter>
-</defs>
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-
-assertAttributeInterpolation({
-  property: 'in',
-  from: 'SourceAlpha',
-  to: 'FillPaint'
-}, [
-  {at: -0.4, is: 'SourceAlpha'},
-  {at: 0, is: 'SourceAlpha'},
-  {at: 0.2, is: 'SourceAlpha'},
-  {at: 0.6, is: 'FillPaint'},
-  {at: 1, is: 'FillPaint'},
-  {at: 1.4, is: 'FillPaint'}
-]);
-
-assertAttributeInterpolation({
-  property: 'in2',
-  from: 'BackgroundImage',
-  to: 'myFilter' // arbitrary <filter-primitive-reference>
-}, [
-  {at: -0.4, is: 'BackgroundImage'},
-  {at: 0, is: 'BackgroundImage'},
-  {at: 0.2, is: 'BackgroundImage'},
-  {at: 0.6, is: 'myFilter'},
-  {at: 1, is: 'myFilter'},
-  {at: 1.4, is: 'myFilter'}
-]);
-
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-intercept-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-intercept-interpolation.html
deleted file mode 100644
index d630ca1..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-intercept-interpolation.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<feComponentTransfer>
-<feFuncR type="linear" class="target" />
-</feComponentTransfer>
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'intercept',
-  from: '-1',
-  to: '1.5'
-}, [
-  {at: -0.4, is: -2},
-  {at: 0, is: -1},
-  {at: 0.2, is: -0.5},
-  {at: 0.6, is: 0.5},
-  {at: 1, is: 1.5},
-  {at: 1.4, is: 2.5}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-k1-k2-k3-k4-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-k1-k2-k3-k4-interpolation.html
deleted file mode 100644
index c6d4a4b8..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-k1-k2-k3-k4-interpolation.html
+++ /dev/null
@@ -1,62 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<feComposite class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'k1',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-assertAttributeInterpolation({
-  property: 'k2',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-assertAttributeInterpolation({
-  property: 'k3',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-assertAttributeInterpolation({
-  property: 'k4',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-kernelMatrix-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-kernelMatrix-interpolation.html
deleted file mode 100644
index 61ed3712..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-kernelMatrix-interpolation.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<defs>
-<filter>
-<feConvolveMatrix order="1, 3" class="target" />
-</filter>
-</defs>
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'kernelMatrix',
-  from: '1, 2, 3',
-  to: '6, 12, 18'
-}, [
-  {at: -0.4, is: '-1, -2, -3'},
-  {at: 0, is: '1, 2, 3'},
-  {at: 0.2, is: '2, 4, 6'},
-  {at: 0.6, is: '4, 8, 12'},
-  {at: 1, is: '6, 12, 18'},
-  {at: 1.4, is: '8, 16, 24'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-kernelUnitLength-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-kernelUnitLength-interpolation.html
deleted file mode 100644
index 2307373..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-kernelUnitLength-interpolation.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<feDiffuseLighting class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'kernelUnitLength',
-  from: '1',
-  to: '6 11'
-}, [
-  {at: -0.4, is: '-1, -3'},
-  {at: 0, is: '1, 1'},
-  {at: 0.2, is: '2, 3'},
-  {at: 0.6, is: '4, 7'},
-  {at: 1, is: '6, 11'},
-  {at: 1.4, is: '8, 15'}
-]);
-assertAttributeInterpolation({
-  property: 'kernelUnitLength',
-  from: '-2 10',
-  to: '3 10'
-}, [
-  {at: -0.4, is: '-4, 10'},
-  {at: 0, is: '-2 10'},
-  {at: 0.2, is: '-1, 10'},
-  {at: 0.6, is: '1, 10'},
-  {at: 1, is: '3, 10'},
-  {at: 1.4, is: '5, 10'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-lengthAdjust-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-lengthAdjust-interpolation.html
deleted file mode 100644
index aa9bee0c..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-lengthAdjust-interpolation.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<text class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'lengthAdjust',
-  from: 'spacing',
-  to: 'spacingAndGlyphs'
-}, [
-  {at: -0.4, is: 'spacing'},
-  {at: 0, is: 'spacing'},
-  {at: 0.2, is: 'spacing'},
-  {at: 0.6, is: 'spacingAndGlyphs'},
-  {at: 1, is: 'spacingAndGlyphs'},
-  {at: 1.4, is: 'spacingAndGlyphs'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-limitingConeAngle-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-limitingConeAngle-interpolation.html
deleted file mode 100644
index f944c0a..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-limitingConeAngle-interpolation.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<filter>
-<defs>
-<feSpotLight class="target" />
-</defs>
-</filter>
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'limitingConeAngle',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: '-1'},
-  {at: 0, is: '1'},
-  {at: 0.2, is: '2'},
-  {at: 0.6, is: '4'},
-  {at: 1, is: '6'},
-  {at: 1.4, is: '8'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-markerHeight-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-markerHeight-interpolation.html
deleted file mode 100644
index 0752b704..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-markerHeight-interpolation.html
+++ /dev/null
@@ -1,67 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script src="../../resources/ahem.js"></script>
-<style>
-:root {
-  font: 10px Ahem;
-}
-</style>
-</head>
-<body>
-<template id="target-template">
-<svg width="200px" height="300px" viewBox="0 0 1500 1000">
-  <marker class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'markerHeight',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-assertAttributeInterpolation({
-  property: 'markerHeight',
-  from: '10in',
-  to: '770pt'
-}, [
-  {at: -0.4, is: '700pt'},
-  {at: 0, is: '720pt'},
-  {at: 0.2, is: '730pt'},
-  {at: 0.6, is: '750pt'},
-  {at: 1, is: '770pt'},
-  {at: 1.4, is: '790pt'}
-]);
-assertAttributeInterpolation({
-  property: 'markerHeight',
-  from: '55%',
-  to: '5em'
-}, [
-  {at: -0.4, is: 750},
-  {at: 0, is: 550},
-  {at: 0.2, is: 450},
-  {at: 0.6, is: 250},
-  {at: 1, is: 50},
-  {at: 1.4, is: 0}
-]);
-assertAttributeInterpolation({
-  property: 'markerHeight',
-  from: '10',
-  to: '20ex'
-}, [
-  {at: -0.4, is: '0'},
-  {at: 0, is: '10'},
-  {at: 1, is: '20ex'},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-markerUnits-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-markerUnits-interpolation.html
deleted file mode 100644
index d00c33b..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-markerUnits-interpolation.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<marker class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'markerUnits',
-  from: 'userSpaceOnUse',
-  to: 'strokeWidth',
-}, [
-  {at: -2.4, is: 'userSpaceOnUse'},
-  {at: 0, is: 'userSpaceOnUse'},
-  {at: 0.2, is: 'userSpaceOnUse'},
-  {at: 0.6, is: 'strokeWidth'},
-  {at: 1, is: 'strokeWidth'},
-  {at: 3.4, is: 'strokeWidth'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-markerWidth-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-markerWidth-interpolation.html
deleted file mode 100644
index b759c8b..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-markerWidth-interpolation.html
+++ /dev/null
@@ -1,82 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<style>
-:root {
-  font: 10px Ahem;
-}
-</style>
-</head>
-<body>
-<template id="target-template">
-<svg width="200px" height="300px" viewBox="0 0 1500 1000">
-  <marker class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'markerWidth',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-assertAttributeInterpolation({
-  property: 'markerWidth',
-  from: '10pt',
-  to: '5pc'
-}, [
-  {at: -0.4, is: '0pt'},
-  {at: 0, is: '10pt'},
-  {at: 0.2, is: '20pt'},
-  {at: 0.6, is: '40pt'},
-  {at: 1, is: '60pt'},
-  {at: 1.4, is: '80pt'}
-]);
-assertAttributeInterpolation({
-  property: 'markerWidth',
-  from: '15%',
-  to: '23em'
-}, [
-  {at: -1000, is: 0},
-  {at: -0.4, is: 223},
-  {at: 0, is: 225},
-  {at: 0.2, is: 226},
-  {at: 0.6, is: 228},
-  {at: 1, is: 230},
-  {at: 1.4, is: 232}
-]);
-assertAttributeInterpolation({
-  property: 'markerWidth',
-  from: '10rem',
-  to: '60rem'
-}, [
-  {at: -0.4, is: '0rem'},
-  {at: 0, is: '10rem'},
-  {at: 0.2, is: '20rem'},
-  {at: 0.6, is: '40rem'},
-  {at: 1, is: '60rem'},
-  {at: 1.4, is: '80rem'}
-]);
-assertAttributeInterpolation({
-  property: 'markerWidth',
-  from: '10ch',
-  to: '20rem'
-}, [
-  {at: -0.4, is: '60'},
-  {at: 0, is: '10ch'},
-  {at: 0.2, is: '120'},
-  {at: 0.6, is: '160'},
-  {at: 1, is: '20rem'},
-  {at: 1.4, is: '240'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-maskContentUnits-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-maskContentUnits-interpolation.html
deleted file mode 100644
index 2234e32..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-maskContentUnits-interpolation.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<mask class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'maskContentUnits',
-  from: 'userSpaceOnUse',
-  to: 'objectBoundingBox',
-}, [
-  {at: -2.4, is: 'userSpaceOnUse'},
-  {at: 0, is: 'userSpaceOnUse'},
-  {at: 0.2, is: 'userSpaceOnUse'},
-  {at: 0.6, is: 'objectBoundingBox'},
-  {at: 1, is: 'objectBoundingBox'},
-  {at: 3.4, is: 'objectBoundingBox'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-maskUnits-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-maskUnits-interpolation.html
deleted file mode 100644
index 478d88b..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-maskUnits-interpolation.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<defs>
-<mask class="target" />
-</defs>
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'maskUnits',
-  from: 'userSpaceOnUse',
-  to: 'objectBoundingBox',
-}, [
-  {at: -2.4, is: 'userSpaceOnUse'},
-  {at: 0, is: 'userSpaceOnUse'},
-  {at: 0.2, is: 'userSpaceOnUse'},
-  {at: 0.6, is: 'objectBoundingBox'},
-  {at: 1, is: 'objectBoundingBox'},
-  {at: 3.4, is: 'objectBoundingBox'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-method-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-method-interpolation.html
deleted file mode 100644
index d7fc3408..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-method-interpolation.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<textPath class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'method',
-  from: 'align',
-  to: 'stretch',
-}, [
-  {at: -2.4, is: 'align'},
-  {at: 0, is: 'align'},
-  {at: 0.2, is: 'align'},
-  {at: 0.6, is: 'stretch'},
-  {at: 1, is: 'stretch'},
-  {at: 3.4, is: 'stretch'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-mode-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-mode-interpolation.html
deleted file mode 100644
index 356d621..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-mode-interpolation.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<feBlend class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'mode',
-  from: 'screen',
-  to: 'lighten'
-}, [
-  {at: -2.4, is: 'screen'},
-  {at: 0, is: 'screen'},
-  {at: 0.2, is: 'screen'},
-  {at: 0.6, is: 'lighten'},
-  {at: 1, is: 'lighten'},
-  {at: 3.4, is: 'lighten'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-numOctaves-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-numOctaves-interpolation.html
deleted file mode 100644
index 5c5a6a0..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-numOctaves-interpolation.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<feTurbulence class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'numOctaves',
-  from: '1',
-  to: '7'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 5},
-  {at: 1, is: 7},
-  {at: 1.4, is: 9}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-offset-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-offset-interpolation.html
deleted file mode 100644
index ea94894..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-offset-interpolation.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<stop class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-// Note: percentage strings like '10%' are not supported.
-assertAttributeInterpolation({
-  property: 'offset',
-  from: '-2.5',
-  to: '7.5'
-}, [
-  {at: -0.4, is: -6.5},
-  {at: 0, is: -2.5},
-  {at: 0.2, is: -0.5},
-  {at: 0.6, is: 3.5},
-  {at: 1, is: 7.5},
-  {at: 1.4, is: 11.5}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-operator-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-operator-interpolation.html
deleted file mode 100644
index 96d76f7..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-operator-interpolation.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<feMorphology class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'operator',
-  from: 'erode',
-  to: 'dilate',
-}, [
-  {at: -2.4, is: 'erode'},
-  {at: 0, is: 'erode'},
-  {at: 0.2, is: 'erode'},
-  {at: 0.6, is: 'dilate'},
-  {at: 1, is: 'dilate'},
-  {at: 3.4, is: 'dilate'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-order-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-order-interpolation.html
deleted file mode 100644
index 65a7c8af..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-order-interpolation.html
+++ /dev/null
@@ -1,58 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<defs>
-<filter>
-<feConvolveMatrix order="4 1" kernelMatrix="100 200 300 400" class="target" />
-</filter>
-</defs>
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-// The number of entries kernelMatrix must equal <orderX> times <orderY>.
-assertAttributeInterpolation({
-  property: 'order',
-  from: '1, 4',
-  to: '2'
-}, [
-  {at: 0, is: '1 4'},
-  {at: 1, is: '2 2'},
-]);
-
-assertAttributeInterpolation({
-  property: 'order',
-  from: '2',
-  to: '2'
-}, [
-  {at: -0.4, is: '2 2'},
-  {at: 0, is: '2 2'},
-  {at: 0.2, is: '2 2'},
-  {at: 0.6, is: '2 2'},
-  {at: 1, is: '2 2'},
-  {at: 1.4, is: '2 2'}
-]);
-
-assertAttributeInterpolation({
-  property: 'order',
-  from: '2',
-  to: '4, 1'
-}, [
-  {at: 0, is: '2 2'},
-  {at: 1, is: '4 1'},
-]);
-
-//Regression test for crbug.com/994800
-assertAttributeInterpolation({
-  property: 'order',
-  from: '1',
-  to: '3'
-}, [
-  {at: 3.40282e+038, is: '2147483647 , 2147483647'},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-orient-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-orient-interpolation.html
deleted file mode 100644
index 3089aea1..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-orient-interpolation.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<defs>
-<marker class="target" />
-</defs>
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'orient',
-  from: '130',
-  to: '200grad' // 180deg
-}, [
-  {at: -3, is: -20},
-  {at: 0, is: 130},
-  {at: 0.2, is: 140},
-  {at: 0.6, is: 160},
-  {at: 1, is: 180},
-  {at: 1.4, is: 200}
-]);
-assertAttributeInterpolation({
-  property: 'orient',
-  from: '90deg',
-  to: 'auto'
-}, [
-  {at: -0.4, is: 90},
-  {at: 0, is: 90},
-  {at: 0.2, is: 90},
-  {at: 0.6, is: 'auto'},
-  {at: 1, is: 'auto'},
-  {at: 1.4, is: 'auto'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-pathLength-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-pathLength-interpolation.html
deleted file mode 100644
index ea2db3c..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-pathLength-interpolation.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg xmlns="http://www.w3.org/2000/svg" width="90" height="90">
-<path d="M 100 200 L 300 400" class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'pathLength',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-patternContentUnits-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-patternContentUnits-interpolation.html
deleted file mode 100644
index 8ba58264..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-patternContentUnits-interpolation.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<pattern class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'patternContentUnits',
-  from: 'userSpaceOnUse',
-  to: 'objectBoundingBox',
-}, [
-  {at: -2.4, is: 'userSpaceOnUse'},
-  {at: 0, is: 'userSpaceOnUse'},
-  {at: 0.2, is: 'userSpaceOnUse'},
-  {at: 0.6, is: 'objectBoundingBox'},
-  {at: 1, is: 'objectBoundingBox'},
-  {at: 3.4, is: 'objectBoundingBox'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-patternTransform-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-patternTransform-interpolation.html
deleted file mode 100644
index 062f2dd..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-patternTransform-interpolation.html
+++ /dev/null
@@ -1,79 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<pattern class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-
-assertAttributeInterpolation({
-  property: 'patternTransform',
-  from: 'translate(10 20)',
-  to: 'translate(30 60)'
-}, [
-  {at: -0.4, is: 'translate(2,4)'},
-  {at: 0, is: 'translate(10 20)'},
-  {at: 0.2, is: 'translate(14,28)'},
-  {at: 0.6, is: 'translate(22,44)'},
-  {at: 1, is: 'translate(30 60)'},
-  {at: 1.4, is: 'translate(38,76)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'patternTransform',
-  from: 'scale(10 20)',
-  to: 'scale(30 60)'
-}, [
-  {at: -0.4, is: 'scale(2 4)'},
-  {at: 0, is: 'scale(10 20)'},
-  {at: 0.2, is: 'scale(14 28)'},
-  {at: 0.6, is: 'scale(22 44)'},
-  {at: 1, is: 'scale(30 60)'},
-  {at: 1.4, is: 'scale(38 76)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'patternTransform',
-  from: 'rotate(10 20 30)',
-  to: 'rotate(40 80 160)'
-}, [
-  {at: -0.4, is: 'rotate(-2 -4 -22)'},
-  {at: 0, is: 'rotate(10 20 30)'},
-  {at: 0.2, is: 'rotate(16 32 56)'},
-  {at: 0.6, is: 'rotate(28 56 108)'},
-  {at: 1, is: 'rotate(40 80 160)'},
-  {at: 1.4, is: 'rotate(52 104 212)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'patternTransform',
-  from: 'skewX(10)',
-  to: 'skewX(20)'
-}, [
-  {at: -0.4, is: 'skewX(6)'},
-  {at: 0, is: 'skewX(10)'},
-  {at: 0.2, is: 'skewX(12)'},
-  {at: 0.6, is: 'skewX(16)'},
-  {at: 1, is: 'skewX(20)'},
-  {at: 1.4, is: 'skewX(24)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'patternTransform',
-  from: 'skewY(10)',
-  to: 'skewY(20)'
-}, [
-  {at: -0.4, is: 'skewY(6)'},
-  {at: 0, is: 'skewY(10)'},
-  {at: 0.2, is: 'skewY(12)'},
-  {at: 0.6, is: 'skewY(16)'},
-  {at: 1, is: 'skewY(20)'},
-  {at: 1.4, is: 'skewY(24)'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-patternUnits-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-patternUnits-interpolation.html
deleted file mode 100644
index 4377a39..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-patternUnits-interpolation.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<pattern class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'patternUnits',
-  from: 'userSpaceOnUse',
-  to: 'objectBoundingBox',
-}, [
-  {at: -2.4, is: 'userSpaceOnUse'},
-  {at: 0, is: 'userSpaceOnUse'},
-  {at: 0.2, is: 'userSpaceOnUse'},
-  {at: 0.6, is: 'objectBoundingBox'},
-  {at: 1, is: 'objectBoundingBox'},
-  {at: 3.4, is: 'objectBoundingBox'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-points-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-points-interpolation.html
deleted file mode 100644
index 1feb1f840..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-points-interpolation.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<polygon class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'points',
-  from: '10 20, 80 20, 80 70, 10 70',
-  to: '15 10, 75 10, 75 80, 15 80'
-}, [
-  {at: -0.4, is: '8 24, 82 24, 82 66, 8 66'},
-  {at: 0, is: '10 20, 80 20, 80 70, 10 70'},
-  {at: 0.2, is: '11 18, 79 18, 79 72, 11 72'},
-  {at: 0.6, is: '13 14, 77 14, 77 76, 13 76'},
-  {at: 1, is: '15 10, 75 10, 75 80, 15 80'},
-  {at: 1.4, is: '17 6, 73 6, 73 84, 17 84'}
-]);
-assertAttributeInterpolation({
-  property: 'points',
-  from: '0 0, 10 0, 20 0, 30 0, 40 0',
-  to: '50 0, 60 0, 70 0'
-}, [
-  {at: -0.4, is: '0 0, 10 0, 20 0, 30 0, 40 0'},
-  {at: 0, is: '0 0, 10 0, 20 0, 30 0, 40 0'},
-  {at: 0.2, is: '0 0, 10 0, 20 0, 30 0, 40 0'},
-  {at: 0.6, is: '50 0, 60 0, 70 0'},
-  {at: 1, is: '50 0, 60 0, 70 0'},
-  {at: 1.4, is: '50 0, 60 0, 70 0'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-pointsAtX-pointsAtY-pointsAtZ-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-pointsAtX-pointsAtY-pointsAtZ-interpolation.html
deleted file mode 100644
index 1b3b920..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-pointsAtX-pointsAtY-pointsAtZ-interpolation.html
+++ /dev/null
@@ -1,50 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<feSpotLight class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'pointsAtX',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-assertAttributeInterpolation({
-  property: 'pointsAtY',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-assertAttributeInterpolation({
-  property: 'pointsAtZ',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-preserveAlpha-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-preserveAlpha-interpolation.html
deleted file mode 100644
index 31eea1d4..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-preserveAlpha-interpolation.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<defs>
-<filter>
-<feConvolveMatrix in="SourceGraphic" order="2 2" kernelMatrix="100 200 300 400" preserveAlpha="false" class="target" />
-</filter>
-</defs>
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'preserveAlpha',
-  from: 'false',
-  to: 'true'
-}, [
-  {at: -2.4, is: 'false'},
-  {at: 0, is: 'false'},
-  {at: 0.2, is: 'false'},
-  {at: 0.6, is: 'true'},
-  {at: 1, is: 'true'},
-  {at: 3.4, is: 'true'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-preserveAspectRatio-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-preserveAspectRatio-interpolation.html
deleted file mode 100644
index e4d8c2b..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-preserveAspectRatio-interpolation.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<defs>
-<filter>
-<feImage class="target" />
-<filter>
-</defs>
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'preserveAspectRatio',
-  from: 'xMidYMin',
-  to: 'xMaxYMid slice'
-}, [
-  {at: -2.4, is: 'xMidYMin'},
-  {at: 0, is: 'xMidYMin'},
-  {at: 0.2, is: 'xMidYMin'},
-  {at: 0.6, is: 'xMaxYMid slice'},
-  {at: 1, is: 'xMaxYMid slice'},
-  {at: 3.4, is: 'xMaxYMid slice'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-primitiveUnits-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-primitiveUnits-interpolation.html
deleted file mode 100644
index 47004a4..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-primitiveUnits-interpolation.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<filter class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'primitiveUnits',
-  from: 'userSpaceOnUse',
-  to: 'objectBoundingBox',
-}, [
-  {at: -2.4, is: 'userSpaceOnUse'},
-  {at: 0, is: 'userSpaceOnUse'},
-  {at: 0.2, is: 'userSpaceOnUse'},
-  {at: 0.6, is: 'objectBoundingBox'},
-  {at: 1, is: 'objectBoundingBox'},
-  {at: 3.4, is: 'objectBoundingBox'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-r-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-r-interpolation.html
deleted file mode 100644
index 85d986d..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-r-interpolation.html
+++ /dev/null
@@ -1,69 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<style>
-:root {
-  font: 10px Ahem;
-}
-</style>
-</head>
-<body>
-<template id="target-template">
-<svg width="7px" height="17px" viewBox="0 0 140 340">
-<circle class="target" cx="70" cy="70" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'r',
-  from: '10ch',
-  to: '60ch'
-}, [
-  {at: -0.4, is: '0ch'},
-  {at: 0, is: '10ch'},
-  {at: 0.2, is: '20ch'},
-  {at: 0.6, is: '40ch'},
-  {at: 1, is: '60ch'},
-  {at: 1.4, is: '80ch'}
-]);
-assertAttributeInterpolation({
-  property: 'r',
-  from: '10mm',
-  to: '6cm'
-}, [
-  {at: -0.4, is: '0mm'},
-  {at: 0, is: '10mm'},
-  {at: 0.2, is: '20mm'},
-  {at: 0.6, is: '40mm'},
-  {at: 1, is: '60mm'},
-  {at: 1.4, is: '80mm'}
-]);
-assertAttributeInterpolation({
-  property: 'r',
-  from: '50%', // http://www.w3.org/TR/SVG11/coords.html#Units 50% * sqrt(140**2+340**2)/sqrt(2) == 130
-  to: '14em' // 14*10 == 140
-}, [
-  {at: -0.4, is: 126},
-  {at: 0, is: 130},
-  {at: 0.2, is: 132},
-  {at: 0.6, is: 136},
-  {at: 1, is: 140},
-  {at: 1.4, is: 144}
-]);
-assertAttributeInterpolation({
-  property: 'r',
-  from: '10pc',
-  to: '20ch'
-}, [
-  {at: -0.4, is: '144'},
-  {at: 0, is: '10pc'},
-  {at: 0.2, is: '168'},
-  {at: 0.6, is: '184'},
-  {at: 1, is: '20ch'},
-  {at: 1.4, is: '216'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-radius-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-radius-interpolation.html
deleted file mode 100644
index cbb4edb0..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-radius-interpolation.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<feMorphology class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'radius',
-  from: '1',
-  to: '6 11'
-}, [
-  {at: -0.4, is: '-1, -3'},
-  {at: 0, is: '1, 1'},
-  {at: 0.2, is: '2, 3'},
-  {at: 0.6, is: '4, 7'},
-  {at: 1, is: '6, 11'},
-  {at: 1.4, is: '8, 15'}
-]);
-assertAttributeInterpolation({
-  property: 'radius',
-  from: '-2 10',
-  to: '3 10'
-}, [
-  {at: -0.4, is: '-4, 10'},
-  {at: 0, is: '-2 10'},
-  {at: 0.2, is: '-1, 10'},
-  {at: 0.6, is: '1, 10'},
-  {at: 1, is: '3, 10'},
-  {at: 1.4, is: '5, 10'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-refX-refY-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-refX-refY-interpolation.html
deleted file mode 100644
index c722c89..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-refX-refY-interpolation.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<marker class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'refX',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-assertAttributeInterpolation({
-  property: 'refY',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-result-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-result-interpolation.html
deleted file mode 100644
index 8693885f..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-result-interpolation.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<defs>
-<filter>
-<feBlend class="target" />
-</filter>
-</defs>
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'result',
-  from: 'foo',
-  to: 'bar'
-}, [
-  {at: -0.4, is: 'foo'},
-  {at: 0, is: 'foo'},
-  {at: 0.2, is: 'foo'},
-  {at: 0.6, is: 'bar'},
-  {at: 1, is: 'bar'},
-  {at: 1.4, is: 'bar'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-rotate-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-rotate-interpolation.html
deleted file mode 100644
index 44f86a3..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-rotate-interpolation.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<text>
-<tspan class="target">
-abcd
-</tspan>
-</text>
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'rotate',
-  from: '20, 30, 40, 500',
-  to: '120, 130, 140, 1500'
-}, [
-  {at: -0.4, is: '-20, -10, 0, 100'},
-  {at: 0, is: '20, 30, 40, 500'},
-  {at: 0.2, is: '40, 50, 60, 700'},
-  {at: 0.6, is: '80, 90, 100, 1100'},
-  {at: 1, is: '120, 130, 140, 1500'},
-  {at: 1.4, is: '160, 170, 180, 1900'}
-]);
-assertAttributeInterpolation({
-  property: 'rotate',
-  from: '60',
-  to: '70, 80'
-}, [
-  {at: -0.4, is: '60'},
-  {at: 0, is: '60'},
-  {at: 0.2, is: '60'},
-  {at: 0.6, is: '70, 80'},
-  {at: 1, is: '70, 80'},
-  {at: 1.4, is: '70, 80'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-rx-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-rx-interpolation.html
deleted file mode 100644
index 56643da..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-rx-interpolation.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<ellipse class="target" cx="20" cy="20" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'rx',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-assertAttributeInterpolation({
-  property: 'ry',
-  from: '10',
-  to: '60'
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 10},
-  {at: 0.2, is: 20},
-  {at: 0.6, is: 40},
-  {at: 1, is: 60},
-  {at: 1.4, is: 80}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-scale-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-scale-interpolation.html
deleted file mode 100644
index 25071c5..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-scale-interpolation.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<defs>
-<filter>
-<feDisplacementMap class="target" />
-</filter>
-</defs>
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'scale',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-seed-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-seed-interpolation.html
deleted file mode 100644
index 877f90e..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-seed-interpolation.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<defs>
-<filter>
-<feTurbulence class="target" />
-</filter>
-</defs>
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'seed',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-slope-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-slope-interpolation.html
deleted file mode 100644
index 232f121..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-slope-interpolation.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<feComponentTransfer>
-<feFuncR type="linear" class="target" />
-</feComponentTransfer>
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'slope',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-spacing-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-spacing-interpolation.html
deleted file mode 100644
index 95f3dc3..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-spacing-interpolation.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<textPath class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'spacing',
-  from: 'auto',
-  to: 'exact'
-}, [
-  {at: -2.4, is: 'auto'},
-  {at: 0, is: 'auto'},
-  {at: 0.2, is: 'auto'},
-  {at: 0.6, is: 'exact'},
-  {at: 1, is: 'exact'},
-  {at: 3.4, is: 'exact'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-specularConstant-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-specularConstant-interpolation.html
deleted file mode 100644
index 8846d02e..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-specularConstant-interpolation.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<fespecularlighting class="target" kernelUnitLength="1" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'specularConstant',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-specularExponent-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-specularExponent-interpolation.html
deleted file mode 100644
index ccb3cb1e..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-specularExponent-interpolation.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<feSpecularLighting class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'specularExponent',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-spreadMethod-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-spreadMethod-interpolation.html
deleted file mode 100644
index 88fc1acf..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-spreadMethod-interpolation.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<linearGradient class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'spreadMethod',
-  from: 'pad',
-  to: 'repeat'
-}, [
-  {at: -0.4, is: 'pad'},
-  {at: 0, is: 'pad'},
-  {at: 0.2, is: 'pad'},
-  {at: 0.6, is: 'repeat'},
-  {at: 1, is: 'repeat'},
-  {at: 1.4, is: 'repeat'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-startOffset-interpolation-001.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-startOffset-interpolation-001.html
deleted file mode 100644
index 0a5e000b..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-startOffset-interpolation-001.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script src="../../resources/ahem.js"></script>
-<style>
-:root {
-  font: 50px Ahem;
-}
-</style>
-</head>
-<body>
-<svg>
-  <defs>
-    <path id="path1" d="m 0 0 h 250 v 250 h -250 z"/>
-  </defs>
-</svg>
-<template id="target-template">
-<svg width="7px" height="17px" viewBox="0 0 140 340">
-  <text text-anchor="middle">
-    <textPath xlink:href="#path1" startOffset="50%" class="target">
-      Text on a path
-    </textPath>
-  </text>
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'startOffset',
-  from: '10in',
-  to: '770pt'
-}, [
-  {at: -0.4, is: '700pt'},
-  {at: 0, is: '720pt'},
-  {at: 0.2, is: '730pt'},
-  {at: 0.6, is: '750pt'},
-  {at: 1, is: '770pt'},
-  {at: 1.4, is: '790pt'}
-]);
-assertAttributeInterpolation({
-  property: 'startOffset',
-  from: '125',
-  to: '25ex'
-}, [
-  {at: 0, is: '125'},
-  {at: 1, is: '25ex'},
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-startOffset-interpolation-002-expected.txt b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-startOffset-interpolation-002-expected.txt
deleted file mode 100644
index 1e2df9a..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-startOffset-interpolation-002-expected.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-This is a testharness.js-based test.
-[FAIL] SMIL: Interpolate attribute <startOffset> from replace [25%] to replace [25em] at (0) is [250]
-  assert_equals: expected "250 " but got "35 "
-[FAIL] SMIL: Interpolate attribute <startOffset> from replace [25%] to replace [25em] at (0.2) is [450]
-  assert_equals: expected "450 " but got "278 "
-[FAIL] SMIL: Interpolate attribute <startOffset> from replace [25%] to replace [25em] at (0.6) is [850]
-  assert_equals: expected "850 " but got "764 "
-[FAIL] Web Animations: Interpolate attribute <startOffset> from replace [25%] to replace [25em] at (-0.4) is [-150]
-  assert_equals: expected "- 150 " but got "- 451 "
-[FAIL] Web Animations: Interpolate attribute <startOffset> from replace [25%] to replace [25em] at (0) is [250]
-  assert_equals: expected "250 " but got "35 "
-[FAIL] Web Animations: Interpolate attribute <startOffset> from replace [25%] to replace [25em] at (0.2) is [450]
-  assert_equals: expected "450 " but got "278 "
-[FAIL] Web Animations: Interpolate attribute <startOffset> from replace [25%] to replace [25em] at (0.6) is [850]
-  assert_equals: expected "850 " but got "764 "
-[FAIL] Web Animations: Interpolate attribute <startOffset> from replace [25%] to replace [25em] at (1.4) is [1650]
-  assert_equals: expected "1650 " but got "1736 "
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-startOffset-interpolation-002.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-startOffset-interpolation-002.html
deleted file mode 100644
index 6540e73..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-startOffset-interpolation-002.html
+++ /dev/null
@@ -1,55 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script src="../../resources/ahem.js"></script>
-<style>
-:root {
-  font: 50px Ahem;
-}
-</style>
-</head>
-<body>
-<svg>
-  <defs>
-    <path id="path1" d="m 0 0 h 250 v 250 h -250 z"/>
-  </defs>
-</svg>
-<template id="target-template">
-<svg width="7px" height="17px" viewBox="0 0 140 340">
-  <text text-anchor="middle">
-    <textPath xlink:href="#path1" startOffset="50%" class="target">
-      Text on a path
-    </textPath>
-  </text>
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'startOffset',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-assertAttributeInterpolation({
-  property: 'startOffset',
-  from: '25%', // 25% of 1000px path length is 250px.
-  to: '25em' // 25 times 50px font size is 1250px.
-}, [
-  {at: -0.4, is: -150},
-  {at: 0, is: 250},
-  {at: 0.2, is: 450},
-  {at: 0.6, is: 850},
-  {at: 1, is: 1250},
-  {at: 1.4, is: 1650}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-stdDeviation-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-stdDeviation-interpolation.html
deleted file mode 100644
index e7a94af..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-stdDeviation-interpolation.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<defs>
-<filter>
-<feGaussianBlur class="target" />
-</filter>
-</defs>
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'stdDeviation',
-  from: '1',
-  to: '6 11'
-}, [
-  {at: -0.4, is: '-1, -3'},
-  {at: 0, is: '1, 1'},
-  {at: 0.2, is: '2, 3'},
-  {at: 0.6, is: '4, 7'},
-  {at: 1, is: '6, 11'},
-  {at: 1.4, is: '8, 15'}
-]);
-assertAttributeInterpolation({
-  property: 'stdDeviation',
-  from: '-2 10',
-  to: '3 10'
-}, [
-  {at: -0.4, is: '-4, 10'},
-  {at: 0, is: '-2 10'},
-  {at: 0.2, is: '-1, 10'},
-  {at: 0.6, is: '1, 10'},
-  {at: 1, is: '3, 10'},
-  {at: 1.4, is: '5, 10'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-stitchTiles-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-stitchTiles-interpolation.html
deleted file mode 100644
index 518a2d8..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-stitchTiles-interpolation.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<defs>
-<filter>
-<feTurbulence baseFrequency="1" numOctaves="2" type="turbulence" class="target" />
-</filter>
-</defs>
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'stitchTiles',
-  from: 'noStitch',
-  to: 'stitch'
-}, [
-  {at: -0.4, is: 'noStitch'},
-  {at: 0, is: 'noStitch'},
-  {at: 0.2, is: 'noStitch'},
-  {at: 0.6, is: 'stitch'},
-  {at: 1, is: 'stitch'},
-  {at: 1.4, is: 'stitch'}
-]);
-assertAttributeInterpolation({
-  property: 'stitchTiles',
-  from: 'stitch',
-  to: 'noStitch'
-}, [
-  {at: -0.4, is: 'stitch'},
-  {at: 0, is: 'stitch'},
-  {at: 0.2, is: 'stitch'},
-  {at: 0.6, is: 'noStitch'},
-  {at: 1, is: 'noStitch'},
-  {at: 1.4, is: 'noStitch'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-surfaceScale-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-surfaceScale-interpolation.html
deleted file mode 100644
index f73ef5a..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-surfaceScale-interpolation.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<feDiffuseLighting class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'surfaceScale',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-tableValues-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-tableValues-interpolation.html
deleted file mode 100644
index 6c3c7d7..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-tableValues-interpolation.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<feComponentTransfer>
-<feFuncG type="table" class="target" />
-</feComponentTransfer>
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'tableValues',
-  from: '3 4',
-  to: '8'
-}, [
-  {at: -0.4, is: '3 4'},
-  {at: 0, is: '3 4'},
-  {at: 0.2, is: '3 4'},
-  {at: 0.6, is: '8'},
-  {at: 1, is: '8'},
-  {at: 1.4, is: '8'}
-]);
-assertAttributeInterpolation({
-  property: 'tableValues',
-  from: '1 2',
-  to: '6 7'
-}, [
-  {at: -0.4, is: '-1 0'},
-  {at: 0, is: '1 2'},
-  {at: 0.2, is: '2 3'},
-  {at: 0.6, is: '4 5'},
-  {at: 1, is: '6 7'},
-  {at: 1.4, is: '8 9'}
-]);
-
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-target-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-target-interpolation.html
deleted file mode 100644
index b3b873ef..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-target-interpolation.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<a class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'target',
-  from: '_top',
-  to: ':A0.-_:' // An XML name http://www.w3.org/TR/SVG/types.html#DataTypeXML-Name
-}, [
-  {at: -0.4, is: '_top'},
-  {at: 0, is: '_top'},
-  {at: 0.2, is: '_top'},
-  {at: 0.6, is: ':A0.-_:'},
-  {at: 1, is: ':A0.-_:'},
-  {at: 1.4, is: ':A0.-_:'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-targetX-targetY-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-targetX-targetY-interpolation.html
deleted file mode 100644
index 7f7edd05..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-targetX-targetY-interpolation.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<feConvolveMatrix class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'targetX',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-assertAttributeInterpolation({
-  property: 'targetY',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-textLength-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-textLength-interpolation.html
deleted file mode 100644
index cb3a5ad..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-textLength-interpolation.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<text class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'textLength',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-transform-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-transform-interpolation.html
deleted file mode 100644
index 65129876..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-transform-interpolation.html
+++ /dev/null
@@ -1,153 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<line x1="1" y1="2" x2="3" y2="4" class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-
-// Single transforms
-
-assertAttributeInterpolation({
-  property: 'transform',
-  from: 'translate(10 20)',
-  to: 'translate(30 60)'
-}, [
-  {at: -0.4, is: 'translate(2,4)'},
-  {at: 0, is: 'translate(10 20)'},
-  {at: 0.2, is: 'translate(14,28)'},
-  {at: 0.6, is: 'translate(22,44)'},
-  {at: 1, is: 'translate(30 60)'},
-  {at: 1.4, is: 'translate(38,76)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  from: 'scale(10 20)',
-  to: 'scale(30 60)'
-}, [
-  {at: -0.4, is: 'scale(2 4)'},
-  {at: 0, is: 'scale(10 20)'},
-  {at: 0.2, is: 'scale(14 28)'},
-  {at: 0.6, is: 'scale(22 44)'},
-  {at: 1, is: 'scale(30 60)'},
-  {at: 1.4, is: 'scale(38 76)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  from: 'rotate(10 20 30)',
-  to: 'rotate(40 80 160)'
-}, [
-  {at: -0.4, is: 'rotate(-2 -4 -22)'},
-  {at: 0, is: 'rotate(10 20 30)'},
-  {at: 0.2, is: 'rotate(16 32 56)'},
-  {at: 0.6, is: 'rotate(28 56 108)'},
-  {at: 1, is: 'rotate(40 80 160)'},
-  {at: 1.4, is: 'rotate(52 104 212)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  from: 'skewX(10)',
-  to: 'skewX(20)'
-}, [
-  {at: -0.4, is: 'skewX(6)'},
-  {at: 0, is: 'skewX(10)'},
-  {at: 0.2, is: 'skewX(12)'},
-  {at: 0.6, is: 'skewX(16)'},
-  {at: 1, is: 'skewX(20)'},
-  {at: 1.4, is: 'skewX(24)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  from: 'skewY(10)',
-  to: 'skewY(20)'
-}, [
-  {at: -0.4, is: 'skewY(6)'},
-  {at: 0, is: 'skewY(10)'},
-  {at: 0.2, is: 'skewY(12)'},
-  {at: 0.6, is: 'skewY(16)'},
-  {at: 1, is: 'skewY(20)'},
-  {at: 1.4, is: 'skewY(24)'}
-]);
-
-// Distinct transforms
-
-assertAttributeInterpolation({
-  property: 'transform',
-  from: 'translate(10 20)',
-  to: 'rotate(30 40 50)'
-}, [
-  {at: -0.4, is: 'translate(10 20)'},
-  {at: 0, is: 'translate(10 20)'},
-  {at: 0.2, is: 'translate(10 20)'},
-  {at: 0.6, is: 'rotate(30 40 50)'},
-  {at: 1, is: 'rotate(30 40 50)'},
-  {at: 1.4, is: 'rotate(30 40 50)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  from: 'skewX(10)',
-  to: 'skewY(20)'
-}, [
-  {at: -0.4, is: 'skewX(10)'},
-  {at: 0, is: 'skewX(10)'},
-  {at: 0.2, is: 'skewX(10)'},
-  {at: 0.6, is: 'skewY(20)'},
-  {at: 1, is: 'skewY(20)'},
-  {at: 1.4, is: 'skewY(20)'}
-]);
-
-// Common list of transforms
-
-assertAttributeInterpolation({
-  property: 'transform',
-  from: 'translate(110 20) scale(10 20) rotate(10 20 30)',
-  to: 'translate(130 60) scale(30 60) rotate(40 80 160)'
-}, [
-  {at: -0.4, is: 'translate(102,4) scale(2 4) rotate(-2 -4 -22)'},
-  {at: 0, is: 'translate(110 20) scale(10 20) rotate(10 20 30)'},
-  {at: 0.2, is: 'translate(114,28) scale(14 28) rotate(16 32 56)'},
-  {at: 0.6, is: 'translate(122,44) scale(22 44) rotate(28 56 108)'},
-  {at: 1, is: 'translate(130 60) scale(30 60) rotate(40 80 160)'},
-  {at: 1.4, is: 'translate(138,76) scale(38 76) rotate(52 104 212)'}
-]);
-
-// Distinct list of transforms
-
-assertAttributeInterpolation({
-  property: 'transform',
-  from: 'translate(110 20) scale(10 20) skewX(10) rotate(10 20 30)',
-  to: 'translate(130 60) scale(30 60) skewY(-30) rotate(40 80 160)'
-}, [
-  {at: -0.4, is: 'translate(110 20) scale(10 20) skewX(10) rotate(10 20 30)'},
-  {at: 0, is: 'translate(110 20) scale(10 20) skewX(10) rotate(10 20 30)'},
-  {at: 0.2, is: 'translate(110 20) scale(10 20) skewX(10) rotate(10 20 30)'},
-  {at: 0.6, is: 'translate(130 60) scale(30 60) skewY(-30) rotate(40 80 160)'},
-  {at: 1, is: 'translate(130 60) scale(30 60) skewY(-30) rotate(40 80 160)'},
-  {at: 1.4, is: 'translate(130 60) scale(30 60) skewY(-30) rotate(40 80 160)'}
-]);
-
-assertAttributeInterpolation({
-  property: 'transform',
-  from: 'translate(110 20) scale(10 20) skewX(10)',
-  to: 'translate(130 60) scale(30 60) skewX(-30) rotate(40 80 160)'
-}, [
-  {at: -0.4, is: 'translate(110 20) scale(10 20) skewX(10)'},
-  {at: 0, is: 'translate(110 20) scale(10 20) skewX(10)'},
-  {at: 0.2, is: 'translate(110 20) scale(10 20) skewX(10)'},
-  {at: 0.6, is: 'translate(130 60) scale(30 60) skewX(-30) rotate(40 80 160)'},
-  {at: 1, is: 'translate(130 60) scale(30 60) skewX(-30) rotate(40 80 160)'},
-  {at: 1.4, is: 'translate(130 60) scale(30 60) skewX(-30) rotate(40 80 160)'}
-]);
-
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-type-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-type-interpolation.html
deleted file mode 100644
index bd9cdb7..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-type-interpolation.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<defs>
-<filter>
-<feColorMatrix class="target" />
-</filter>
-</defs>
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'type',
-  from: 'saturate',
-  to: 'hueRotate'
-}, [
-  {at: -0.4, is: 'saturate'},
-  {at: 0, is: 'saturate'},
-  {at: 0.2, is: 'saturate'},
-  {at: 0.6, is: 'hueRotate'},
-  {at: 1, is: 'hueRotate'},
-  {at: 1.4, is: 'hueRotate'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-values-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-values-interpolation.html
deleted file mode 100644
index 76d2cdd..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-values-interpolation.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<defs>
-<filter>
-<feColorMatrix type="matrix" class="target" />
-</filter>
-</defs>
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'values',
-  from: '1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, -20',
-  to: '11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, -30'
-}, [
-  {at: -0.4, is: '-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, -16'},
-  {at: 0, is: '1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, -20'},
-  {at: 0.2, is: '3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, -22'},
-  {at: 0.6, is: '7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -26'},
-  {at: 1, is: '11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, -30'},
-  {at: 1.4, is: '15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, -34'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-viewBox-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-viewBox-interpolation.html
deleted file mode 100644
index e98fe14..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-viewBox-interpolation.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<defs>
-<marker class="target" />
-</defs>
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'viewBox',
-  from: '-10, 20, 80, 90',
-  to: '-20, 30, 70, 80'
-}, [
-  {at: -0.4, is: '-6, 16, 84, 94'},
-  {at: 0, is: '-10, 20, 80, 90'},
-  {at: 0.2, is: '-12, 22, 78, 88'},
-  {at: 0.6, is: '-16, 26, 74, 84'},
-  {at: 1, is: '-20, 30, 70, 80'},
-  {at: 1.4, is: '-24, 34, 66, 76'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-width-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-width-interpolation.html
deleted file mode 100644
index c561683..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-width-interpolation.html
+++ /dev/null
@@ -1,166 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script src="../../resources/ahem.js"></script>
-<style>
-:root {
-  font: 10px Ahem;
-}
-</style>
-</head>
-<body>
-<template id="target-template">
-<svg width="200px" height="300px" viewBox="0 0 1500 1000">
-<rect class="target" x="10" y="10" width="10" height="10" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'width',
-  from: 10,
-  to: 60
-}, [
-  {at: -0.4, is: 0},
-  {at: 0, is: 10},
-  {at: 0.2, is: 20},
-  {at: 0.6, is: 40},
-  {at: 1, is: 60},
-  {at: 1.4, is: 80}
-]);
-assertAttributeInterpolation({
-  property: 'width',
-  from: '10%',
-  to: '60%'
-}, [
-  {at: -0.4, is: '0%'},
-  {at: 0, is: '10%'},
-  {at: 0.2, is: '20%'},
-  {at: 0.6, is: '40%'},
-  {at: 1, is: '60%'},
-  {at: 1.4, is: '80%'}
-]);
-assertAttributeInterpolation({
-  property: 'width',
-  from: '10em',
-  to: '60em'
-}, [
-  {at: -0.4, is: '0em'},
-  {at: 0, is: '10em'},
-  {at: 0.2, is: '20em'},
-  {at: 0.6, is: '40em'},
-  {at: 1, is: '60em'},
-  {at: 1.4, is: '80em'}
-]);
-assertAttributeInterpolation({
-  property: 'width',
-  from: '10ex',
-  to: '60ex'
-}, [
-  {at: -0.4, is: '0ex'},
-  {at: 0, is: '10ex'},
-  {at: 0.2, is: '20ex'},
-  {at: 0.6, is: '40ex'},
-  {at: 1, is: '60ex'},
-  {at: 1.4, is: '80ex'}
-]);
-assertAttributeInterpolation({
-  property: 'width',
-  from: '10rem',
-  to: '60rem'
-}, [
-  {at: -0.4, is: '0rem'},
-  {at: 0, is: '10rem'},
-  {at: 0.2, is: '20rem'},
-  {at: 0.6, is: '40rem'},
-  {at: 1, is: '60rem'},
-  {at: 1.4, is: '80rem'}
-]);
-assertAttributeInterpolation({
-  property: 'width',
-  from: '10in',
-  to: '20rem'
-}, [
-  {at: -0.4, is: '1264'},
-  {at: 0, is: '10in'},
-  {at: 0.2, is: '808'},
-  {at: 0.6, is: '504'},
-  {at: 1, is: '20rem'},
-  {at: 1.4, is: '0'}
-]);
-assertAttributeInterpolation({
-  property: 'width',
-  from: '1vw',
-  to: '6vw'
-}, [
-  {at: -0.4, is: '0vw'},
-  {at: 0, is: '1vw'},
-  {at: 0.2, is: '2vw'},
-  {at: 0.6, is: '4vw'},
-  {at: 1, is: '6vw'},
-  {at: 1.4, is: '8vw'}
-]);
-assertAttributeInterpolation({
-  property: 'width',
-  from: '1vh',
-  to: '6vh'
-}, [
-  {at: -0.4, is: '0vh'},
-  {at: 0, is: '1vh'},
-  {at: 0.2, is: '2vh'},
-  {at: 0.6, is: '4vh'},
-  {at: 1, is: '6vh'},
-  {at: 1.4, is: '8vh'}
-]);
-assertAttributeInterpolation({
-  property: 'width',
-  from: '1vmin',
-  to: '6vmin'
-}, [
-  {at: -0.4, is: '0vmin'},
-  {at: 0, is: '1vmin'},
-  {at: 0.2, is: '2vmin'},
-  {at: 0.6, is: '4vmin'},
-  {at: 1, is: '6vmin'},
-  {at: 1.4, is: '8vmin'}
-]);
-assertAttributeInterpolation({
-  property: 'width',
-  from: '1vmax',
-  to: '6vmax'
-}, [
-  {at: -0.4, is: '0vmax'},
-  {at: 0, is: '1vmax'},
-  {at: 0.2, is: '2vmax'},
-  {at: 0.6, is: '4vmax'},
-  {at: 1, is: '6vmax'},
-  {at: 1.4, is: '8vmax'}
-]);
-assertAttributeInterpolation({
-  property: 'width',
-  from: '10vh',
-  to: '20vw'
-}, [
-  {at: -0.4, is: '20'},
-  {at: 0, is: '10vh'},
-  {at: 0.2, is: '80'},
-  {at: 0.6, is: '120'},
-  {at: 1, is: '20vw'},
-  {at: 1.4, is: '200'}
-]);
-assertAttributeInterpolation({
-  property: 'width',
-  from: '10vmin',
-  to: '20vmax'
-}, [
-  {at: -0.4, is: '20'},
-  {at: 0, is: '10vmin'},
-  {at: 0.2, is: '80'},
-  {at: 0.6, is: '120'},
-  {at: 1, is: '20vmax'},
-  {at: 1.4, is: '200'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-x-list-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-x-list-interpolation.html
deleted file mode 100644
index d7bd1d6..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-x-list-interpolation.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<!DOCTYPE html>
-<style>
-body {
-  font-size: 10px;
-}
-</style>
-<body>
-<template id="target-template">
-  <svg width="0" height="0" viewBox="0 0 1000 1000">
-    <text class="target"/>
-  </svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-
-assertAttributeInterpolation({
-  property: 'x',
-  from: '0, -1, 2',
-  to: '5, -6, 7',
-}, [
-  {at: -0.4, is: '-2, 1, 0'},
-  {at: 0, is: '0, -1, 2'},
-  {at: 0.2, is: '1, -2, 3'},
-  {at: 0.6, is: '3, -4, 5'},
-  {at: 1, is: '5, -6, 7'},
-  {at: 1.4, is: '7, -8, 9'},
-]);
-
-assertAttributeInterpolation({
-  property: 'x',
-  from: '0em, 1ex, 2rem',
-  to: '5em, 6ex, 7rem',
-}, [
-  {at: -0.4, is: '-2em, -1ex, 0rem'},
-  {at: 0, is: '0em, 1ex, 2rem'},
-  {at: 0.2, is: '1em, 2ex, 3rem'},
-  {at: 0.6, is: '3em, 4ex, 5rem'},
-  {at: 1, is: '5em, 6ex, 7rem'},
-  {at: 1.4, is: '7em, 8ex, 9rem'},
-]);
-
-assertAttributeInterpolation({
-  property: 'x',
-  from: '55%, 5em, 0',
-  to: '5em, 55%, 0',
-}, [
-  {at: -0.4, is: '750, -150, 0'},
-  {at: 0, is: '550, 50, 0'},
-  {at: 0.2, is: '450, 150, 0'},
-  {at: 0.6, is: '250, 350, 0'},
-  {at: 1, is: '50, 550, 0'},
-  {at: 1.4, is: '-150, 750, 0'},
-]);
-</script>
-</body>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-x-y-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-x-y-interpolation.html
deleted file mode 100644
index 515ff63..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-x-y-interpolation.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-  <svg width="90" height="90">
-    <rect class="target"/>
-  </svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-
-assertAttributeInterpolation({
-  property: 'x',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-
-assertAttributeInterpolation({
-  property: 'y',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-x1-x2-y1-y2-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-x1-x2-y1-y2-interpolation.html
deleted file mode 100644
index a6619383..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-x1-x2-y1-y2-interpolation.html
+++ /dev/null
@@ -1,62 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<line class="target" x1="10" y1="10" x2="60" y2="60" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'x1',
-  from: 10,
-  to: 60
-}, [
-  {at: -0.4, is: -10},
-  {at: 0, is: 10},
-  {at: 0.2, is: 20},
-  {at: 0.6, is: 40},
-  {at: 1, is: 60},
-  {at: 1.4, is: 80}
-]);
-assertAttributeInterpolation({
-  property: 'x2',
-  from: 10,
-  to: 60
-}, [
-  {at: -0.4, is: -10},
-  {at: 0, is: 10},
-  {at: 0.2, is: 20},
-  {at: 0.6, is: 40},
-  {at: 1, is: 60},
-  {at: 1.4, is: 80}
-]);
-assertAttributeInterpolation({
-  property: 'y1',
-  from: 10,
-  to: 60
-}, [
-  {at: -0.4, is: -10},
-  {at: 0, is: 10},
-  {at: 0.2, is: 20},
-  {at: 0.6, is: 40},
-  {at: 1, is: 60},
-  {at: 1.4, is: 80}
-]);
-assertAttributeInterpolation({
-  property: 'y2',
-  from: 10,
-  to: 60
-}, [
-  {at: -0.4, is: -10},
-  {at: 0, is: 10},
-  {at: 0.2, is: 20},
-  {at: 0.6, is: 40},
-  {at: 1, is: 60},
-  {at: 1.4, is: 80}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-xChannelSelector-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-xChannelSelector-interpolation.html
deleted file mode 100644
index c5c7734a..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-xChannelSelector-interpolation.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<feDisplacementMap class="target" />
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'xChannelSelector',
-  from: 'R',
-  to: 'A'
-}, [
-  {at: -2.4, is: 'R'},
-  {at: 0, is: 'R'},
-  {at: 0.2, is: 'R'},
-  {at: 0.6, is: 'A'},
-  {at: 1, is: 'A'},
-  {at: 3.4, is: 'A'}
-]);
-assertAttributeInterpolation({
-  property: 'yChannelSelector',
-  from: 'B',
-  to: 'G'
-}, [
-  {at: -2.4, is: 'B'},
-  {at: 0, is: 'B'},
-  {at: 0.2, is: 'B'},
-  {at: 0.6, is: 'G'},
-  {at: 1, is: 'G'},
-  {at: 3.4, is: 'G'}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-y-list-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-y-list-interpolation.html
deleted file mode 100644
index 462df964..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-y-list-interpolation.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<!DOCTYPE html>
-<style>
-body {
-  font-size: 10px;
-}
-</style>
-<body>
-<template id="target-template">
-  <svg width="0" height="0" viewBox="0 0 1000 1000">
-    <text class="target"/>
-  </svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-
-assertAttributeInterpolation({
-  property: 'y',
-  from: '0, -1, 2',
-  to: '5, -6, 7'
-}, [
-  {at: -0.4, is: '-2, 1, 0'},
-  {at: 0, is: '0, -1, 2'},
-  {at: 0.2, is: '1, -2, 3'},
-  {at: 0.6, is: '3, -4, 5'},
-  {at: 1, is: '5, -6, 7'},
-  {at: 1.4, is: '7, -8, 9'}
-]);
-
-assertAttributeInterpolation({
-  property: 'y',
-  from: '0em, 1ex, 2rem',
-  to: '5em, 6ex, 7rem'
-}, [
-  {at: -0.4, is: '-2em, -1ex, 0rem'},
-  {at: 0, is: '0em, 1ex, 2rem'},
-  {at: 0.2, is: '1em, 2ex, 3rem'},
-  {at: 0.6, is: '3em, 4ex, 5rem'},
-  {at: 1, is: '5em, 6ex, 7rem'},
-  {at: 1.4, is: '7em, 8ex, 9rem'}
-]);
-
-assertAttributeInterpolation({
-  property: 'y',
-  from: '55%, 5em, 0',
-  to: '5em, 55%, 0'
-}, [
-  {at: -0.4, is: '750, -150, 0'},
-  {at: 0, is: '550, 50, 0'},
-  {at: 0.2, is: '450, 150, 0'},
-  {at: 0.6, is: '250, 350, 0'},
-  {at: 1, is: '50, 550, 0'},
-  {at: 1.4, is: '-150, 750, 0'}
-]);
-</script>
-</body>
diff --git a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-z-interpolation.html b/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-z-interpolation.html
deleted file mode 100644
index d2d894f..0000000
--- a/third_party/blink/web_tests/animations/svg-attribute-interpolation/svg-z-interpolation.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<template id="target-template">
-<svg width="90" height="90">
-<defs>
-<filter>
-<fePointLight class="target" />
-</filter>
-</defs>
-</svg>
-</template>
-<script src="resources/interpolation-test.js"></script>
-<script>
-'use strict';
-assertAttributeInterpolation({
-  property: 'z',
-  from: '1',
-  to: '6'
-}, [
-  {at: -0.4, is: -1},
-  {at: 0, is: 1},
-  {at: 0.2, is: 2},
-  {at: 0.6, is: 4},
-  {at: 1, is: 6},
-  {at: 1.4, is: 8}
-]);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/svg/clear-svg-animation-effects.html b/third_party/blink/web_tests/animations/svg/clear-svg-animation-effects.html
deleted file mode 100644
index d225a2a..0000000
--- a/third_party/blink/web_tests/animations/svg/clear-svg-animation-effects.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<svg>
-  <stop id="target" offset="1"/>
-</svg>
-<script>
-var asyncHandle = async_test('SVG Attributes should return to their base values after animations have stopped applying.');
-
-var animation = target.animate([
-  {'svg-offset': '0'},
-  {'svg-offset': '0.5'},
-], 1000);
-animation.pause();
-animation.currentTime = 500;
-
-requestAnimationFrame(() => {
-  asyncHandle.step(() => {
-    assert_equals(target.offset.animVal, 0.25, 'Animation is in effect.');
-  });
-  animation.cancel();
-  requestAnimationFrame(() => {
-    asyncHandle.step(() => {
-      assert_equals(target.offset.animVal, 1, 'Animation is no longer in effect.');
-    });
-    asyncHandle.done();
-  });
-});
-</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/animations/svg/svg-animation-affects-use-elements-expected.html b/third_party/blink/web_tests/animations/svg/svg-animation-affects-use-elements-expected.html
deleted file mode 100644
index 7f38a91..0000000
--- a/third_party/blink/web_tests/animations/svg/svg-animation-affects-use-elements-expected.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<!DOCTYPE html>
-<svg>
-  <rect x="100" y="50" width="100" height="40" fill="green" />
-  <rect x="100" y="100" width="100" height="40" fill="green" />
-</svg>
diff --git a/third_party/blink/web_tests/animations/svg/svg-animation-affects-use-elements.html b/third_party/blink/web_tests/animations/svg/svg-animation-affects-use-elements.html
deleted file mode 100644
index 3fcb8ad..0000000
--- a/third_party/blink/web_tests/animations/svg/svg-animation-affects-use-elements.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<!DOCTYPE html>
-<svg>
-  <defs>
-    <rect x="0" y="0" width="100" height="40" id="target" fill="green" />
-    <rect x="100" y="0" width="100" height="40" id="expected" fill="red" />
-    <use xlink:href="#target" id="use"/>
-  </defs>
-
-  <use y="50" xlink:href="#expected"/>
-  <use y="100" xlink:href="#expected"/>
-
-  <use y="50" xlink:href="#target"/>
-  <use y="100" xlink:href="#use"/>
-</svg>
-<script>
-target.animate([{'svg-x': '100'}, {'svg-x': '100'}], {fill: 'forwards'});
-</script>
diff --git a/third_party/blink/web_tests/animations/svg/svg-presentation-attribute-animation.html b/third_party/blink/web_tests/animations/svg/svg-presentation-attribute-animation.html
deleted file mode 100644
index 0d3fe11d..0000000
--- a/third_party/blink/web_tests/animations/svg/svg-presentation-attribute-animation.html
+++ /dev/null
@@ -1,86 +0,0 @@
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-
-<svg>
-  <rect id="target"/>
-</svg>
-
-<script>
-'use strict';
-
-var testCases = [
-  ['alignment-baseline', 'middle'],
-  ['baseline-shift', '100px'],
-  ['buffered-rendering', 'dynamic'],
-  ['clip-path', 'url("#test")'],
-  ['clip-rule', 'evenodd'],
-  ['color', 'rgb(1, 2, 3)'],
-  ['color-interpolation', 'linearrgb'],
-  ['color-interpolation-filters', 'srgb'],
-  ['color-rendering', 'optimizespeed'],
-  ['cursor', 'url("test://uri/"), auto'],
-  ['dominant-baseline', 'middle'],
-  ['fill', 'rgb(1, 2, 3)'],
-  ['fill-opacity', '0.25'],
-  ['fill-rule', 'evenodd'],
-  ['filter', 'url("#test")'],
-  ['flood-color', 'rgb(1, 2, 3)'],
-  ['flood-opacity', '0.25'],
-  ['font-family', "\"Test Font\""],
-  ['font-size', '123px'],
-  ['font-stretch', '75%'],
-  ['font-style', 'italic'],
-  ['font-variant', 'small-caps'],
-  ['font-weight', '900'],
-  ['image-rendering', 'pixelated'],
-  ['letter-spacing', '123px'],
-  ['lighting-color', 'rgb(1, 2, 3)'],
-  ['marker-end', 'url("#test")'],
-  ['marker-mid', 'url("#test")'],
-  ['marker-start', 'url("#test")'],
-  ['mask', 'url("#test")'],
-  ['mask-type', 'alpha'],
-  ['opacity', '0.25'],
-  ['overflow', 'hidden'],
-  ['paint-order', 'fill markers'],
-  ['pointer-events', 'all'],
-  ['shape-rendering', 'geometricprecision'],
-  ['stop-color', 'rgb(1, 2, 3)'],
-  ['stop-opacity', '0.25'],
-  ['stroke', 'rgb(1, 2, 3)'],
-  ['stroke-dasharray', '1px, 2px, 3px'],
-  ['stroke-dashoffset', '123px'],
-  ['stroke-linecap', 'square'],
-  ['stroke-linejoin', 'round'],
-  ['stroke-miterlimit', '123'],
-  ['stroke-opacity', '0.25'],
-  ['stroke-width', '123px'],
-  ['text-anchor', 'middle'],
-  ['text-decoration', 'underline solid rgb(1, 2, 3)'],
-  ['text-rendering', 'geometricprecision'],
-  ['vector-effect', 'non-scaling-stroke'],
-  ['visibility', 'collapse'],
-  ['word-spacing', '123px'],
-];
-
-function svgPrefix(property) {
-  return 'svg-' + property;
-}
-
-test(() => {
-  for (var [property, value] of testCases) {
-    assert_not_equals(getComputedStyle(target)[property], value, 'Precheck that this test is using a non-default value for ' + property);
-  }
-}, 'Pretest assertions');
-
-// Separate animate() and getComputedStyle() into different phases to avoid quadratic animated style recalc churn.
-for (var [property, value] of testCases) {
-  target.animate({[svgPrefix(property)]: value}, {fill: 'forwards'});
-}
-
-for (var [property, value] of testCases) {
-  test(() => {
-    assert_equals(getComputedStyle(target)[property], value);
-  }, 'Web Animations can target ' + svgPrefix(property));
-}
-</script>
diff --git a/third_party/blink/web_tests/css3/calc/number-parsing.html b/third_party/blink/web_tests/css3/calc/number-parsing.html
index b369946..0f18c4b 100644
--- a/third_party/blink/web_tests/css3/calc/number-parsing.html
+++ b/third_party/blink/web_tests/css3/calc/number-parsing.html
@@ -42,7 +42,7 @@
   assertParsedValue('font-weight', 'calc(100 + 200)', 'calc(300)');
 }, 'Ensure using calc() for CSS numbers with + on font-weight does not crash or produce incorrect values.');
 test(function() {
-  assertParsedValue('flex', 'calc(1 + 2) calc(3 + 4)', '3 7 0%');
+  assertParsedValue('flex', 'calc(1 + 2) calc(3 + 4)', 'calc(3) calc(7) 0%');
 }, 'Ensure using calc() for CSS numbers with + on flex does not crash or produce incorrect values.');
 test(function() {
   assertParsedValue('-webkit-filter', 'saturate(calc(4 / 2))', 'saturate(calc(2))');
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 c9875b1..a91188c 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
@@ -4690,6 +4690,13 @@
        null,
        {}
       ]
+     ],
+     "ruby-inlinize-fieldset-crash.html": [
+      "5454362077c4e01c6edd6f19f7fe7801b86a4b1b",
+      [
+       null,
+       {}
+      ]
      ]
     },
     "css-scoping": {
@@ -369365,7 +369372,7 @@
       []
      ],
      "WEB_FEATURES.yml": [
-      "e1df1b8c670205931df252d4956287277f97700d",
+      "cbdc654b1d6280d3eeb3d49e440b69c71eb00463",
       []
      ],
      "animating-new-content-ref.html": [
@@ -369673,6 +369680,10 @@
       []
      ],
      "navigation": {
+      "WEB_FEATURES.yml": [
+       "1b95bc2b45bbeb5535d60c0786f7f4794ab16620",
+       []
+      ],
       "at-rule-opt-in-auto-ref.html": [
        "be8cc501cf09a01105a8f0c89d8e47b91dd66c01",
        []
@@ -370074,6 +370085,12 @@
       "23852cf6a7cae7868ee19a52315be1f20c47ac84",
       []
      ],
+     "parsing": {
+      "WEB_FEATURES.yml": [
+       "e011b34e2a06d5edbbdde0cf541fb86f00803644",
+       []
+      ]
+     },
      "pseudo-element-overflow-hidden-ref.html": [
       "02bcb5bb49c09ba151b10751ad31b9ebba91bdef",
       []
@@ -766119,7 +766136,7 @@
       ]
      ],
      "quantizeLinear.https.any.js": [
-      "c25bdbaac60fca0525e8cbcf080c1319a5ab0c26",
+      "5c4989fdf31f2c94d028cd8a74fe935c49f09986",
       [
        "webnn/conformance_tests/quantizeLinear.https.any.html?cpu",
        {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-shorthand-calc-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-shorthand-calc-expected.txt
deleted file mode 100644
index 3441cee..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-shorthand-calc-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-This is a testharness.js-based test.
-[FAIL] e.style['flex'] = "sign(1em - 1px) sibling-index()" should set flex-basis
-  assert_equals: flex-basis should be canonical expected "auto" but got ""
-[FAIL] e.style['flex'] = "sign(1em - 1px) sibling-index()" should set flex-grow
-  assert_equals: flex-grow should be canonical expected "sign(1em - 1px)" but got ""
-[FAIL] e.style['flex'] = "sign(1em - 1px) sibling-index()" should set flex-shrink
-  assert_equals: flex-shrink should be canonical expected "sibling-index()" but got ""
-[FAIL] e.style['flex'] = "sign(1em - 1px) sibling-index()" should not set unrelated longhands
-  assert_true: expected true got false
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-shorthand-calc.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-shorthand-calc.html
index 6498988d..2cbd1c2 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-shorthand-calc.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-shorthand-calc.html
@@ -11,6 +11,6 @@
   test_shorthand_value('flex', 'sign(1em - 1px) sibling-index()', {
     'flex-grow': 'sign(1em - 1px)',
     'flex-shrink': 'sibling-index()',
-    'flex-basis': 'auto'
+    'flex-basis': '0%'
   });
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/parsing/flex-computed-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-flexbox/parsing/flex-computed-expected.txt
deleted file mode 100644
index 33fd04c5..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-flexbox/parsing/flex-computed-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-[FAIL] Property flex value 'calc(10 + (sign(20cqw - 10px) * 5)) calc(10 + (sign(20cqw - 10px) * 5)) 1px'
-  assert_true: 'calc(10 + (sign(20cqw - 10px) * 5)) calc(10 + (sign(20cqw - 10px) * 5)) 1px' is a supported value for flex. expected true got false
-[FAIL] Property flex value 'calc(-1) calc(-1) 0'
-  assert_true: 'calc(-1) calc(-1) 0' is a supported value for flex. expected true got false
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/parsing/flex-invalid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-flexbox/parsing/flex-invalid-expected.txt
deleted file mode 100644
index 96a40d6..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-flexbox/parsing/flex-invalid-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-[FAIL] e.style['flex'] = "1 2 calc(0)" should not set the property value
-  assert_equals: expected "" but got "1 2 0px"
-[FAIL] e.style['flex'] = "1 2 calc(3 - 3)" should not set the property value
-  assert_equals: expected "" but got "1 2 0px"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/parsing/flex-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-flexbox/parsing/flex-valid-expected.txt
index 39b72d2..efc8aa3c 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-flexbox/parsing/flex-valid-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/parsing/flex-valid-expected.txt
@@ -1,11 +1,7 @@
 This is a testharness.js-based test.
 [FAIL] e.style['flex'] = "calc(10 + (sign(20cqw - 10px) * 5)) calc(10 + (sign(20cqw - 10px) * 5)) 1px" should set the property value
-  assert_not_equals: property should be set got disallowed value ""
+  assert_equals: serialization should be canonical expected "calc(10 + (5 * sign(20cqw - 10px))) calc(10 + (5 * sign(20cqw - 10px))) 1px" but got "calc(10 + sign(20cqw - 10px) * 5) calc(10 + sign(20cqw - 10px) * 5) 1px"
 [FAIL] e.style['flex'] = "1 1 calc(10px + (sign(20cqw - 10px) * 5px))" should set the property value
   assert_equals: serialization should be canonical expected "1 1 calc(10px + (5px * sign(20cqw - 10px)))" but got "1 1 calc(10px + sign(20cqw - 10px) * 5px)"
-[FAIL] e.style['flex'] = "calc(1) calc(2 + 1) calc(3px)" should set the property value
-  assert_equals: serialization should be canonical expected "calc(1) calc(3) calc(3px)" but got "1 3 calc(3px)"
-[FAIL] e.style['flex'] = "calc(-1) calc(-1) 0" should set the property value
-  assert_not_equals: property should be set got disallowed value ""
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/scrollbar-gutter-with-background-gradient-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/scrollbar-gutter-with-background-gradient-ref.html
new file mode 100644
index 0000000..1af00bae
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/scrollbar-gutter-with-background-gradient-ref.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSS Overflow: test scrollbar-gutter with background gradient</title>
+<link rel="author" title="CGQAQ" href="mailto:m.jason.liu@gmail.com">
+<link rel="help" href="https://drafts.csswg.org/css-overflow-4/#scrollbar-gutter-property">
+<style>
+  html {
+    scrollbar-gutter: stable both-edges;
+    background-image: linear-gradient(to right, green, blue);
+    position: fixed;
+    inset: 0;
+  }
+</style>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/scrollbar-gutter-with-background-gradient.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/scrollbar-gutter-with-background-gradient.html
new file mode 100644
index 0000000..0b39244
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/scrollbar-gutter-with-background-gradient.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSS Overflow: test scrollbar-gutter with background gradient</title>
+<link rel="author" title="CGQAQ" href="mailto:m.jason.liu@gmail.com">
+<link rel="help" href="https://drafts.csswg.org/css-overflow-4/#scrollbar-gutter-property">
+<link rel="match" href="scrollbar-gutter-with-background-gradient-ref.html">
+<meta name=fuzzy content="maxDifference=0-1;totalPixels=0-70000">
+<style>
+  html {
+    scrollbar-gutter: stable both-edges;
+    background-image: linear-gradient(to right, green, blue);
+  }
+</style>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ruby/ruby-inlinize-fieldset-crash.html b/third_party/blink/web_tests/external/wpt/css/css-ruby/ruby-inlinize-fieldset-crash.html
new file mode 100644
index 0000000..5454362
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ruby/ruby-inlinize-fieldset-crash.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>crbug.com/402200344</title>
+<ruby><i>
+<object classid="5Ygt" name="NEefr" type="text/javascript"><fieldset style="display:contents;"><header></header>
+</object>
+</i>
+<rt>ô6Ì9ºÍ¶æ</ruby>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/WEB_FEATURES.yml
index e1df1b8c..cbdc654b 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/WEB_FEATURES.yml
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/WEB_FEATURES.yml
@@ -1,3 +1,7 @@
 features:
 - name: view-transitions
   files: "**"
+- name: view-transition-class
+  files:
+  - class-specificity.html
+  - pseudo-with-classes-*
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/navigation/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/navigation/WEB_FEATURES.yml
new file mode 100644
index 0000000..1b95bc2b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/navigation/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: cross-document-view-transitions
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/parsing/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/parsing/WEB_FEATURES.yml
new file mode 100644
index 0000000..e011b34
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/parsing/WEB_FEATURES.yml
@@ -0,0 +1,4 @@
+features:
+- name: view-transition-class
+  files:
+  - view-transition-class-*
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/rtp-stats-lifetime.https-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/rtp-stats-lifetime.https-expected.txt
new file mode 100644
index 0000000..db10a0f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webrtc/rtp-stats-lifetime.https-expected.txt
@@ -0,0 +1,7 @@
+This is a testharness.js-based test.
+[FAIL] RTCOutboundRtpStreamStats does not exist as early as have-local-offer
+  assert_false: outbound-rtp does not exist in have-local-offer expected false got true
+[FAIL] RTCInboundRtpStreamStats are created by packet reception
+  assert_false: inbound-rtp does not exist before packets are received expected false got true
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/rtp-stats-lifetime.https.html b/third_party/blink/web_tests/external/wpt/webrtc/rtp-stats-lifetime.https.html
new file mode 100644
index 0000000..4ddd6ad
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webrtc/rtp-stats-lifetime.https.html
@@ -0,0 +1,102 @@
+<!doctype html>
+<meta charset=utf-8>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+async function hasStats(pc, type) {
+  const report = await pc.getStats();
+  for (const stats of report.values()) {
+    if (stats.type == type) {
+      return true;
+    }
+  }
+  return false;
+}
+
+async function getInboundRtpPollUntilItExists(pc, kTimeoutMs = 10000) {
+  const t0 = performance.now();
+  while (performance.now() - t0 < kTimeoutMs) {
+    const report = await pc.getStats();
+    for (const stats of report.values()) {
+      if (stats.type == 'inbound-rtp') {
+        return stats;
+      }
+    }
+  }
+  return null;
+}
+
+promise_test(async t => {
+  const pc = new RTCPeerConnection();
+  t.add_cleanup(() => pc.close());
+
+  pc.addTransceiver('video');
+  assert_false(await hasStats(pc, 'outbound-rtp'),
+               'outbound-rtp does not exist after addTransceiver');
+  await pc.setLocalDescription();
+  assert_false(await hasStats(pc, 'outbound-rtp'),
+              'outbound-rtp does not exist in have-local-offer');
+}, `RTCOutboundRtpStreamStats does not exist as early as have-local-offer`);
+
+// This test does not exchange ICE candidates, meaning no packets are sent.
+// We should still see outbound-rtp stats because they are created by the O/A.
+promise_test(async t => {
+  const pc1 = new RTCPeerConnection();
+  t.add_cleanup(() => pc1.close());
+  const pc2 = new RTCPeerConnection();
+  t.add_cleanup(() => pc1.close());
+
+  // Offer to send. See previous test for assertions that the outbound-rtp is
+  // not created this early, which this test does not care about.
+  pc1.addTransceiver('video');
+  await pc1.setLocalDescription();
+
+  // Answer to send.
+  await pc2.setRemoteDescription(pc1.localDescription);
+  const [transceiver] = pc2.getTransceivers();
+  transceiver.direction = 'sendrecv';
+  assert_false(await hasStats(pc2, 'outbound-rtp'),
+               'outbound-rtp does not exist in has-remote-offer');
+  await pc2.setLocalDescription();
+  assert_true(await hasStats(pc2, 'outbound-rtp'),
+              'outbound-rtp exists after answerer returns to stable');
+
+  // Complete offerer negotiation.
+  await pc1.setRemoteDescription(pc2.localDescription);
+  assert_true(await hasStats(pc1, 'outbound-rtp'),
+              'outbound-rtp exists after offerer returns to stable');
+}, `RTCOutboundRtpStreamStats exists after returning to stable`);
+
+promise_test(async t => {
+  const pc1 = new RTCPeerConnection();
+  t.add_cleanup(() => pc1.close());
+  const pc2 = new RTCPeerConnection();
+  t.add_cleanup(() => pc1.close());
+  pc1.onicecandidate = e => pc2.addIceCandidate(e.candidate);
+  pc2.onicecandidate = e => pc1.addIceCandidate(e.candidate);
+
+  // Negotaite to send, but don't send anything yet (track is null).
+  const {sender} = pc1.addTransceiver('video');
+  await pc1.setLocalDescription();
+  await pc2.setRemoteDescription(pc1.localDescription);
+  await pc2.setLocalDescription();
+  await pc1.setRemoteDescription(pc2.localDescription);
+  assert_false(await hasStats(pc2, 'inbound-rtp'),
+               'inbound-rtp does not exist before packets are received');
+
+  // Start sending. This results in inbound-rtp being created.
+  const stream = await getNoiseStream({video:true});
+  const [track] = stream.getTracks();
+  await sender.replaceTrack(track);
+  const inboundRtp = await getInboundRtpPollUntilItExists(pc2);
+  assert_not_equals(
+      inboundRtp, null,
+      'inbound-rtp should be created in response to the sender having a track');
+  assert_greater_than(
+      inboundRtp.packetsReceived, 0,
+      'inbound-rtp must only exist after packets have been received');
+}, `RTCInboundRtpStreamStats are created by packet reception`);
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/digital-credentials/identity-get.tentative.https.html b/third_party/blink/web_tests/wpt_internal/digital-credentials/identity-get.tentative.https.html
index 0e16631..15ce0831d 100644
--- a/third_party/blink/web_tests/wpt_internal/digital-credentials/identity-get.tentative.https.html
+++ b/third_party/blink/web_tests/wpt_internal/digital-credentials/identity-get.tentative.https.html
@@ -26,8 +26,11 @@
 promise_test(async t => {
   let request = buildValidNavigatorIdentityRequest();
   let credential = await requestIdentityWithActivation(test_driver, request);
+  let expectedResponseData = { "token": "fake_test_token" };
   assert_equals("openid4vp", credential.protocol);
-  assert_equals("fake_test_token", credential.data);
+  assert_equals(
+    JSON.stringify(expectedResponseData),
+    JSON.stringify(credential.data));
 }, "navigator.identity.get() API works in toplevel frame.");
 
 promise_test(async t => {
diff --git a/third_party/dawn b/third_party/dawn
index 025b5011..66a8850 160000
--- a/third_party/dawn
+++ b/third_party/dawn
@@ -1 +1 @@
-Subproject commit 025b5011849104e079510121385aa099125ea65c
+Subproject commit 66a8850fbf4baf4311fa4410f88a3af9ed8f43b5
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src
index cfa11f3..cf70a05 160000
--- a/third_party/devtools-frontend/src
+++ b/third_party/devtools-frontend/src
@@ -1 +1 @@
-Subproject commit cfa11f3ba573a287a9e0fb71ab1ab640746f3477
+Subproject commit cf70a057cfa87616144125951b1e88c633006eac
diff --git a/third_party/lit/v3_0/BUILD.gn b/third_party/lit/v3_0/BUILD.gn
index 62abd83..a0c8bc6 100644
--- a/third_party/lit/v3_0/BUILD.gn
+++ b/third_party/lit/v3_0/BUILD.gn
@@ -61,6 +61,7 @@
     "//chrome/browser/resources/side_panel/shared:build_ts",
     "//chrome/browser/resources/signin:build_ts",
     "//chrome/browser/resources/signin/batch_upload:build_ts",
+    "//chrome/browser/resources/signin/history_sync_optin:build_ts",
     "//chrome/browser/resources/signin/profile_picker:build_ts",
     "//chrome/browser/resources/signin/signout_confirmation:build_ts",
     "//chrome/browser/resources/tab_search:build_ts",
diff --git a/third_party/llvm-libc/src b/third_party/llvm-libc/src
index 225cbad..ffdeea1 160000
--- a/third_party/llvm-libc/src
+++ b/third_party/llvm-libc/src
@@ -1 +1 @@
-Subproject commit 225cbadd34448e99d4fe6f2a75f20ec59bcdab83
+Subproject commit ffdeea1ab212d6349484afb9ba9532e252fde09d
diff --git a/third_party/skia b/third_party/skia
index 10f4cf9..b64f585 160000
--- a/third_party/skia
+++ b/third_party/skia
@@ -1 +1 @@
-Subproject commit 10f4cf9a817dbc0e86179ce38c48f6e44ddd25af
+Subproject commit b64f5854c4148431f1dba95b592795dc98f3e6c7
diff --git a/third_party/spirv-headers/src b/third_party/spirv-headers/src
index 0e71067..8c88e0c 160000
--- a/third_party/spirv-headers/src
+++ b/third_party/spirv-headers/src
@@ -1 +1 @@
-Subproject commit 0e710677989b4326ac974fd80c5308191ed80965
+Subproject commit 8c88e0c4c94a21de825efccba5f99a862b049825
diff --git a/third_party/vulkan-deps b/third_party/vulkan-deps
index b9840c7..1d9c182 160000
--- a/third_party/vulkan-deps
+++ b/third_party/vulkan-deps
@@ -1 +1 @@
-Subproject commit b9840c73fad2fd81fe88dd40806b3ef0ddbf5c13
+Subproject commit 1d9c182c6fab8ac1826d0487e4508a1016771277
diff --git a/third_party/vulkan-tools/src b/third_party/vulkan-tools/src
index da7c7db..289efcc 160000
--- a/third_party/vulkan-tools/src
+++ b/third_party/vulkan-tools/src
@@ -1 +1 @@
-Subproject commit da7c7db28d36f66dff88f00412dceb480ccc77ea
+Subproject commit 289efccc7560f2b970e2b4e0f50349da87669311
diff --git a/third_party/vulkan-validation-layers/src b/third_party/vulkan-validation-layers/src
index 2e6787d..912f6b6 160000
--- a/third_party/vulkan-validation-layers/src
+++ b/third_party/vulkan-validation-layers/src
@@ -1 +1 @@
-Subproject commit 2e6787d498d65bc20c195d667b8cd3c63e1a8aa9
+Subproject commit 912f6b6645b309c46828e43304d331cc9a218469
diff --git a/third_party/webgpu-cts/src b/third_party/webgpu-cts/src
index 2c09e17..bd79291 160000
--- a/third_party/webgpu-cts/src
+++ b/third_party/webgpu-cts/src
@@ -1 +1 @@
-Subproject commit 2c09e17c32931273808700d7544ec28470e5d5fe
+Subproject commit bd792919c655555a98c9813e2817a83e634a4111
diff --git a/third_party/webrtc b/third_party/webrtc
index dbb6921..77d37ae 160000
--- a/third_party/webrtc
+++ b/third_party/webrtc
@@ -1 +1 @@
-Subproject commit dbb6921457926818beaedbd1ea0ab4096ecd50be
+Subproject commit 77d37aec1d71b636781a7717537cf8538e60068f
diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec
index a0d9eca..2f5be98 100644
--- a/tools/gritsettings/resource_ids.spec
+++ b/tools/gritsettings/resource_ids.spec
@@ -636,6 +636,10 @@
     "META": {"sizes": {"includes": [10]}},
     "includes": [4940],
   },
+  "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/signin/history_sync_optin/resources.grd": {
+    "META": {"sizes": {"includes": [10],}},
+    "includes": [4950],
+  },
   "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/signin/profile_picker/resources.grd": {
     "META": {"sizes": {"includes": [50],}},
     "includes": [4960],
diff --git a/tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS b/tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS
index 5d336ffd..0ea597a 100644
--- a/tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS
+++ b/tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS
@@ -11,7 +11,6 @@
 mvanouwerkerk@chromium.org
 sinansahin@google.com
 jinsukkim@chromium.org
-altimin@chromium.org
 wenyufu@chromium.org
 peter@chromium.org
 ashleynewson@chromium.org
@@ -250,7 +249,6 @@
 dschuff@chromium.org
 fabiansommer@chromium.org
 # navigation
-altimin@chromium.org
 cthomp@chromium.org
 tbansal@chromium.org
 toyoshim@chromium.org
@@ -399,7 +397,6 @@
 jimmyxgong@chromium.org
 gavinwill@chromium.org
 # scheduler
-altimin@chromium.org
 spvw@chromium.org
 # search
 ender@google.com
diff --git a/tools/metrics/histograms/metadata/extensions/histograms.xml b/tools/metrics/histograms/metadata/extensions/histograms.xml
index e3aa920..155b815e 100644
--- a/tools/metrics/histograms/metadata/extensions/histograms.xml
+++ b/tools/metrics/histograms/metadata/extensions/histograms.xml
@@ -3826,8 +3826,6 @@
   <summary>
     The number of converted user scripts loaded at profile open.
 
-
-
     Histogram is in the process of being removed in favor of its incremented
     version that emits only on profile open for &quot;user&quot; profiles
     (profiles where people can install extensions, specifically profiles that
@@ -3873,8 +3871,6 @@
   <summary>
     The manifest version of each loaded extension.
 
-
-
     Histogram is in the process of being removed in favor of its incremented
     version that emits only on profile open for &quot;user&quot; profiles
     (profiles where people can install extensions, specifically profiles that
diff --git a/tools/metrics/histograms/metadata/ios/enums.xml b/tools/metrics/histograms/metadata/ios/enums.xml
index 925f751a..048d19c 100644
--- a/tools/metrics/histograms/metadata/ios/enums.xml
+++ b/tools/metrics/histograms/metadata/ios/enums.xml
@@ -1005,7 +1005,7 @@
   <int value="5" label="Animated Promo Dismissed"/>
 </enum>
 
-<!-- LINT.ThenChange(//ios/chrome/browser/ui/content_suggestions/set_up_list/constants.h:SegmentedDefaultBrowserPromoAction) -->
+<!-- LINT.ThenChange(//ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/constants.h:SegmentedDefaultBrowserPromoAction) -->
 
 <enum name="IOSSessionMigration">
   <int value="0" label="No Migration"/>
diff --git a/tools/metrics/histograms/metadata/navigation/histograms.xml b/tools/metrics/histograms/metadata/navigation/histograms.xml
index 071edb92..88d7003 100644
--- a/tools/metrics/histograms/metadata/navigation/histograms.xml
+++ b/tools/metrics/histograms/metadata/navigation/histograms.xml
@@ -81,6 +81,17 @@
 
 <!-- LINT.ThenChange(//tools/metrics/histograms/metadata/page/histograms.xml:PagePreloadingTriggerType) -->
 
+<!-- LINT.IfChange(ProcessReuseOnCOOPType) -->
+
+<variants name="ProcessReuseOnCOOPType">
+  <variant name="DifferentSiteInstance"/>
+  <variant name="None"/>
+  <variant name="Prerender"/>
+  <variant name="SameSiteNavigationInSingleWebContents"/>
+</variants>
+
+<!-- LINT.ThenChange(//content/browser/renderer_host/render_frame_host_manager.cc:ProcessReuseOnCOOPType) -->
+
 <variants name="RegularOrMHTMLType">
   <variant name="MHTML"/>
   <variant name="Regular"/>
@@ -493,7 +504,6 @@
 
 <histogram name="BackForwardCache.MainFrameHasPageshowListenersOnRestore"
     enum="BooleanPresent" expires_after="M82">
-  <owner>altimin@chromium.org</owner>
   <owner>hajimehoshi@chromium.org</owner>
   <owner>bfcache-dev@chromium.org</owner>
   <summary>
@@ -598,7 +608,6 @@
 <histogram name="BackForwardCache.Restore.NavigationToFirstPaint" units="ms"
     expires_after="2025-08-03">
   <owner>sreejakshetty@chromium.org</owner>
-  <owner>altimin@chromium.org</owner>
   <owner>bfcache-dev@chromium.org</owner>
   <summary>
     Duration between start of navigation restoring a document from back-forward
@@ -1891,6 +1900,29 @@
   <token key="FrameType" variants="FrameTypes"/>
 </histogram>
 
+<histogram name="Navigation.ProcessReuseOnCOOP.{ProcessReuseOnCOOPType}"
+    enum="Boolean" expires_after="2025-06-25">
+  <owner>taiyo@chromium.org</owner>
+  <owner>chrome-loading@google.com</owner>
+  <summary>
+    Records the result of process reuse when swapping Browsing Instances due to
+    COOP mismatches on `RenderFrameHostManager::GetSiteInstanceForNavigation()`.
+
+    The outcomes of reuse successes/failures are recorded once per each reuse
+    attempt categorized by `ProcessReuseOnCOOPType`. Specifically, 1)
+    `DifferentSiteInstance`: Candidate and target SiteInstances differ (e.g.,
+    cross-site navigations with speculative RFH) 2)
+    `SameSiteNavigationInSingleWebContents`: Same-site navigations with single
+    WebContents in the current BrowsingInstance 3) `Prerender`: Prerender's
+    initial navigation with new FrameTree. If none of these strategies match,
+    the type will be `None`, and the result is recorded as always false.
+
+    For more context, please see crbug.com/40254888, crbug.com/41492112,
+    crrev.com/c/6238439/comment/fb22b7bc_c8962d32/.
+  </summary>
+  <token key="ProcessReuseOnCOOPType" variants="ProcessReuseOnCOOPType"/>
+</histogram>
+
 <histogram name="Navigation.QueueTime.{Method}.{FrameType}" units="ms"
     expires_after="2025-08-10">
   <owner>cduvall@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/net/histograms.xml b/tools/metrics/histograms/metadata/net/histograms.xml
index 358ab91..140ca7b5 100644
--- a/tools/metrics/histograms/metadata/net/histograms.xml
+++ b/tools/metrics/histograms/metadata/net/histograms.xml
@@ -519,6 +519,22 @@
   </summary>
 </histogram>
 
+<histogram name="HttpCache.NoVarySearch.LookupTime" units="microseconds"
+    expires_after="2025-12-16">
+  <owner>ricea@chromium.org</owner>
+  <owner>net-dev@chromium.org</owner>
+  <summary>
+    The time spent executing net::NoVarySearchCache::Lookup(). This is recorded
+    once for every call to the function, so approximately once for every HTTP(S)
+    request.
+
+    This will be used to evaluate the need for optimization.
+
+    The histogram is not reported on Windows machines without high resolution
+    clocks.
+  </summary>
+</histogram>
+
 <histogram name="HttpCache.NoVarySearch.UseResult" enum="NoVarySearchUseResult"
     expires_after="2025-12-16">
   <owner>ricea@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/page/histograms.xml b/tools/metrics/histograms/metadata/page/histograms.xml
index f9bd5a9..6935503c 100644
--- a/tools/metrics/histograms/metadata/page/histograms.xml
+++ b/tools/metrics/histograms/metadata/page/histograms.xml
@@ -428,7 +428,6 @@
 
 <histogram name="PageLoad.BackForwardCache.Event"
     enum="PageLoadBackForwardCacheEvent" expires_after="2025-08-31">
-  <owner>altimin@chromium.org</owner>
   <owner>bmcquade@chromium.org</owner>
   <owner>hajimehoshi@chromium.org</owner>
   <summary>
@@ -3409,7 +3408,6 @@
     units="ms" expires_after="never">
 <!-- expires-never: used in server pipeline to derive additional metrics -->
 
-  <owner>altimin@chromium.org</owner>
   <owner>hajimehoshi@chromium.org</owner>
   <owner>bfcache-dev@chromium.org</owner>
   <owner>speed-metrics-dev@chromium.org</owner>
@@ -3434,7 +3432,6 @@
     units="ms" expires_after="never">
 <!-- expires-never: used in server pipeline to derive additional metrics -->
 
-  <owner>altimin@chromium.org</owner>
   <owner>hajimehoshi@chromium.org</owner>
   <owner>bfcache-dev@chromium.org</owner>
   <owner>speed-metrics-dev@chromium.org</owner>
@@ -3964,7 +3961,6 @@
     units="scorex10" expires_after="never">
 <!-- expires-never: used in server pipeline to derive additional metrics -->
 
-  <owner>altimin@chromium.org</owner>
   <owner>hajimehoshi@chromium.org</owner>
   <owner>bfcache-dev@chromium.org</owner>
   <summary>
@@ -3996,7 +3992,6 @@
 <histogram
     name="PageLoad.LayoutInstability.CumulativeShiftScore.MainFrame.AfterBackForwardCacheRestore"
     units="scorex10" expires_after="2022-01-02">
-  <owner>altimin@chromium.org</owner>
   <owner>hajimehoshi@chromium.org</owner>
   <owner>bfcache-dev@chromium.org</owner>
   <summary>
@@ -4329,7 +4324,6 @@
 <histogram
     name="PageLoad.PaintTiming.NavigationToFirstPaint.AfterBackForwardCacheRestore"
     units="ms" expires_after="2025-11-30">
-  <owner>altimin@chromium.org</owner>
   <owner>djw@chromium.org</owner>
   <owner>bfcache-dev@chromium.org</owner>
   <owner>speed-metrics-dev@chromium.org</owner>
@@ -4369,7 +4363,7 @@
     units="ms" expires_after="never">
 <!-- expires-never: used in server pipeline to derive additional metrics -->
 
-  <owner>altimin@chromium.org</owner>
+  <owner>rakina@chromium.org</owner>
   <owner>bfcache-dev@chromium.org</owner>
   <owner>speed-metrics-dev@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/renderer/histograms.xml b/tools/metrics/histograms/metadata/renderer/histograms.xml
index 903dc64..7b8e4c1 100644
--- a/tools/metrics/histograms/metadata/renderer/histograms.xml
+++ b/tools/metrics/histograms/metadata/renderer/histograms.xml
@@ -633,7 +633,6 @@
 <histogram name="RendererScheduler.RendererMainThreadLoad6" units="%"
     expires_after="2025-08-17">
   <owner>lizeb@chromium.org</owner>
-  <owner>altimin@chromium.org</owner>
   <summary>
     Renderer main thread load (percentage of time spent in tasks), reported in
     one second chunks.
diff --git a/tools/metrics/histograms/metadata/signin/histograms.xml b/tools/metrics/histograms/metadata/signin/histograms.xml
index 1620156f..97a9ee8e 100644
--- a/tools/metrics/histograms/metadata/signin/histograms.xml
+++ b/tools/metrics/histograms/metadata/signin/histograms.xml
@@ -1865,6 +1865,22 @@
   </summary>
 </histogram>
 
+<histogram name="Signin.IOSNumberOfAccountSwitches.{TimeRange}"
+    units="switches" expires_after="2026-03-01">
+  <owner>jlebel@chromium.org</owner>
+  <owner>treib@chromium.org</owner>
+  <owner>chrome-signin-mobile-team@google.com</owner>
+  <summary>
+    The number of times the user switched accounts in the {TimeRange}. Emitted
+    no more than once every 24 hours, as soon as Chrome detects that more than
+    24 hours passed from the last recording. Recorded only on iOS.
+  </summary>
+  <token key="TimeRange">
+    <variant name="Last7Days" summary="last 7 days"/>
+    <variant name="Last28Days" summary="last 28 days"/>
+  </token>
+</histogram>
+
 <histogram name="Signin.IOSNumberOfDeviceAccounts" units="accounts"
     expires_after="2025-08-24">
   <owner>jlebel@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/stability/histograms.xml b/tools/metrics/histograms/metadata/stability/histograms.xml
index 71fe299..80bc5441 100644
--- a/tools/metrics/histograms/metadata/stability/histograms.xml
+++ b/tools/metrics/histograms/metadata/stability/histograms.xml
@@ -383,7 +383,6 @@
 <histogram name="Stability.DebugScenario.Navigation" enum="DebugScenario"
     expires_after="2023-08-08">
   <owner>nasko@chromium.org</owner>
-  <owner>altimin@chromium.org</owner>
   <summary>
     Logged at the time when a complex debugging scenario is encountered. The
     enum value is the type of scenario encountered. This metric will give us two
diff --git a/tools/metrics/histograms/metadata/ui/enums.xml b/tools/metrics/histograms/metadata/ui/enums.xml
index bdad924..08ca102 100644
--- a/tools/metrics/histograms/metadata/ui/enums.xml
+++ b/tools/metrics/histograms/metadata/ui/enums.xml
@@ -750,6 +750,7 @@
   <int value="48333657" label="chrome://about/"/>
   <int value="57900378" label="chrome://conch/"/>
   <int value="58807865" label="chrome://local-state/"/>
+  <int value="71502624" label="chrome://history-sync-optin/"/>
   <int value="84832110" label="chrome://fileicon/"/>
   <int value="104579118" label="chrome://boca-app/"/>
   <int value="110166858" label="chrome://saved-tab-groups-unsupported/"/>
diff --git a/tools/metrics/histograms/metadata/web_core/histograms.xml b/tools/metrics/histograms/metadata/web_core/histograms.xml
index d6452c80..d89a427 100644
--- a/tools/metrics/histograms/metadata/web_core/histograms.xml
+++ b/tools/metrics/histograms/metadata/web_core/histograms.xml
@@ -102,7 +102,6 @@
 <histogram name="WebCore.FindInPage.TaskDuration" units="ms"
     expires_after="2023-05-07">
   <owner>rakina@chromium.org</owner>
-  <owner>altimin@chromium.org</owner>
   <summary>
     Records how long one find-in-page task took from invocation start to end.
     Emitted when a find-in-page task finished running.
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index ef05571..46e6683 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -3407,7 +3407,6 @@
 </event>
 
 <event name="BackForwardCacheDisabledForRenderFrameHostReason">
-  <owner>altimin@chromium.org</owner>
   <owner>hajimehoshi@chromium.org</owner>
   <summary>
     Recorded at a history commit for each reason passed to
@@ -3432,7 +3431,6 @@
 </event>
 
 <event name="BackForwardCacheDisallowActivationReason">
-  <owner>altimin@chromium.org</owner>
   <owner>hajimehoshi@chromium.org</owner>
   <owner>fergal@chromium.org</owner>
   <summary>
@@ -11298,7 +11296,6 @@
 </event>
 
 <event name="HistoryNavigation" singular="True">
-  <owner>altimin@chromium.org</owner>
   <owner>arthursonzogni@chromium.org</owner>
   <owner>hajimehoshi@chromium.org</owner>
   <summary>
@@ -16563,7 +16560,6 @@
     </summary>
   </metric>
   <metric name="IsCrossProcessNavigation">
-    <owner>altimin@chromium.org</owner>
     <owner>arthursonzogni@chromium.org</owner>
     <summary>
       Whether the navigation resulted in the main frame being hosted in a
@@ -16709,7 +16705,6 @@
     </aggregation>
   </metric>
   <metric name="MainDocumentSequenceNumber">
-    <owner>altimin@chromium.org</owner>
     <owner>arthursonzogni@chromium.org</owner>
     <summary>
       An id for the main frame's document associated with the current
@@ -16824,7 +16819,6 @@
     </summary>
   </metric>
   <metric name="NavigationEntryOffset">
-    <owner>altimin@chromium.org</owner>
     <owner>arthursonzogni@chromium.org</owner>
     <summary>
       Difference between the last committed navigation entry index before and
@@ -23979,7 +23973,6 @@
 
 <event name="UserPerceivedPageVisit" singular="True">
   <owner>djw@chromium.org</owner>
-  <owner>altimin@chromium.org</owner>
   <summary>
     Metrics related to a page visit as a user perceives it, regardless of how
     the page was visited. More metrics may be associated with a particular page
diff --git a/tools/whats_new/OWNERS b/tools/whats_new/OWNERS
index eceac4c..34b9ce9 100644
--- a/tools/whats_new/OWNERS
+++ b/tools/whats_new/OWNERS
@@ -1 +1 @@
-file://ios/chrome/browser/ui/whats_new/OWNERS
+file://ios/chrome/browser/whats_new/OWNERS
diff --git a/tools/whats_new/whats_new_util.py b/tools/whats_new/whats_new_util.py
index e0a0f15..b471359 100644
--- a/tools/whats_new/whats_new_util.py
+++ b/tools/whats_new/whats_new_util.py
@@ -47,7 +47,7 @@
     feature_name = feature_dict['Feature name']
     whats_new_item_file = os.path.join(
         BASE_DIR,
-        '../ios/chrome/browser/ui/whats_new/data_source/whats_new_item.h')
+        '../ios/chrome/browser/whats_new/ui/data_source/whats_new_item.h')
     with open(whats_new_item_file, 'r+', encoding='utf-8', newline='') as file:
         file_content = file.read()
         read_whats_new_types_regex = r'enum class WhatsNewType\s*\{\s(.*?)\s\}'
@@ -103,7 +103,7 @@
 
   """
     whats_new_plist_file = os.path.join(
-        BASE_DIR, '../ios/chrome/browser/ui/whats_new/data_source/'
+        BASE_DIR, '../ios/chrome/browser/whats_new/ui/data_source/'
         'resources/whats_new_entries.plist')
     with open(whats_new_plist_file, 'rb') as file:
         plist_data = plistlib.load(file)
@@ -143,7 +143,7 @@
         'LearnMoreUrlString': feature_dict['Help url']
     }
     whats_new_plist_file = os.path.join(
-        BASE_DIR, '../ios/chrome/browser/ui/whats_new/data_source/'
+        BASE_DIR, '../ios/chrome/browser/whats_new/ui/data_source/'
         'resources/whats_new_entries.plist')
     with open(whats_new_plist_file, 'rb') as file:
         plist_data = plistlib.load(file)
@@ -160,7 +160,8 @@
   """
     feature_name = feature_dict['Feature name']
     whats_new_util_file = os.path.join(
-        BASE_DIR, '..', 'ios/chrome/browser/ui/whats_new/whats_new_util.mm')
+        BASE_DIR, '..',
+        'ios/chrome/browser/whats_new/coordinator/whats_new_util.mm')
     with open(whats_new_util_file, 'r+', encoding='utf-8', newline='') as file:
         read_data = file.read()
         whats_new_type_error_regex = r'case WhatsNewType::kError:'
@@ -190,7 +191,7 @@
     animation_name = feature_dict['Animation']
     milestone = feature_dict['Milestone'].lower()
     DEST_DIR = os.path.join(
-        BASE_DIR, '../ios/chrome/browser/ui/whats_new/data_source/resources',
+        BASE_DIR, '../ios/chrome/browser/whats_new/ui/data_source/resources',
         milestone)
     os.makedirs(DEST_DIR, exist_ok=True)
     darkmode_src_file = os.path.join(path_to_milestone_folder, feature_name,
@@ -215,7 +216,7 @@
     milestone = feature_dict['Milestone'].lower()
     whats_new_resources_build_file = os.path.join(
         BASE_DIR,
-        '../ios/chrome/browser/ui/whats_new/data_source/resources/BUILD.gn')
+        '../ios/chrome/browser/whats_new/ui/data_source/resources/BUILD.gn')
     with open(whats_new_resources_build_file,
               'r+',
               encoding='utf-8',
@@ -254,7 +255,7 @@
             if paragraph.text:
                 paragraphs_string_builder.append(paragraph.text)
     milestone_string_grd_file = os.path.join(
-        BASE_DIR, '../ios/chrome/browser/ui/whats_new/strings/',
+        BASE_DIR, '../ios/chrome/browser/whats_new/ui/strings/',
         milestone + '_strings.grdp')
     if not os.path.exists(milestone_string_grd_file):
         #Create new file and add to grd main
@@ -269,7 +270,7 @@
             grd_file_handler.write('\n'.join(grd_content_builder))
         #open and add to main grd
         whats_new_strings_grd_file = os.path.join(
-            BASE_DIR, '../ios/chrome/browser/ui/whats_new',
+            BASE_DIR, '../ios/chrome/browser/whats_new/ui',
             'strings/ios_whats_new_strings.grd')
         with open(whats_new_strings_grd_file,
                   'r+',
@@ -286,7 +287,7 @@
     else:
         #search for '</grit-part>' and add above
         feature_strings_grd_file = os.path.join(
-            BASE_DIR, '../ios/chrome/browser/ui/whats_new/strings/',
+            BASE_DIR, '../ios/chrome/browser/whats_new/ui/strings/',
             milestone + '_strings.grdp')
         with open(feature_strings_grd_file, 'r+', encoding='utf-8',
                   newline='') as file:
@@ -316,7 +317,7 @@
     animation_texts_string = feature_dict['Animation texts'].splitlines()
     titles.extend("".join(StripWhitespacesAndEmptyLines(json.loads(a)['value'])) for a in animation_texts_string)
     screenshot_dir = os.path.join(
-        BASE_DIR, '../ios/chrome/browser/ui/whats_new/strings',
+        BASE_DIR, '../ios/chrome/browser/whats_new/ui/strings',
         milestone + '_strings_grdp')
     os.makedirs(screenshot_dir, exist_ok=True)
     for title in titles:
@@ -364,7 +365,7 @@
         milestone: milestone for which the strings will be removed.
     """
     whats_new_strings_grd_file = os.path.join(
-        BASE_DIR, '../ios/chrome/browser/ui/whats_new',
+        BASE_DIR, '../ios/chrome/browser/whats_new/ui',
         'strings/ios_whats_new_strings.grd')
     with open(whats_new_strings_grd_file, 'r+', encoding='utf-8',
               newline='') as file:
@@ -381,7 +382,7 @@
                 'for more information.')
     try:
         screenshot_milestone_dir = os.path.join(
-            BASE_DIR, '../ios/chrome/browser/ui/whats_new/strings',
+            BASE_DIR, '../ios/chrome/browser/whats_new/ui/strings',
             milestone + '_strings_grdp')
         shutil.rmtree(screenshot_milestone_dir)
     except:
@@ -389,7 +390,7 @@
               'been removed.')
     try:
         strings_file = os.path.join(
-            BASE_DIR, '../ios/chrome/browser/ui/whats_new/strings',
+            BASE_DIR, '../ios/chrome/browser/whats_new/ui/strings',
             milestone + '_strings.grdp')
         os.remove(strings_file)
     except:
@@ -407,7 +408,7 @@
     try:
         whats_new_milestone_resource_dir = os.path.join(
             BASE_DIR,
-            '../ios/chrome/browser/ui/whats_new/data_source/resources',
+            '../ios/chrome/browser/whats_new/ui/data_source/resources',
             milestone)
         shutil.rmtree(whats_new_milestone_resource_dir)
     except:
@@ -416,7 +417,7 @@
     screenshots_lists_regex = r'screenshots_lists\s*=\s*(\[.*?\])'
     whats_new_resources_build_file = os.path.join(
         BASE_DIR,
-        '../ios/chrome/browser/ui/whats_new/data_source/resources/BUILD.gn')
+        '../ios/chrome/browser/whats_new/ui/data_source/resources/BUILD.gn')
     with open(whats_new_resources_build_file,
               'r+',
               encoding='utf-8',
diff --git a/v8 b/v8
index 08f66b18..be3c061 160000
--- a/v8
+++ b/v8
@@ -1 +1 @@
-Subproject commit 08f66b181c57e381cda1ee15023d53a620616ed7
+Subproject commit be3c06167b01bc7cd70edb4e44ec76ce8058390d